├── Patrons.csv ├── .gitlurker ├── Microsoft.png ├── src ├── GitLurker.UI │ ├── GitLurker.png │ ├── Resources │ │ ├── Game.gif │ │ ├── Action.png │ │ ├── Theme.gif │ │ ├── GitLurker.ico │ │ └── SystemTray.png │ ├── Messages │ │ ├── CloseMessage.cs │ │ ├── PatronMessage.cs │ │ └── ActionMessage.cs │ ├── Models │ │ ├── MousePosition.cs │ │ ├── ConsoleLine.cs │ │ ├── FlyoutRequest.cs │ │ └── DoubleClickCommand.cs │ ├── Services │ │ ├── IDebounceService.cs │ │ ├── ConsoleService.cs │ │ ├── PopupService.cs │ │ ├── DialogService.cs │ │ ├── ModeService.cs │ │ ├── DebounceService.cs │ │ ├── FlyoutService.cs │ │ ├── MouseService.cs │ │ ├── ThemeService.cs │ │ └── GithubUpdateManager.cs │ ├── App.xaml.cs │ ├── Views │ │ ├── ActionView.xaml.cs │ │ ├── FileView.xaml.cs │ │ ├── FolderView.xaml.cs │ │ ├── GameView.xaml.cs │ │ ├── HotkeyView.xaml.cs │ │ ├── SnippetView.xaml.cs │ │ ├── ActionBarView.xaml.cs │ │ ├── RepositoryView.xaml.cs │ │ ├── AudioLibraryView.xaml.cs │ │ ├── AudioSessionView.xaml.cs │ │ ├── CommitActionView.xaml.cs │ │ ├── CustomActionView.xaml.cs │ │ ├── GameLibraryView.xaml.cs │ │ ├── SnippetTileView.xaml.cs │ │ ├── BranchManagerView.xaml.cs │ │ ├── NugetSettingsView.xaml.cs │ │ ├── CustomActionTileView.xaml.cs │ │ ├── PatreonSettingsView.xaml.cs │ │ ├── ShellView.xaml.cs │ │ ├── WorkspaceView.xaml.cs │ │ ├── RepoManagerView.xaml.cs │ │ ├── SnippetManagerView.xaml.cs │ │ ├── CustomActionManagerView.xaml.cs │ │ ├── ModeStatusView.xaml.cs │ │ ├── ConsoleView.xaml.cs │ │ ├── WorkspaceView.xaml │ │ ├── AudioLibraryView.xaml │ │ ├── GameLibraryView.xaml │ │ ├── WelcomeView.xaml │ │ ├── FolderView.xaml │ │ ├── RepoManagerView.xaml │ │ ├── SnippetManagerView.xaml │ │ ├── CustomActionManagerView.xaml │ │ ├── PatreonView.xaml.cs │ │ ├── WelcomeView.xaml.cs │ │ ├── SettingsView.xaml.cs │ │ ├── SnippetView.xaml │ │ ├── ActionBarView.xaml │ │ ├── FileView.xaml │ │ ├── ConsoleView.xaml │ │ ├── AudioSessionView.xaml │ │ ├── CommitActionView.xaml │ │ ├── SnippetTileView.xaml │ │ ├── CustomActionTileView.xaml │ │ └── GameView.xaml │ ├── ViewModels │ │ ├── WelcomeViewModel.cs │ │ ├── IItemListViewModel.cs │ │ ├── ItemViewModelBase.cs │ │ ├── FolderViewModel.cs │ │ ├── SnippetTileViewModel.cs │ │ ├── CustomActionTileViewModel.cs │ │ ├── FileViewModel.cs │ │ ├── ModeStatusViewModel.cs │ │ ├── RepoManagerViewModel.cs │ │ ├── FlyoutScreenBase.cs │ │ ├── GameViewModel.cs │ │ ├── SnippetManagerViewModel.cs │ │ ├── CustomActionManagerViewModel.cs │ │ ├── ItemListViewModelBase.cs │ │ ├── SnippetViewModel.cs │ │ ├── PatreonViewModel.cs │ │ ├── AudioLibraryViewModel.cs │ │ ├── NugetSettingsViewModel.cs │ │ ├── AudioSessionViewModel.cs │ │ ├── ActionViewModel.cs │ │ ├── HotkeyViewModel.cs │ │ ├── ConsoleViewModel.cs │ │ ├── ActionBarViewModel.cs │ │ ├── CommitActionViewModel.cs │ │ └── CustomActionViewModel.cs │ ├── app.manifest │ ├── Helpers │ │ ├── DockingHelper.cs │ │ └── ClipboardHelper.cs │ ├── Extensions │ │ └── ProcessExtensions.cs │ ├── AssemblyInfo.cs │ ├── nlog.config │ ├── .vscode │ │ ├── launch.json │ │ └── tasks.json │ ├── Converters │ │ └── ModifierConverter.cs │ ├── GitLurker.UI.csproj │ └── App.xaml ├── GitLurker.Core │ ├── Models │ │ ├── Mode.cs │ │ ├── ChangeStatus.cs │ │ ├── CLIEvent.cs │ │ ├── FileChange.cs │ │ ├── Configuration.cs │ │ ├── ExecutionResult.cs │ │ ├── Snippet.cs │ │ ├── Hotkey.cs │ │ ├── CustomActionSettings.cs │ │ ├── Theme.cs │ │ ├── GameSettings.cs │ │ ├── CustomActionSettingsFile.cs │ │ ├── CustomAction.cs │ │ ├── NugetInformation.cs │ │ ├── GameSettingsFile.cs │ │ ├── Settings.cs │ │ ├── SettingsFile.cs │ │ └── Workspace.cs │ ├── GitLurker.Core.csproj │ ├── Services │ │ ├── NugetService.cs │ │ ├── RepositoryService.cs │ │ └── ProcessService.cs │ └── Extensions │ │ └── StringExtensions.cs └── GitLurker.Package │ ├── Images │ ├── StoreLogo.backup.png │ ├── BadgeLogo.scale-100.png │ ├── BadgeLogo.scale-125.png │ ├── BadgeLogo.scale-150.png │ ├── BadgeLogo.scale-200.png │ ├── BadgeLogo.scale-400.png │ ├── LargeTile.scale-100.png │ ├── LargeTile.scale-125.png │ ├── LargeTile.scale-150.png │ ├── LargeTile.scale-200.png │ ├── LargeTile.scale-400.png │ ├── SmallTile.scale-100.png │ ├── SmallTile.scale-125.png │ ├── SmallTile.scale-150.png │ ├── SmallTile.scale-200.png │ ├── SmallTile.scale-400.png │ ├── StoreLogo.scale-100.png │ ├── StoreLogo.scale-125.png │ ├── StoreLogo.scale-150.png │ ├── StoreLogo.scale-200.png │ ├── StoreLogo.scale-400.png │ ├── SplashScreen.scale-100.png │ ├── SplashScreen.scale-125.png │ ├── SplashScreen.scale-150.png │ ├── SplashScreen.scale-200.png │ ├── SplashScreen.scale-400.png │ ├── LockScreenLogo.scale-200.png │ ├── Square150x150Logo.scale-100.png │ ├── Square150x150Logo.scale-125.png │ ├── Square150x150Logo.scale-150.png │ ├── Square150x150Logo.scale-200.png │ ├── Square150x150Logo.scale-400.png │ ├── Square44x44Logo.scale-100.png │ ├── Square44x44Logo.scale-125.png │ ├── Square44x44Logo.scale-150.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.scale-400.png │ ├── Wide310x150Logo.scale-100.png │ ├── Wide310x150Logo.scale-125.png │ ├── Wide310x150Logo.scale-150.png │ ├── Wide310x150Logo.scale-200.png │ ├── Wide310x150Logo.scale-400.png │ ├── Square44x44Logo.targetsize-16.png │ ├── Square44x44Logo.targetsize-24.png │ ├── Square44x44Logo.targetsize-32.png │ ├── Square44x44Logo.targetsize-48.png │ ├── Square44x44Logo.targetsize-256.png │ ├── Square44x44Logo.altform-unplated_targetsize-16.png │ ├── Square44x44Logo.altform-unplated_targetsize-256.png │ ├── Square44x44Logo.altform-unplated_targetsize-32.png │ ├── Square44x44Logo.altform-unplated_targetsize-48.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-16.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-24.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-256.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-32.png │ └── Square44x44Logo.altform-lightunplated_targetsize-48.png │ └── Package.appxmanifest ├── MouseKeyHook.5.6.0 ├── .signature.p7s └── lib │ └── net40 │ └── Gma.System.MouseKeyHook.dll ├── update.bat ├── LICENSE └── README.md /Patrons.csv: -------------------------------------------------------------------------------- 1 | 4000228;78559226 -------------------------------------------------------------------------------- /.gitlurker: -------------------------------------------------------------------------------- 1 | { 2 | "IconPath": "src\\GitLurker.UI\\Resources\\GitLurker.ico" 3 | } -------------------------------------------------------------------------------- /Microsoft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/Microsoft.png -------------------------------------------------------------------------------- /src/GitLurker.UI/GitLurker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.UI/GitLurker.png -------------------------------------------------------------------------------- /MouseKeyHook.5.6.0/.signature.p7s: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/MouseKeyHook.5.6.0/.signature.p7s -------------------------------------------------------------------------------- /src/GitLurker.UI/Resources/Game.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.UI/Resources/Game.gif -------------------------------------------------------------------------------- /src/GitLurker.UI/Messages/CloseMessage.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Messages; 2 | 3 | public class CloseMessage 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Messages/PatronMessage.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Messages; 2 | 3 | public class PatronMessage 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Resources/Action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.UI/Resources/Action.png -------------------------------------------------------------------------------- /src/GitLurker.UI/Resources/Theme.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.UI/Resources/Theme.gif -------------------------------------------------------------------------------- /src/GitLurker.UI/Resources/GitLurker.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.UI/Resources/GitLurker.ico -------------------------------------------------------------------------------- /update.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | timeout 10 && dotnet build -c release && .\\src\\GitLurker.UI\\bin\\Release\\net6.0-windows\\GitLurker.exe -------------------------------------------------------------------------------- /src/GitLurker.UI/Resources/SystemTray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.UI/Resources/SystemTray.png -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/Mode.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | public enum Mode 4 | { 5 | Git, 6 | Audio, 7 | Game, 8 | } 9 | -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/StoreLogo.backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/StoreLogo.backup.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/BadgeLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/BadgeLogo.scale-100.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/BadgeLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/BadgeLogo.scale-125.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/BadgeLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/BadgeLogo.scale-150.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/BadgeLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/BadgeLogo.scale-200.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/BadgeLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/BadgeLogo.scale-400.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/LargeTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/LargeTile.scale-100.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/LargeTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/LargeTile.scale-125.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/LargeTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/LargeTile.scale-150.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/LargeTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/LargeTile.scale-200.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/LargeTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/LargeTile.scale-400.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/SmallTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/SmallTile.scale-100.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/SmallTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/SmallTile.scale-125.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/SmallTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/SmallTile.scale-150.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/SmallTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/SmallTile.scale-200.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/SmallTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/SmallTile.scale-400.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/StoreLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/StoreLogo.scale-125.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/StoreLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/StoreLogo.scale-150.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/StoreLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/StoreLogo.scale-200.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/StoreLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/StoreLogo.scale-400.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/SplashScreen.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/SplashScreen.scale-125.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/SplashScreen.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/SplashScreen.scale-150.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/SplashScreen.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/SplashScreen.scale-400.png -------------------------------------------------------------------------------- /MouseKeyHook.5.6.0/lib/net40/Gma.System.MouseKeyHook.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/MouseKeyHook.5.6.0/lib/net40/Gma.System.MouseKeyHook.dll -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square150x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square150x150Logo.scale-100.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square150x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square150x150Logo.scale-125.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square150x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square150x150Logo.scale-150.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square150x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square150x150Logo.scale-400.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.scale-100.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.scale-125.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.scale-150.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Wide310x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Wide310x150Logo.scale-100.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Wide310x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Wide310x150Logo.scale-125.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Wide310x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Wide310x150Logo.scale-150.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Wide310x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Wide310x150Logo.scale-400.png -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/ChangeStatus.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | public enum ChangeStatus 4 | { 5 | Modified, 6 | Added, 7 | Deleted, 8 | } 9 | -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.targetsize-16.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.targetsize-24.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.targetsize-32.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.targetsize-48.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.targetsize-256.png -------------------------------------------------------------------------------- /src/GitLurker.UI/Models/MousePosition.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Models; 2 | 3 | public class MousePosition 4 | { 5 | public int X { get; set; } 6 | 7 | public int Y { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/CLIEvent.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | public class CLIEvent 4 | { 5 | public string Text { get; set; } 6 | 7 | public bool IsError { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.altform-unplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.altform-unplated_targetsize-16.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.altform-unplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.altform-unplated_targetsize-256.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.altform-unplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.altform-unplated_targetsize-32.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.altform-unplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.altform-unplated_targetsize-48.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/FileChange.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | public class FileChange 4 | { 5 | public string FilePath { get; set; } 6 | 7 | public ChangeStatus Status { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.altform-lightunplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.altform-lightunplated_targetsize-16.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.altform-lightunplated_targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.altform-lightunplated_targetsize-24.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.altform-lightunplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.altform-lightunplated_targetsize-256.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.altform-lightunplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.altform-lightunplated_targetsize-32.png -------------------------------------------------------------------------------- /src/GitLurker.Package/Images/Square44x44Logo.altform-lightunplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/C1rdec/Git-Lurker/HEAD/src/GitLurker.Package/Images/Square44x44Logo.altform-lightunplated_targetsize-48.png -------------------------------------------------------------------------------- /src/GitLurker.UI/Models/ConsoleLine.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Models; 2 | 3 | public class ConsoleLine 4 | { 5 | #region Properties 6 | 7 | public string Line { get; set; } 8 | 9 | public bool IsError { get; set; } 10 | 11 | #endregion 12 | } 13 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Services/IDebounceService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Services; 2 | 3 | using System; 4 | 5 | public interface IDebounceService 6 | { 7 | bool HasTimer { get; } 8 | 9 | void Debounce(int interval, Action action); 10 | 11 | bool Reset(); 12 | } -------------------------------------------------------------------------------- /src/GitLurker.UI/App.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI; 2 | 3 | using System.Windows; 4 | 5 | /// 6 | /// Interaction logic for App.xaml 7 | /// 8 | public partial class App : Application 9 | { 10 | public App() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Messages/ActionMessage.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Messages; 2 | 3 | using GitLurker.UI.ViewModels; 4 | 5 | public class ActionMessage 6 | { 7 | public string WaterMark { get; set; } 8 | 9 | public IItemListViewModel ListViewModel { get; set; } 10 | 11 | public bool Focus { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/Configuration.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | public class Configuration 4 | { 5 | #region Properties 6 | 7 | public string Name { get; set; } 8 | 9 | public string IconPath { get; set; } 10 | 11 | public string FrontEndPath { get; set; } 12 | 13 | #endregion 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/ExecutionResult.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using System.Collections.Generic; 4 | 5 | public class ExecutionResult 6 | { 7 | #region Properties 8 | 9 | public IEnumerable Output { get; set; } 10 | 11 | public int ExitCode { get; set; } 12 | 13 | #endregion 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/ActionView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for ActionView.xaml 7 | /// 8 | public partial class ActionView : UserControl 9 | { 10 | public ActionView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/FileView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for SteamGameView.xaml 7 | /// 8 | public partial class FileView : UserControl 9 | { 10 | public FileView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/FolderView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for FolderView.xaml 7 | /// 8 | public partial class FolderView : UserControl 9 | { 10 | public FolderView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/GameView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for SteamGameView.xaml 7 | /// 8 | public partial class GameView : UserControl 9 | { 10 | public GameView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/HotkeyView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for HotkeyView.xaml 7 | /// 8 | public partial class HotkeyView : UserControl 9 | { 10 | public HotkeyView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/SnippetView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for SnippetView.xaml 7 | /// 8 | public partial class SnippetView : UserControl 9 | { 10 | public SnippetView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/ActionBarView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for ActionBarView.xaml 7 | /// 8 | public partial class ActionBarView : UserControl 9 | { 10 | public ActionBarView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/WelcomeViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using Caliburn.Micro; 4 | 5 | internal class WelcomeViewModel : Screen 6 | { 7 | public async void Start() 8 | { 9 | var shellViewModel = IoC.Get(); 10 | await IoC.Get().ShowWindowAsync(shellViewModel); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/RepositoryView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for RepositoryView.xaml 7 | /// 8 | public partial class RepositoryView : UserControl 9 | { 10 | public RepositoryView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/AudioLibraryView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for SteamLibraryView.xaml 7 | /// 8 | public partial class AudioLibraryView : UserControl 9 | { 10 | public AudioLibraryView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/AudioSessionView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for SteamGameView.xaml 7 | /// 8 | public partial class AudioSessionView : UserControl 9 | { 10 | public AudioSessionView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/CommitActionView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for CommitActionView.xaml 7 | /// 8 | public partial class CommitActionView : UserControl 9 | { 10 | public CommitActionView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/CustomActionView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for CustomActionView.xaml 7 | /// 8 | public partial class CustomActionView : UserControl 9 | { 10 | public CustomActionView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/GameLibraryView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for SteamLibraryView.xaml 7 | /// 8 | public partial class GameLibraryView : UserControl 9 | { 10 | public GameLibraryView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/SnippetTileView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for CustomActionView.xaml 7 | /// 8 | public partial class SnippetTileView : UserControl 9 | { 10 | public SnippetTileView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/BranchManagerView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for BranchManagerView.xaml 7 | /// 8 | public partial class BranchManagerView : UserControl 9 | { 10 | public BranchManagerView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/NugetSettingsView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for NugetSettingsView.xaml 7 | /// 8 | public partial class NugetSettingsView : UserControl 9 | { 10 | public NugetSettingsView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/CustomActionTileView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for CustomActionView.xaml 7 | /// 8 | public partial class CustomActionTileView : UserControl 9 | { 10 | public CustomActionTileView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/PatreonSettingsView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for PatreonSettingsView.xaml 7 | /// 8 | public partial class PatreonSettingsView : UserControl 9 | { 10 | public PatreonSettingsView() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Models/FlyoutRequest.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Models; 2 | 3 | using Caliburn.Micro; 4 | using MahApps.Metro.Controls; 5 | 6 | public class FlyoutRequest 7 | { 8 | #region Properties 9 | 10 | public string Header { get; set; } 11 | 12 | public Position Position { get; set; } 13 | 14 | public PropertyChangedBase Content { get; set; } 15 | 16 | #endregion 17 | } 18 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/Snippet.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using System; 4 | 5 | public class Snippet 6 | { 7 | public Snippet() 8 | { 9 | Id = Guid.NewGuid(); 10 | Hotkey = new Hotkey(); 11 | } 12 | 13 | public Guid Id { get; set; } 14 | 15 | public string Name { get; set; } 16 | 17 | public string Value { get; set; } 18 | 19 | public Hotkey Hotkey { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/Hotkey.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using Winook; 4 | 5 | public sealed class Hotkey 6 | { 7 | #region Properties 8 | 9 | public Modifiers Modifier { get; set; } 10 | 11 | public KeyCode KeyCode { get; set; } 12 | 13 | #endregion 14 | 15 | #region Methods 16 | 17 | public bool IsDefined() 18 | { 19 | return KeyCode != KeyCode.None; 20 | } 21 | 22 | #endregion 23 | } 24 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/CustomActionSettings.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using System.Collections.Generic; 4 | 5 | public class CustomActionSettings 6 | { 7 | #region Constructors 8 | 9 | public CustomActionSettings() 10 | { 11 | Actions = new List(); 12 | } 13 | 14 | #endregion 15 | 16 | #region Properties 17 | 18 | public List Actions { get; set; } 19 | 20 | #endregion 21 | } 22 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/Theme.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | public enum Scheme 4 | { 5 | Steel, 6 | Amber, 7 | Blue, 8 | Brown, 9 | Cobalt, 10 | Crimson, 11 | Cyan, 12 | Emerald, 13 | Green, 14 | Indigo, 15 | Lime, 16 | Magenta, 17 | Mauve, 18 | Olive, 19 | Orange, 20 | Pink, 21 | Purple, 22 | Red, 23 | Sienna, 24 | Taupe, 25 | Teal, 26 | Yellow, 27 | Violet, 28 | } 29 | -------------------------------------------------------------------------------- /src/GitLurker.UI/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/IItemListViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System.Threading.Tasks; 4 | 5 | public interface IItemListViewModel 6 | { 7 | Task RefreshItems(); 8 | 9 | void Search(string term); 10 | 11 | bool Close(); 12 | 13 | void Clear(); 14 | 15 | void ShowRecent(); 16 | 17 | void MoveUp(); 18 | 19 | void MoveDown(); 20 | 21 | Task Open(bool skipModifier); 22 | 23 | void EnterLongPressed(); 24 | 25 | void NextTabPressed(); 26 | } 27 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/ShellView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Input; 4 | using MahApps.Metro.Controls; 5 | 6 | public partial class ShellView : MetroWindow 7 | { 8 | public ShellView() 9 | { 10 | InitializeComponent(); 11 | PreviewKeyDown += ShellView_PreviewKeyDown; 12 | } 13 | 14 | private void ShellView_PreviewKeyDown(object sender, KeyEventArgs e) 15 | { 16 | if (e.Key == Key.Tab) 17 | { 18 | e.Handled = true; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Helpers/DockingHelper.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Helpers; 2 | 3 | using System; 4 | using System.Windows; 5 | using System.Windows.Interop; 6 | using GitLurker.Core; 7 | 8 | internal class DockingHelper 9 | { 10 | public static void SetForeground(Window window, Action callback) 11 | { 12 | if (window == null) 13 | { 14 | return; 15 | } 16 | 17 | var handle = new WindowInteropHelper(window).Handle; 18 | _ = Native.SetForegroundWindow(handle); 19 | 20 | callback(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Services/ConsoleService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Services; 2 | 3 | using System; 4 | using GitLurker.Core.Services; 5 | 6 | public class ConsoleService 7 | { 8 | #region Events 9 | 10 | public event EventHandler ExecutionRequested; 11 | 12 | public event EventHandler ShowRequested; 13 | 14 | #endregion 15 | 16 | #region Methods 17 | 18 | public void Listen(ProcessService process) => ExecutionRequested?.Invoke(this, process); 19 | 20 | public void Show() => ShowRequested?.Invoke(this, EventArgs.Empty); 21 | 22 | #endregion 23 | } 24 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Extensions/ProcessExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Extensions; 2 | 3 | using System.Diagnostics; 4 | using System.Text; 5 | using GitLurker.Core; 6 | 7 | public static class ProcessExtensions 8 | { 9 | public static string GetMainModuleFileName(this Process process, int buffer = 1024) 10 | { 11 | var fileNameBuilder = new StringBuilder(buffer); 12 | var bufferLength = (uint)fileNameBuilder.Capacity + 1; 13 | 14 | return Native.QueryFullProcessImageName(process.Handle, 0, fileNameBuilder, ref bufferLength) ? 15 | fileNameBuilder.ToString() : 16 | null; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GitLurker.UI/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/WorkspaceView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | using System.Windows.Input; 5 | 6 | /// 7 | /// Interaction logic for WorkspaceView.xaml 8 | /// 9 | public partial class WorkspaceView : UserControl 10 | { 11 | public WorkspaceView() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e) 17 | { 18 | var scrollViewer = (ScrollViewer)sender; 19 | scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta); 20 | e.Handled = true; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/RepoManagerView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | using System.Windows.Input; 5 | 6 | /// 7 | /// Interaction logic for RepoManagerView.xaml 8 | /// 9 | public partial class RepoManagerView : UserControl 10 | { 11 | public RepoManagerView() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e) 17 | { 18 | var scrollViewer = (ScrollViewer)sender; 19 | scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta); 20 | e.Handled = true; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/SnippetManagerView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | using System.Windows.Input; 5 | 6 | /// 7 | /// Interaction logic for SnippetManagerView.xaml 8 | /// 9 | public partial class SnippetManagerView : UserControl 10 | { 11 | public SnippetManagerView() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e) 17 | { 18 | var scrollViewer = (ScrollViewer)sender; 19 | scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta); 20 | e.Handled = true; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/CustomActionManagerView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | using System.Windows.Input; 5 | 6 | /// 7 | /// Interaction logic for CustomActionManagerView.xaml 8 | /// 9 | public partial class CustomActionManagerView : UserControl 10 | { 11 | public CustomActionManagerView() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e) 17 | { 18 | var scrollViewer = (ScrollViewer)sender; 19 | scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta); 20 | e.Handled = true; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/ModeStatusView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Navigation; 15 | using System.Windows.Shapes; 16 | 17 | /// 18 | /// Interaction logic for ModeStatusView.xaml 19 | /// 20 | public partial class ModeStatusView : UserControl 21 | { 22 | public ModeStatusView() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Services/PopupService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Services; 2 | 3 | public class PopupService 4 | { 5 | #region Fields 6 | 7 | private readonly IDebounceService _debounce; 8 | 9 | #endregion 10 | 11 | #region Constructors 12 | 13 | public PopupService(IDebounceService debounceService) 14 | { 15 | _debounce = debounceService; 16 | } 17 | 18 | #endregion 19 | 20 | #region Properties 21 | 22 | public bool IsOpen { get; set; } 23 | 24 | public bool JustClosed { get; set; } 25 | 26 | #endregion 27 | 28 | #region Methods 29 | 30 | public void SetClosed() 31 | { 32 | JustClosed = true; 33 | _debounce.Debounce(150, () => JustClosed = false); 34 | } 35 | 36 | #endregion 37 | } 38 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/GameSettings.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using System.Collections.Generic; 4 | 5 | public class GameSettings 6 | { 7 | #region Constructors 8 | 9 | public GameSettings() 10 | { 11 | RecentGameIds = new List(); 12 | Scheme = Scheme.Crimson; 13 | } 14 | 15 | #endregion 16 | 17 | #region Properties 18 | 19 | public List RecentGameIds { get; set; } 20 | 21 | public Scheme Scheme { get; set; } 22 | 23 | public string SteamExePath { get; set; } 24 | 25 | public string EpicExePath { get; set; } 26 | 27 | public bool BattleNetInstalled { get; set; } 28 | 29 | public bool SteamAsked { get; set; } 30 | 31 | public bool EpicAsked { get; set; } 32 | 33 | #endregion 34 | } 35 | -------------------------------------------------------------------------------- /src/GitLurker.UI/nlog.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ${LogDirectory}/${date:format=yyyy-MM-dd}.log 7 | 8 | [${date:format=yyyy/MM/dd HH\:mm\:ss.fff}] ${level:padding=-5} [${threadid}] ${message}${onexception:inner=${newline}${exception:format=tostring:maxInnerExceptionLevel=10:innerExceptionSeparator=Inner exception\:}} (${logger}) 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/ItemViewModelBase.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using Caliburn.Micro; 4 | 5 | public abstract class ItemViewModelBase : ViewAware 6 | { 7 | #region Fields 8 | 9 | private object _view; 10 | 11 | #endregion 12 | 13 | #region Properties 14 | 15 | public abstract string Id { get; } 16 | 17 | public bool IsSelected 18 | { 19 | get => field; 20 | set 21 | { 22 | field = value; 23 | NotifyOfPropertyChange(); 24 | } 25 | } 26 | 27 | protected object View => _view; 28 | 29 | #endregion 30 | 31 | #region Methods 32 | 33 | protected override void OnViewLoaded(object view) 34 | { 35 | _view = view; 36 | base.OnViewLoaded(view); 37 | } 38 | 39 | #endregion 40 | } 41 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/FolderViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System; 4 | using System.IO; 5 | 6 | public class FolderViewModel 7 | { 8 | #region Fields 9 | 10 | private string _folder; 11 | private Action _deleteCallback; 12 | 13 | #endregion 14 | 15 | #region Constructors 16 | 17 | public FolderViewModel(string folder, Action deleteCallback) 18 | { 19 | _folder = folder; 20 | _deleteCallback = deleteCallback; 21 | } 22 | 23 | #endregion 24 | 25 | #region Properties 26 | 27 | public string Folder => _folder; 28 | 29 | public bool FolderExists => Directory.Exists(Folder); 30 | 31 | #endregion 32 | 33 | #region Methods 34 | 35 | public void Delete() => _deleteCallback(_folder); 36 | 37 | #endregion 38 | } 39 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Models/DoubleClickCommand.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System; 4 | using System.Windows.Input; 5 | 6 | public class DoubleClickCommand : ICommand 7 | { 8 | #region Fields 9 | 10 | private Action _action; 11 | 12 | #endregion 13 | 14 | #region Constructors 15 | 16 | public DoubleClickCommand(Action action) 17 | { 18 | _action = action; 19 | } 20 | 21 | #endregion 22 | 23 | #region Events 24 | 25 | public event EventHandler CanExecuteChanged; 26 | 27 | #endregion 28 | 29 | #region Methods 30 | 31 | public bool CanExecute(object parameter) 32 | { 33 | return true; 34 | } 35 | 36 | public void Execute(object parameter) 37 | { 38 | _action?.Invoke(parameter); 39 | } 40 | 41 | #endregion 42 | } -------------------------------------------------------------------------------- /src/GitLurker.UI/Services/DialogService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Services; 2 | 3 | using System.Threading.Tasks; 4 | using MahApps.Metro.Controls.Dialogs; 5 | 6 | public class DialogService 7 | { 8 | #region Fields 9 | 10 | private static readonly IDialogCoordinator Coordinator = DialogCoordinator.Instance; 11 | 12 | private object _context; 13 | 14 | #endregion 15 | 16 | #region Methods 17 | 18 | public async Task ShowProgressAsync(string title, string message, Task task) 19 | { 20 | var controller = await Coordinator.ShowProgressAsync(_context, title, message); 21 | controller.SetIndeterminate(); 22 | 23 | await task; 24 | 25 | await controller.CloseAsync(); 26 | } 27 | 28 | public void Register(object context) 29 | { 30 | _context = context; 31 | } 32 | 33 | #endregion 34 | } 35 | -------------------------------------------------------------------------------- /src/GitLurker.Core/GitLurker.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net10.0-windows7.0 5 | disable 6 | AnyCPU;x64;x86 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Services/ModeService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Services; 2 | 3 | using System.Linq; 4 | using GitLurker.Core.Models; 5 | using Lurker.Audio; 6 | 7 | public class ModeService 8 | { 9 | private SettingsFile _settingsFile; 10 | private AudioSessionService _audioSessionService; 11 | 12 | public ModeService(SettingsFile file, AudioSessionService audioService) 13 | { 14 | _settingsFile = file; 15 | _audioSessionService = audioService; 16 | } 17 | 18 | public Mode GetNextMode() 19 | { 20 | var mode = _settingsFile.GetNextMode(); 21 | if (mode == Mode.Audio && !_audioSessionService.GetSessions().Any()) 22 | { 23 | // We need to set the Mode to Audio to get the next one 24 | _settingsFile.Entity.Mode = Mode.Audio; 25 | mode = _settingsFile.GetNextMode(); 26 | } 27 | 28 | return mode; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/CustomActionSettingsFile.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using Lurker.AppData; 6 | 7 | public class CustomActionSettingsFile : AppDataFileBase 8 | { 9 | #region Properties 10 | 11 | protected override string FileName => "Actions.json"; 12 | 13 | protected override string FolderName => "GitLurker"; 14 | 15 | #endregion 16 | 17 | #region Methods 18 | 19 | public void AddAction(CustomAction action) 20 | { 21 | Entity.Actions.Add(action); 22 | Save(); 23 | } 24 | 25 | public void DeleteAction(CustomAction action) 26 | { 27 | Entity.Actions.Remove(action); 28 | Save(); 29 | } 30 | 31 | public IEnumerable GetActions(string path) 32 | { 33 | return Entity.Actions.Where(a => a.IsIncluded(path)); 34 | } 35 | 36 | #endregion 37 | } 38 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Helpers/ClipboardHelper.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Helper; 2 | 3 | using System; 4 | using System.Threading; 5 | 6 | internal class ClipboardHelper 7 | { 8 | public static void SetText(string text) 9 | { 10 | RetryOnMainThread(() => 11 | { 12 | System.Windows.Clipboard.SetText(text); 13 | }); 14 | } 15 | 16 | private static void RetryOnMainThread(Action action) 17 | { 18 | var thread = new Thread(() => 19 | { 20 | var retryCount = 3; 21 | while (retryCount != 0) 22 | { 23 | try 24 | { 25 | action(); 26 | break; 27 | } 28 | catch 29 | { 30 | retryCount--; 31 | Thread.Sleep(200); 32 | } 33 | } 34 | }); 35 | thread.SetApartmentState(ApartmentState.STA); 36 | thread.Start(); 37 | thread.Join(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Cédric Lampron 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/GitLurker.UI/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | // Use IntelliSense to find out which attributes exist for C# debugging 6 | // Use hover for the description of the existing attributes 7 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 8 | "name": ".NET Core Launch (console)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/bin/Debug/net6.0-windows/GitLurker.UI.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}", 16 | // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console 17 | "console": "internalConsole", 18 | "stopAtEntry": false 19 | }, 20 | { 21 | "name": ".NET Core Attach", 22 | "type": "coreclr", 23 | "request": "attach" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /src/GitLurker.UI/Services/DebounceService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Services; 2 | 3 | using System; 4 | using System.Windows.Threading; 5 | 6 | public class DebounceService : IDebounceService 7 | { 8 | #region Fields 9 | 10 | private DispatcherTimer _timer; 11 | 12 | #endregion 13 | 14 | #region Properties 15 | 16 | public bool HasTimer => _timer != null; 17 | 18 | #endregion 19 | 20 | #region Methods 21 | 22 | public void Debounce(int interval, Action action) 23 | { 24 | _timer?.Stop(); 25 | _timer = null; 26 | 27 | _timer = new DispatcherTimer(TimeSpan.FromMilliseconds(interval), DispatcherPriority.Normal, (s, e) => 28 | { 29 | if (_timer == null) 30 | { 31 | return; 32 | } 33 | 34 | _timer?.Stop(); 35 | _timer = null; 36 | 37 | action.Invoke(); 38 | }, Dispatcher.CurrentDispatcher); 39 | 40 | _timer.Start(); 41 | } 42 | 43 | public bool Reset() 44 | { 45 | if (_timer == null) 46 | { 47 | return false; 48 | } 49 | 50 | _timer?.Stop(); 51 | _timer = null; 52 | 53 | return true; 54 | } 55 | 56 | #endregion 57 | } 58 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Services/FlyoutService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Services; 2 | 3 | using System; 4 | using Caliburn.Micro; 5 | using GitLurker.UI.Models; 6 | using MahApps.Metro.Controls; 7 | 8 | public class FlyoutService 9 | { 10 | #region Events 11 | 12 | public event EventHandler ShowFlyoutRequested; 13 | public event EventHandler CloseFlyoutRequested; 14 | public event EventHandler FlyoutClosed; 15 | 16 | #endregion 17 | 18 | #region Methods 19 | 20 | public Position CurrentPosition { get; private set; } 21 | 22 | #endregion 23 | 24 | #region Methods 25 | 26 | public void Show(string header, PropertyChangedBase content, Position position) 27 | { 28 | CurrentPosition = position; 29 | var request = new FlyoutRequest 30 | { 31 | Header = header, 32 | Content = content, 33 | Position = position 34 | }; 35 | ShowFlyoutRequested?.Invoke(this, request); 36 | } 37 | 38 | public void Close() 39 | { 40 | CloseFlyoutRequested?.Invoke(this, EventArgs.Empty); 41 | } 42 | 43 | public void NotifyFlyoutClosed() 44 | { 45 | FlyoutClosed?.Invoke(this, EventArgs.Empty); 46 | } 47 | 48 | #endregion 49 | } 50 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Services/MouseService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Services; 2 | 3 | using System; 4 | using System.Diagnostics; 5 | using System.Threading.Tasks; 6 | using GitLurker.UI.Models; 7 | using Winook; 8 | 9 | public class MouseService 10 | { 11 | #region Fields 12 | 13 | private int _x; 14 | private int _y; 15 | private MouseHook _hook; 16 | 17 | #endregion 18 | 19 | public event EventHandler LeftButtonUp; 20 | 21 | public event EventHandler MousePositionChanged; 22 | 23 | public MousePosition GetCurrentPosition() 24 | => new() { X = _x, Y = _y }; 25 | 26 | public Task InstallAsync() 27 | { 28 | var process = Process.GetCurrentProcess(); 29 | _hook = new MouseHook(process.Id); 30 | _hook.MouseMove += Hook_MouseMove; 31 | _hook.LeftButtonUp += Hook_LeftButtonUp; 32 | 33 | return _hook.InstallAsync(); 34 | } 35 | 36 | private void Hook_LeftButtonUp(object sender, MouseMessageEventArgs e) 37 | { 38 | LeftButtonUp?.Invoke(this, EventArgs.Empty); 39 | } 40 | 41 | private void Hook_MouseMove(object sender, MouseMessageEventArgs e) 42 | { 43 | _x = e.X; 44 | _y = e.Y; 45 | MousePositionChanged?.Invoke(this, new MousePosition{ X = e.X, Y = e.Y}); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/CustomAction.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using System.Collections.Generic; 4 | 5 | public class CustomAction 6 | { 7 | #region Constructors 8 | 9 | public CustomAction() 10 | { 11 | Repositories = []; 12 | } 13 | 14 | #endregion 15 | 16 | #region Properties 17 | 18 | public string Name { get; set; } 19 | 20 | public string Icon { get; set; } 21 | 22 | public string Command { get; set; } 23 | 24 | public List Repositories { get; set; } 25 | 26 | public bool OpenConsole { get; set; } 27 | 28 | public bool ExcludeRepositories { get; set; } 29 | 30 | #endregion 31 | 32 | #region Methods 33 | 34 | public bool AddRepository(Repository repo) 35 | { 36 | if (Repositories.Contains(repo.Folder)) 37 | { 38 | return false; 39 | } 40 | 41 | Repositories.Add(repo.Folder); 42 | return true; 43 | } 44 | 45 | public bool RemoveRepository(Repository repo) 46 | { 47 | return Repositories.Remove(repo.Folder); 48 | } 49 | 50 | public bool IsIncluded(string repoPath) 51 | { 52 | var contains = Repositories.Contains(repoPath); 53 | return ExcludeRepositories ? !contains : contains; 54 | } 55 | 56 | #endregion 57 | } 58 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/ConsoleView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System.Windows.Controls; 4 | using System.Windows.Input; 5 | 6 | /// 7 | /// Interaction logic for ConsoleView.xaml 8 | /// 9 | public partial class ConsoleView : UserControl 10 | { 11 | private bool _autoScroll = true; 12 | 13 | public ConsoleView() 14 | { 15 | InitializeComponent(); 16 | } 17 | 18 | private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e) 19 | { 20 | var scrollViewer = (ScrollViewer)sender; 21 | scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta); 22 | e.Handled = true; 23 | } 24 | 25 | private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) 26 | { 27 | if (e.ExtentHeightChange == 0) 28 | { 29 | if (ScrollViewer.VerticalOffset == ScrollViewer.ScrollableHeight) 30 | { 31 | _autoScroll = true; 32 | } 33 | else 34 | { 35 | _autoScroll = false; 36 | } 37 | } 38 | 39 | if (_autoScroll && e.ExtentHeightChange != 0) 40 | { 41 | ScrollViewer.ScrollToVerticalOffset(ScrollViewer.ExtentHeight); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/GitLurker.UI/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/GitLurker.UI.csproj", 11 | "/property:GenerateFullPaths=true", 12 | "/consoleloggerparameters:NoSummary" 13 | ], 14 | "problemMatcher": "$msCompile" 15 | }, 16 | { 17 | "label": "publish", 18 | "command": "dotnet", 19 | "type": "process", 20 | "args": [ 21 | "publish", 22 | "${workspaceFolder}/GitLurker.UI.csproj", 23 | "/property:GenerateFullPaths=true", 24 | "/consoleloggerparameters:NoSummary" 25 | ], 26 | "problemMatcher": "$msCompile" 27 | }, 28 | { 29 | "label": "watch", 30 | "command": "dotnet", 31 | "type": "process", 32 | "args": [ 33 | "watch", 34 | "run", 35 | "--project", 36 | "${workspaceFolder}/GitLurker.UI.csproj" 37 | ], 38 | "problemMatcher": "$msCompile" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/SnippetTileViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using Caliburn.Micro; 4 | using GitLurker.Core.Models; 5 | using GitLurker.UI.Services; 6 | using NHotkey.Wpf; 7 | 8 | public class SnippetTileViewModel : PropertyChangedBase 9 | { 10 | #region Fields 11 | 12 | private static readonly SettingsFile SettingsFile = IoC.Get(); 13 | private static readonly FlyoutService CurrentFlyoutService = IoC.Get(); 14 | private Snippet _snippet; 15 | 16 | #endregion 17 | 18 | #region Constructors 19 | 20 | public SnippetTileViewModel(Snippet snippet) 21 | { 22 | _snippet = snippet; 23 | } 24 | 25 | #endregion 26 | 27 | #region Properties 28 | 29 | public string SnippetName => _snippet.Name; 30 | 31 | #endregion 32 | 33 | #region Methods 34 | 35 | public void Open() 36 | { 37 | CurrentFlyoutService.Show(_snippet.Name, new SnippetViewModel(_snippet), MahApps.Metro.Controls.Position.Right); 38 | } 39 | 40 | public void Delete() 41 | { 42 | SettingsFile.RemoveSnippet(_snippet); 43 | 44 | HotkeyManager.Current.Remove(_snippet.Id.ToString()); 45 | 46 | // To notify the parent 47 | NotifyOfPropertyChange("Deleted"); 48 | } 49 | 50 | #endregion 51 | } 52 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/CustomActionTileViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using Caliburn.Micro; 4 | using GitLurker.Core.Models; 5 | using GitLurker.UI.Services; 6 | using MahApps.Metro.IconPacks; 7 | 8 | public class CustomActionTileViewModel : PropertyChangedBase 9 | { 10 | #region Fields 11 | 12 | private static readonly CustomActionSettingsFile CustomActionSettingsFile = IoC.Get(); 13 | private static readonly FlyoutService CurrentFlyoutService = IoC.Get(); 14 | private CustomAction _action; 15 | 16 | #endregion 17 | 18 | #region Constructors 19 | 20 | public CustomActionTileViewModel(CustomAction action) 21 | { 22 | _action = action; 23 | } 24 | 25 | #endregion 26 | 27 | #region Properties 28 | 29 | public string ActionName => _action.Name; 30 | 31 | public PackIconControlBase Icon => new PackIconMaterial() { Kind = System.Enum.Parse(_action.Icon) }; 32 | 33 | #endregion 34 | 35 | #region Methods 36 | 37 | public void Open() 38 | { 39 | CurrentFlyoutService.Show(_action.Name, new CustomActionViewModel(_action), MahApps.Metro.Controls.Position.Right); 40 | } 41 | 42 | public void Delete() 43 | { 44 | CustomActionSettingsFile.DeleteAction(_action); 45 | 46 | // To notify the parent 47 | NotifyOfPropertyChange("Deleted"); 48 | } 49 | 50 | #endregion 51 | } 52 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/FileViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System.IO; 4 | using Caliburn.Micro; 5 | using GitLurker.Core.Models; 6 | using GitLurker.UI.Views; 7 | 8 | public class FileViewModel : ItemViewModelBase 9 | { 10 | #region Fields 11 | 12 | private FileChange _fileChange; 13 | private Repository _repo; 14 | 15 | #endregion 16 | 17 | #region Constructors 18 | 19 | public FileViewModel(FileChange fileChange, Repository repo) 20 | { 21 | _repo = repo; 22 | _fileChange = fileChange; 23 | } 24 | 25 | #endregion 26 | 27 | #region Properties 28 | 29 | public string FileName => Path.GetFileName(_fileChange.FilePath); 30 | 31 | public override string Id => _fileChange.FilePath; 32 | 33 | public string Letter => _fileChange.Status switch 34 | { 35 | ChangeStatus.Deleted => "D", 36 | ChangeStatus.Modified => "M", 37 | ChangeStatus.Added => "A", 38 | _ => string.Empty, 39 | }; 40 | 41 | #endregion 42 | 43 | #region Methods 44 | 45 | public async void Open() 46 | { 47 | await _repo.ExecuteCommandAsync($"git difftool -x \"code --wait --diff\" -y -- \"{_fileChange.FilePath}\""); 48 | } 49 | 50 | public string Select() 51 | { 52 | IsSelected = true; 53 | Execute.OnUIThread(() => (View as FileView).MainBorder.BringIntoView()); 54 | 55 | return Id; 56 | } 57 | 58 | #endregion 59 | } 60 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/WorkspaceView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/AudioLibraryView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/GameLibraryView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/WelcomeView.xaml: -------------------------------------------------------------------------------- 1 | 12 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/ModeStatusViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System.Linq; 4 | using Caliburn.Micro; 5 | using GitLurker.Core.Models; 6 | using Lurker.Audio; 7 | 8 | public class ModeStatusViewModel : PropertyChangedBase 9 | { 10 | private SettingsFile _settings; 11 | private AudioSessionService _audioSessionService; 12 | 13 | public ModeStatusViewModel(SettingsFile settings, AudioSessionService audioService) 14 | { 15 | _settings = settings; 16 | _settings.OnFileSaved += Settings_OnFileSaved; 17 | _audioSessionService = audioService; 18 | } 19 | 20 | public bool GitActive => _settings.Entity.Mode == Mode.Git; 21 | 22 | public bool GitVisible => _settings.Entity.AudioEnabled || _settings.Entity.SteamEnabled; 23 | 24 | public bool AudioActive => _settings.Entity.Mode == Mode.Audio; 25 | 26 | public bool AudioVisible => _settings.Entity.AudioEnabled && _audioSessionService.GetSessions().Any(); 27 | 28 | public bool GameActive => _settings.Entity.Mode == Mode.Game; 29 | 30 | public bool GameVisible => _settings.Entity.SteamEnabled; 31 | 32 | private void Settings_OnFileSaved(object sender, Settings e) 33 | { 34 | NotifyModeChange(); 35 | } 36 | 37 | public void NotifyModeChange() 38 | { 39 | NotifyOfPropertyChange(() => GitActive); 40 | NotifyOfPropertyChange(() => AudioActive); 41 | NotifyOfPropertyChange(() => GameActive); 42 | 43 | NotifyOfPropertyChange(() => GitVisible); 44 | NotifyOfPropertyChange(() => AudioVisible); 45 | NotifyOfPropertyChange(() => GameVisible); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Services/ThemeService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Services; 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Windows; 7 | using GitLurker.Core.Models; 8 | 9 | public class ThemeService 10 | { 11 | #region Fields 12 | 13 | private Application _application; 14 | private SettingsFile _settingsService; 15 | 16 | #endregion 17 | 18 | #region Constructors 19 | 20 | public ThemeService(Application application, SettingsFile settingsFile) 21 | { 22 | _settingsService = settingsFile; 23 | _application = application; 24 | } 25 | 26 | #endregion 27 | 28 | #region Properties 29 | 30 | public Scheme Scheme => _settingsService.Entity.Scheme; 31 | 32 | #endregion 33 | 34 | #region Methods 35 | 36 | public void Apply() 37 | => Apply(_settingsService.Entity.Scheme); 38 | 39 | public void Apply(Scheme scheme) 40 | { 41 | ControlzEx.Theming.ThemeManager.Current.ChangeTheme(_application, $"{Theme.Dark}.{scheme}"); 42 | } 43 | 44 | public void Change(Theme theme, Scheme scheme) 45 | { 46 | _settingsService.Entity.Scheme = scheme; 47 | _settingsService.Save(); 48 | ControlzEx.Theming.ThemeManager.Current.ChangeTheme(_application, $"{theme}.{scheme}"); 49 | } 50 | 51 | public IEnumerable GetSchemes() => GetEnumValues(); 52 | 53 | private static IEnumerable GetEnumValues() 54 | { 55 | return Enum.GetValues(typeof(T)).Cast().ToArray().OrderBy(t => t); 56 | } 57 | 58 | #endregion 59 | } 60 | 61 | public enum Theme 62 | { 63 | Light, 64 | Dark 65 | } 66 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/NugetInformation.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using System; 4 | using System.IO; 5 | using System.Linq; 6 | using NuGet.Versioning; 7 | 8 | public class NugetInformation 9 | { 10 | private NugetInformation(string fileName) 11 | { 12 | var segments = fileName.Split("."); 13 | 14 | var versionValue = string.Join('.', segments.TakeLast(3)); 15 | 16 | Version = new NuGetVersion(versionValue); 17 | PackageName = string.Join(".", segments.Take(segments.Length - 3)); 18 | } 19 | 20 | public string Name => $"{PackageName} {Version.ToNormalizedString()}"; 21 | 22 | public NuGetVersion Version { get; private set; } 23 | 24 | public string PackageName { get; private set; } 25 | 26 | public string FilePath { get; set; } 27 | 28 | public static NugetInformation Parse(string value) 29 | { 30 | if (Path.GetExtension(value) != ".nupkg") 31 | { 32 | throw new InvalidOperationException("Not a nuget package"); 33 | } 34 | 35 | var fileName = Path.GetFileNameWithoutExtension(value); 36 | return new NugetInformation(fileName) 37 | { 38 | FilePath = value, 39 | }; 40 | } 41 | 42 | public static NugetInformation ParseFromFeed(string value) 43 | { 44 | return new NugetInformation(value.Replace(' ', '.')); 45 | } 46 | 47 | public bool Ahead(NugetInformation informationToCompare) 48 | { 49 | return CompareTo(informationToCompare) > 0; 50 | } 51 | 52 | public int CompareTo(NugetInformation informationToCompare) 53 | { 54 | return Version.CompareTo(informationToCompare.Version); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/GameSettingsFile.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using Lurker.AppData; 4 | 5 | public class GameSettingsFile : AppDataFileBase 6 | { 7 | #region Fields 8 | 9 | private static readonly int MaxRecentCount = 5; 10 | 11 | #endregion 12 | 13 | #region Properties 14 | 15 | protected override string FileName => "Games.json"; 16 | 17 | protected override string FolderName => "GitLurker"; 18 | 19 | #endregion 20 | 21 | #region Methods 22 | 23 | public void AddRecent(string gameId) 24 | { 25 | var games = Entity.RecentGameIds; 26 | var index = games.IndexOf(gameId); 27 | if (index == -1) 28 | { 29 | if (games.Count >= MaxRecentCount) 30 | { 31 | games.RemoveAt(MaxRecentCount - 1); 32 | } 33 | } 34 | else 35 | { 36 | games.RemoveAt(index); 37 | } 38 | 39 | Entity.RecentGameIds.Insert(0, gameId); 40 | Save(); 41 | } 42 | 43 | public void RemoveRecent(string gameId) 44 | { 45 | var games = Entity.RecentGameIds; 46 | var index = games.IndexOf(gameId); 47 | if (index == -1) 48 | { 49 | return; 50 | } 51 | 52 | games.RemoveAt(index); 53 | Save(); 54 | } 55 | 56 | public void SetSteamExePath(string path) 57 | { 58 | Entity.SteamExePath = path; 59 | Entity.SteamAsked = true; 60 | Save(); 61 | } 62 | 63 | public void SetEpicExePath(string path) 64 | { 65 | Entity.EpicExePath = path; 66 | Entity.EpicAsked = true; 67 | Save(); 68 | } 69 | 70 | #endregion 71 | } 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git-Lurker 2 | 3 | GitLurker is an overlay to ease the navigation between Git Repositories 4 | 5 | ## Hotkeys 6 | 7 | `CTRL + G` : Is the Default Hotkey to open the overlay. 8 | 9 | `Enter` : Will launch the selected project using your default editor. ([Visual Studio](https://visualstudio.microsoft.com/vs/community/) | [Rider](https://www.jetbrains.com/rider/) | [VSCode](https://code.visualstudio.com/)) 10 | 11 | `CTRL + Enter` : Will open [Windows Terminal](https://www.microsoft.com/en-ca/p/windows-terminal/9n0dx20hk701?activetab=pivot:overviewtab) to the Git Repository path. 12 | 13 | `CTRL + Shift + Enter` : Will open Windows File Explorer to the Git Repository path. 14 | 15 | ![image](https://user-images.githubusercontent.com/5436436/173985733-0d8dc9c6-fbad-4d79-a83d-36d6f746aa85.png) 16 | 17 | # Usage 18 | - `git clone https://github.com/C1rdec/Git-Lurker.git` 19 | - Build the Solution with your favorite IDE **or** run this command: 20 | - `dotnet run --project .\Git-Lurker\src\GitLurker.UI\GitLurker.UI.csproj -c release` 21 | 22 | After the first Launch **GitLurker** will set a shortcut to the ***Startup Menu*** and ***Start with Windows***. 23 |
(*Can be disabled in the Settings/Advanced*) 24 | 25 | | System Tray | Add Workspace Folder Path | 26 | | ------------- | ------------- | 27 | | ![image](https://user-images.githubusercontent.com/5436436/159106241-eac5b233-10a4-4dbc-a781-3f1944c08c84.png) | ![image](https://user-images.githubusercontent.com/5436436/173984452-3dcea779-0c56-429f-bda0-0dec451245ad.png) 28 | 29 | ![GitLurker](https://user-images.githubusercontent.com/5436436/173988706-939889f4-a76d-42b3-abbe-0ee6a5e45a8b.gif) 30 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/Settings.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using System.Collections.Generic; 4 | using LibGit2Sharp; 5 | 6 | public class Settings 7 | { 8 | #region Constructors 9 | 10 | public Settings() 11 | { 12 | Snippets = []; 13 | Workspaces = []; 14 | RecentRepos = []; 15 | HotKey = new Hotkey() 16 | { 17 | Modifier = Winook.Modifiers.Control, 18 | KeyCode = Winook.KeyCode.G, 19 | }; 20 | DevToysHotKey = new Hotkey() 21 | { 22 | Modifier = Winook.Modifiers.None, 23 | KeyCode = Winook.KeyCode.None, 24 | }; 25 | 26 | StartWithWindows = true; 27 | AddToStartMenu = true; 28 | RebaseOperation = CurrentOperation.Rebase; 29 | Mode = Mode.Git; 30 | RemoteNugetSource = "https://api.nuget.org/v3/index.json"; 31 | } 32 | 33 | #endregion 34 | 35 | #region Properties 36 | 37 | public List Snippets { get; set; } 38 | 39 | public List Workspaces { get; set; } 40 | 41 | public List RecentRepos { get; set; } 42 | 43 | public Hotkey HotKey { get; set; } 44 | 45 | public Hotkey DevToysHotKey { get; set; } 46 | 47 | public bool ConsoleOuput { get; set; } 48 | 49 | public bool StartWithWindows { get; set; } 50 | 51 | public bool AddToStartMenu { get; set; } 52 | 53 | public string LocalNugetSource { get; set; } 54 | 55 | public string RemoteNugetSource { get; set; } 56 | 57 | public string NugetApiKey { get; set; } 58 | 59 | public bool IsAdmin { get; set; } 60 | 61 | public bool SteamEnabled { get; set; } 62 | 63 | public bool AudioEnabled { get; set; } 64 | 65 | public Scheme Scheme { get; set; } 66 | 67 | public CurrentOperation RebaseOperation { get; set; } 68 | 69 | public Mode Mode { get; set; } 70 | 71 | #endregion 72 | } 73 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/RepoManagerViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Windows.Forms; 6 | using GitLurker.Core.Models; 7 | 8 | public class RepoManagerViewModel 9 | { 10 | #region Fields 11 | 12 | private SettingsFile _settings; 13 | 14 | #endregion 15 | 16 | #region Constructors 17 | 18 | public RepoManagerViewModel(SettingsFile settings) 19 | { 20 | _settings = settings; 21 | 22 | Folders = new ObservableCollection(); 23 | foreach (var workspace in _settings.Entity.Workspaces) 24 | { 25 | Folders.Add(new FolderViewModel(workspace, Delete)); 26 | } 27 | } 28 | 29 | #endregion 30 | 31 | #region Properties 32 | 33 | public ObservableCollection Folders { get; set; } 34 | 35 | #endregion 36 | 37 | #region Methods 38 | 39 | public void Add() 40 | { 41 | using var dialog = new FolderBrowserDialog(); 42 | var result = dialog.ShowDialog(); 43 | if (result != DialogResult.OK) 44 | { 45 | return; 46 | } 47 | 48 | var existingWorkspace = _settings.Entity.Workspaces.FirstOrDefault(w => w == dialog.SelectedPath); 49 | if (existingWorkspace != null) 50 | { 51 | return; 52 | } 53 | 54 | _settings.Entity.Workspaces.Add(dialog.SelectedPath); 55 | _settings.Save(); 56 | 57 | Folders.Add(new FolderViewModel(dialog.SelectedPath, Delete)); 58 | } 59 | 60 | private void Delete(string folderPath) 61 | { 62 | var folder = Folders.FirstOrDefault(f => f.Folder == folderPath); 63 | if (folder != null) 64 | { 65 | Folders.Remove(folder); 66 | _settings.RemoveWorkspace(folderPath); 67 | } 68 | } 69 | 70 | #endregion 71 | } 72 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Services/NugetService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Services; 2 | 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using GitLurker.Core.Models; 6 | 7 | public class NugetService : ProcessService 8 | { 9 | #region Constructors 10 | 11 | public NugetService(string folder) 12 | : base(folder) 13 | { 14 | } 15 | 16 | #endregion 17 | 18 | #region Methods 19 | 20 | public Task AddNugetAsync(NugetInformation nuget) 21 | => AddNugetAsync(nuget, false); 22 | 23 | public Task AddNugetAsync(NugetInformation nuget, bool online) 24 | { 25 | var settings = new SettingsFile(); 26 | settings.Initialize(); 27 | 28 | if (!settings.HasNugetSource()) 29 | { 30 | return null; 31 | } 32 | 33 | var source = online ? settings.Entity.RemoteNugetSource : settings.Entity.LocalNugetSource; 34 | var apiKey = online && !string.IsNullOrEmpty(settings.Entity.NugetApiKey) ? $"-k {settings.Entity.NugetApiKey}" : ""; 35 | 36 | return ExecuteCommandAsync($@"dotnet nuget push ""{nuget.FilePath}"" {apiKey} -s {source} --skip-duplicate", true); 37 | } 38 | 39 | public async Task GetLatestNugetAsync() 40 | { 41 | NugetInformation newNuget = null; 42 | 43 | // To get out of the UI Thread 44 | await Task.Run(() => 45 | { 46 | var filePaths = GetFiles($"*.nupkg", int.MaxValue).Where(n => n.FullName.Contains("\\bin\\")); 47 | if (filePaths.Any()) 48 | { 49 | var nugetsInRepo = filePaths.Select(p => NugetInformation.Parse(p.FullName)); 50 | 51 | var list = nugetsInRepo.ToList(); 52 | list.Sort((n1, n2) => n2.CompareTo(n1)); 53 | newNuget = list.FirstOrDefault(); 54 | } 55 | }); 56 | 57 | return newNuget; 58 | } 59 | 60 | #endregion 61 | } 62 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/FlyoutScreenBase.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System; 4 | using Caliburn.Micro; 5 | using GitLurker.UI.Models; 6 | using GitLurker.UI.Services; 7 | 8 | public abstract class FlyoutScreenBase : Screen 9 | { 10 | private FlyoutService _flyoutService; 11 | private PropertyChangedBase _flyoutContent; 12 | 13 | public FlyoutScreenBase(FlyoutService service) 14 | { 15 | _flyoutService = service; 16 | _flyoutService.ShowFlyoutRequested += FlyoutService_ShowFlyout; 17 | _flyoutService.CloseFlyoutRequested += FlyoutService_CloseFlyout; 18 | } 19 | 20 | public string FlyoutHeader 21 | { 22 | get => field; 23 | set 24 | { 25 | field = value; 26 | NotifyOfPropertyChange(() => FlyoutHeader); 27 | } 28 | } 29 | 30 | public bool FlyoutOpen 31 | { 32 | get => field; 33 | set 34 | { 35 | if (!value) 36 | { 37 | _flyoutService.NotifyFlyoutClosed(); 38 | } 39 | 40 | field = value; 41 | NotifyOfPropertyChange(() => FlyoutOpen); 42 | } 43 | } 44 | 45 | public PropertyChangedBase FlyoutContent 46 | { 47 | get => _flyoutContent; 48 | set 49 | { 50 | _flyoutContent = value; 51 | NotifyOfPropertyChange(() => FlyoutContent); 52 | } 53 | } 54 | 55 | public void ShowFlyout(string header, PropertyChangedBase content) 56 | { 57 | FlyoutHeader = header; 58 | FlyoutContent = content; 59 | FlyoutOpen = true; 60 | } 61 | 62 | public void CloseFlyout() 63 | { 64 | FlyoutOpen = false; 65 | 66 | // We use the field since we dont want to notify the UI 67 | _flyoutContent = null; 68 | } 69 | 70 | private void FlyoutService_ShowFlyout(object _, FlyoutRequest e) => ShowFlyout(e.Header, e.Content); 71 | 72 | private void FlyoutService_CloseFlyout(object _, EventArgs e) => CloseFlyout(); 73 | } 74 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/GameViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System; 4 | using System.Windows; 5 | using System.Windows.Interop; 6 | using System.Windows.Media.Imaging; 7 | using Caliburn.Micro; 8 | using GitLurker.Core.Models; 9 | using GitLurker.UI.Messages; 10 | using Lurker.Common.Models; 11 | 12 | public class GameViewModel : ItemViewModelBase 13 | { 14 | #region Fields 15 | 16 | private static readonly CloseMessage CloseMessage = new(); 17 | private GameBase _game; 18 | private IEventAggregator _eventAggregator; 19 | 20 | #endregion 21 | 22 | #region Constructors 23 | 24 | public GameViewModel(GameBase game) 25 | { 26 | _game = game; 27 | _eventAggregator = IoC.Get(); 28 | } 29 | 30 | #endregion 31 | 32 | #region Properties 33 | 34 | public override string Id => _game.Id; 35 | 36 | public BitmapSource IconSource 37 | { 38 | get 39 | { 40 | try 41 | { 42 | var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap( 43 | _game.GetIcon().GetHbitmap(), 44 | IntPtr.Zero, 45 | Int32Rect.Empty, 46 | BitmapSizeOptions.FromEmptyOptions()); 47 | 48 | return bitmapSource; 49 | } 50 | catch 51 | { 52 | return null; 53 | } 54 | } 55 | } 56 | 57 | public string GameName => _game.Name; 58 | 59 | public bool IsSteam => _game.Launcher == LauncherType.Steam; 60 | 61 | public bool IsEpic => _game.Launcher == LauncherType.Epic; 62 | 63 | public bool IsBattleNet => _game.Launcher == LauncherType.BattleNet; 64 | 65 | #endregion 66 | 67 | #region Methods 68 | 69 | public void Open() 70 | { 71 | var settings = new GameSettingsFile(); 72 | settings.Initialize(); 73 | settings.AddRecent(_game.Id); 74 | _eventAggregator.PublishOnCurrentThreadAsync(CloseMessage); 75 | 76 | _game.Open(); 77 | } 78 | 79 | #endregion 80 | } 81 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/FolderView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | 21 | 28 | 29 | 30 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/RepoManagerView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/SnippetManagerViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System.Collections.ObjectModel; 4 | using Caliburn.Micro; 5 | using GitLurker.Core.Models; 6 | using GitLurker.UI.Services; 7 | 8 | public class SnippetManagerViewModel : PropertyChangedBase 9 | { 10 | #region Fields 11 | 12 | private SettingsFile _file; 13 | 14 | #endregion 15 | 16 | #region Constructors 17 | 18 | public SnippetManagerViewModel() 19 | { 20 | _file = IoC.Get(); 21 | _file.OnFileSaved += File_OnFileSaved; 22 | Snippets = new ObservableCollection(); 23 | AddSnippets(); 24 | } 25 | 26 | #endregion 27 | 28 | #region Properties 29 | 30 | public ObservableCollection Snippets { get; set; } 31 | 32 | #endregion 33 | 34 | public void Add() 35 | { 36 | var viewModel = new SnippetViewModel(new Snippet()); 37 | IoC.Get().Show("New Snippet", viewModel, MahApps.Metro.Controls.Position.Right); 38 | } 39 | 40 | private void File_OnFileSaved(object sender, Settings e) 41 | { 42 | foreach (var snippet in Snippets) 43 | { 44 | snippet.PropertyChanged -= CustomActionManagerViewModel_PropertyChanged; 45 | } 46 | 47 | Snippets.Clear(); 48 | AddSnippets(); 49 | } 50 | 51 | private void AddSnippets() 52 | { 53 | foreach (var snippet in _file.Entity.Snippets) 54 | { 55 | var viewModel = new SnippetTileViewModel(snippet); 56 | viewModel.PropertyChanged += CustomActionManagerViewModel_PropertyChanged; 57 | Snippets.Add(viewModel); 58 | } 59 | } 60 | 61 | private void CustomActionManagerViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 62 | { 63 | if (sender is not SnippetTileViewModel viewModel) 64 | { 65 | return; 66 | } 67 | 68 | if (e.PropertyName == "Deleted") 69 | { 70 | viewModel.PropertyChanged -= CustomActionManagerViewModel_PropertyChanged; 71 | Snippets.Remove(viewModel); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/SnippetManagerView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/CustomActionManagerView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/PatreonView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System; 4 | using System.Runtime.InteropServices; 5 | using System.Windows.Interop; 6 | using MahApps.Metro.Controls; 7 | 8 | /// 9 | /// Interaction logic for PatreonView.xaml 10 | /// 11 | public partial class PatreonView : MetroWindow 12 | { 13 | public PatreonView() 14 | { 15 | InitializeComponent(); 16 | 17 | var hWnd = new WindowInteropHelper(GetWindow(this)).EnsureHandle(); 18 | var attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE; 19 | var preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND; 20 | DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint)); 21 | } 22 | 23 | /// 24 | /// Represents window attributes. 25 | /// 26 | public enum DWMWINDOWATTRIBUTE 27 | { 28 | /// 29 | /// The windows preference. 30 | /// 31 | DWMWA_WINDOW_CORNER_PREFERENCE = 33, 32 | } 33 | 34 | /// 35 | /// The DWM_WINDOW_CORNER_PREFERENCE enum for DwmSetWindowAttribute's third parameter, which tells the function 36 | /// what value of the enum to set. 37 | /// 38 | public enum DWM_WINDOW_CORNER_PREFERENCE 39 | { 40 | /// 41 | /// Let the system decide whether or not to round window corners. 42 | /// 43 | DWMWCP_DEFAULT = 0, 44 | 45 | /// 46 | /// Never round window corners. 47 | /// 48 | DWMWCP_DONOTROUND = 1, 49 | 50 | /// 51 | /// Round the corners if appropriate. 52 | /// 53 | DWMWCP_ROUND = 2, 54 | 55 | /// 56 | /// Round the corners if appropriate, with a small radius. 57 | /// 58 | DWMWCP_ROUNDSMALL = 3, 59 | } 60 | 61 | // Import dwmapi.dll and define DwmSetWindowAttribute in C# corresponding to the native function. 62 | [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, SetLastError = true)] 63 | private static extern long DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute, uint cbAttribute); 64 | } 65 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/WelcomeView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System; 4 | using System.Runtime.InteropServices; 5 | using System.Windows.Interop; 6 | using MahApps.Metro.Controls; 7 | 8 | /// 9 | /// Interaction logic for WelcomeView.xaml 10 | /// 11 | public partial class WelcomeView : MetroWindow 12 | { 13 | public WelcomeView() 14 | { 15 | InitializeComponent(); 16 | 17 | var hWnd = new WindowInteropHelper(GetWindow(this)).EnsureHandle(); 18 | var attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE; 19 | var preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND; 20 | DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint)); 21 | } 22 | 23 | /// 24 | /// Represents window attributes. 25 | /// 26 | public enum DWMWINDOWATTRIBUTE 27 | { 28 | /// 29 | /// The windows preference. 30 | /// 31 | DWMWA_WINDOW_CORNER_PREFERENCE = 33, 32 | } 33 | 34 | /// 35 | /// The DWM_WINDOW_CORNER_PREFERENCE enum for DwmSetWindowAttribute's third parameter, which tells the function 36 | /// what value of the enum to set. 37 | /// 38 | public enum DWM_WINDOW_CORNER_PREFERENCE 39 | { 40 | /// 41 | /// Let the system decide whether or not to round window corners. 42 | /// 43 | DWMWCP_DEFAULT = 0, 44 | 45 | /// 46 | /// Never round window corners. 47 | /// 48 | DWMWCP_DONOTROUND = 1, 49 | 50 | /// 51 | /// Round the corners if appropriate. 52 | /// 53 | DWMWCP_ROUND = 2, 54 | 55 | /// 56 | /// Round the corners if appropriate, with a small radius. 57 | /// 58 | DWMWCP_ROUNDSMALL = 3, 59 | } 60 | 61 | // Import dwmapi.dll and define DwmSetWindowAttribute in C# corresponding to the native function. 62 | [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, SetLastError = true)] 63 | private static extern long DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute, uint cbAttribute); 64 | } 65 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/SettingsView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Views; 2 | 3 | using System; 4 | using System.Runtime.InteropServices; 5 | using System.Windows.Interop; 6 | using MahApps.Metro.Controls; 7 | 8 | /// 9 | /// Interaction logic for SettingsView.xaml 10 | /// 11 | public partial class SettingsView : MetroWindow 12 | { 13 | public SettingsView() 14 | { 15 | InitializeComponent(); 16 | 17 | var hWnd = new WindowInteropHelper(GetWindow(this)).EnsureHandle(); 18 | var attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE; 19 | var preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND; 20 | DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint)); 21 | } 22 | 23 | /// 24 | /// Represents window attributes. 25 | /// 26 | public enum DWMWINDOWATTRIBUTE 27 | { 28 | /// 29 | /// The windows preference. 30 | /// 31 | DWMWA_WINDOW_CORNER_PREFERENCE = 33, 32 | } 33 | 34 | /// 35 | /// The DWM_WINDOW_CORNER_PREFERENCE enum for DwmSetWindowAttribute's third parameter, which tells the function 36 | /// what value of the enum to set. 37 | /// 38 | public enum DWM_WINDOW_CORNER_PREFERENCE 39 | { 40 | /// 41 | /// Let the system decide whether or not to round window corners. 42 | /// 43 | DWMWCP_DEFAULT = 0, 44 | 45 | /// 46 | /// Never round window corners. 47 | /// 48 | DWMWCP_DONOTROUND = 1, 49 | 50 | /// 51 | /// Round the corners if appropriate. 52 | /// 53 | DWMWCP_ROUND = 2, 54 | 55 | /// 56 | /// Round the corners if appropriate, with a small radius. 57 | /// 58 | DWMWCP_ROUNDSMALL = 3, 59 | } 60 | 61 | // Import dwmapi.dll and define DwmSetWindowAttribute in C# corresponding to the native function. 62 | [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, SetLastError = true)] 63 | private static extern long DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute, uint cbAttribute); 64 | } 65 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Services/RepositoryService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Services; 2 | 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using GitLurker.Core.Models; 7 | 8 | public class RepositoryService 9 | { 10 | #region Fields 11 | 12 | private IEnumerable _workspaces; 13 | 14 | #endregion 15 | 16 | #region Constructors 17 | 18 | public RepositoryService() 19 | { 20 | _workspaces = new List(); 21 | GetWorkspaces(); 22 | } 23 | 24 | #endregion 25 | 26 | public IEnumerable Workspaces => _workspaces; 27 | 28 | #region Methods 29 | 30 | public IEnumerable Search(string term) 31 | { 32 | var allRepos = GetAllRepo(); 33 | 34 | var startWith = allRepos.Where(r => r.Name.StartsWith(term, System.StringComparison.CurrentCultureIgnoreCase)); 35 | var contain = allRepos.Where(r => r.Name.Contains(term, System.StringComparison.CurrentCultureIgnoreCase)).ToList(); 36 | contain.InsertRange(0, startWith); 37 | 38 | return contain.Distinct().Take(5); 39 | } 40 | 41 | public IEnumerable GetAllRepo() 42 | { 43 | var allRepos = new List(); 44 | foreach (var workspace in _workspaces) 45 | { 46 | allRepos.AddRange(workspace.Repositories); 47 | } 48 | 49 | return allRepos; 50 | } 51 | 52 | public Repository GetRepo(string name) 53 | { 54 | return GetAllRepo().FirstOrDefault(r => r.Name == name); 55 | } 56 | 57 | public IEnumerable GetWorkspaces() 58 | { 59 | var settingsFile = new SettingsFile(); 60 | settingsFile.Initialize(); 61 | 62 | _workspaces = settingsFile.Entity.Workspaces.Where(Directory.Exists).Select(w => new Workspace(w)).ToArray(); 63 | return _workspaces; 64 | } 65 | 66 | public Repository GetRepository(string folderPath) 67 | { 68 | foreach (var workspace in _workspaces) 69 | { 70 | var repo = workspace.GetRepo(folderPath); 71 | if (repo != null) 72 | { 73 | return repo; 74 | } 75 | } 76 | 77 | return null; 78 | } 79 | 80 | #endregion 81 | } 82 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/SnippetView.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 18 | 27 | 28 | 29 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/GitLurker.Package/Package.appxmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | GitLurker 16 | Cedrico 17 | Images\StoreLogo.png 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/CustomActionManagerViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System.Collections.ObjectModel; 4 | using Caliburn.Micro; 5 | using GitLurker.Core.Models; 6 | using GitLurker.UI.Services; 7 | 8 | public class CustomActionManagerViewModel : PropertyChangedBase 9 | { 10 | #region Fields 11 | 12 | private CustomActionSettingsFile _file; 13 | 14 | #endregion 15 | 16 | #region Constructors 17 | 18 | public CustomActionManagerViewModel() 19 | { 20 | _file = IoC.Get(); 21 | _file.OnFileSaved += File_OnFileSaved; 22 | Actions = new ObservableCollection(); 23 | AddActions(); 24 | } 25 | 26 | private void File_OnFileSaved(object sender, CustomActionSettings e) 27 | { 28 | foreach (var action in Actions) 29 | { 30 | action.PropertyChanged -= CustomActionManagerViewModel_PropertyChanged; 31 | } 32 | 33 | Actions.Clear(); 34 | 35 | 36 | AddActions(); 37 | } 38 | 39 | #endregion 40 | 41 | #region Properties 42 | 43 | public ObservableCollection Actions { get; set; } 44 | 45 | #endregion 46 | 47 | #region Methods 48 | 49 | public void Add() 50 | { 51 | var viewModel = new CustomActionViewModel(new CustomAction(), true); 52 | IoC.Get().Show("New Action", viewModel, MahApps.Metro.Controls.Position.Right); 53 | } 54 | 55 | private void CustomActionManagerViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 56 | { 57 | if (sender is not CustomActionTileViewModel viewModel) 58 | { 59 | return; 60 | } 61 | 62 | if (e.PropertyName == "Deleted") 63 | { 64 | viewModel.PropertyChanged -= CustomActionManagerViewModel_PropertyChanged; 65 | Actions.Remove(viewModel); 66 | } 67 | } 68 | 69 | private void AddActions() 70 | { 71 | foreach (var action in _file.Entity.Actions) 72 | { 73 | var viewModel = new CustomActionTileViewModel(action); 74 | viewModel.PropertyChanged += CustomActionManagerViewModel_PropertyChanged; 75 | Actions.Add(viewModel); 76 | } 77 | } 78 | 79 | #endregion 80 | } 81 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Services/GithubUpdateManager.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Services; 2 | 3 | using System; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Threading.Tasks; 7 | using System.Timers; 8 | using GitLurker.Core.Models; 9 | 10 | public class GithubUpdateManager 11 | { 12 | #region Fields 13 | 14 | private Repository _repo; 15 | private Timer _timer; 16 | 17 | #endregion 18 | 19 | #region Events 20 | 21 | public event EventHandler UpdateRequested; 22 | 23 | #endregion 24 | 25 | #region Methods 26 | 27 | public async Task Update() 28 | { 29 | await _repo.PullAsync(); 30 | var updateScript = Path.Combine(_repo.Folder, "update.bat"); 31 | var startInfo = new ProcessStartInfo() 32 | { 33 | WorkingDirectory = _repo.Folder, 34 | CreateNoWindow = true, 35 | FileName = updateScript 36 | }; 37 | 38 | Process.Start(startInfo); 39 | } 40 | 41 | public void Watch(Repository repo) 42 | { 43 | _repo = repo; 44 | 45 | if (CheckForUpdate()) 46 | { 47 | return; 48 | } 49 | 50 | if (_timer != null) 51 | { 52 | DisposeTimer(); 53 | } 54 | 55 | _timer = new Timer(TimeSpan.FromMinutes(8).TotalMilliseconds); 56 | _timer.Elapsed += Timer_Elapsed; 57 | _timer.Start(); 58 | } 59 | 60 | private void Timer_Elapsed(object sender, ElapsedEventArgs e) 61 | { 62 | CheckForUpdate(); 63 | } 64 | 65 | private bool CheckForUpdate() 66 | { 67 | try 68 | { 69 | _repo.Fetch(); 70 | } 71 | catch 72 | { 73 | return false; 74 | } 75 | 76 | var needUpdate = _repo.IsBehind(); 77 | if (needUpdate) 78 | { 79 | UpdateRequested?.Invoke(this, EventArgs.Empty); 80 | DisposeTimer(); 81 | } 82 | 83 | return needUpdate; 84 | } 85 | 86 | private void DisposeTimer() 87 | { 88 | if (_timer == null) 89 | { 90 | return; 91 | } 92 | 93 | _timer.Stop(); 94 | _timer.Elapsed -= Timer_Elapsed; 95 | _timer.Dispose(); 96 | _timer = null; 97 | } 98 | 99 | #endregion 100 | } 101 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/ItemListViewModelBase.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using Caliburn.Micro; 6 | 7 | public abstract class ItemListViewModelBase : PropertyChangedBase 8 | where T : ItemViewModelBase 9 | { 10 | private T _selectedViewModel; 11 | 12 | public T SelectedViewModel 13 | { 14 | get => _selectedViewModel; 15 | set 16 | { 17 | _selectedViewModel = value; 18 | NotifyOfPropertyChange(); 19 | } 20 | } 21 | 22 | public abstract ObservableCollection ItemViewModels { get; } 23 | 24 | protected bool IsMouseHover { get; private set; } 25 | 26 | public void Clear() 27 | { 28 | SelectedViewModel = null; 29 | Execute.OnUIThread(() => ItemViewModels.Clear()); 30 | } 31 | 32 | public void MoveUp() 33 | { 34 | if (SelectedViewModel == null) 35 | { 36 | return; 37 | } 38 | 39 | SelectedViewModel = ItemViewModels.FirstOrDefault(g => g.Id == SelectedViewModel.Id); 40 | var index = ItemViewModels.IndexOf(SelectedViewModel); 41 | if (index <= 0) 42 | { 43 | return; 44 | } 45 | 46 | index--; 47 | SelectedViewModel.IsSelected = false; 48 | SelectedViewModel = ItemViewModels.ElementAt(index); 49 | SelectedViewModel.IsSelected = true; 50 | } 51 | 52 | public void MoveDown() 53 | { 54 | if (SelectedViewModel == null) 55 | { 56 | SelectedViewModel = ItemViewModels.FirstOrDefault(); 57 | if (SelectedViewModel != null) 58 | { 59 | SelectedViewModel.IsSelected = true; 60 | } 61 | 62 | return; 63 | } 64 | 65 | SelectedViewModel = ItemViewModels.FirstOrDefault(g => g.Id == SelectedViewModel.Id); 66 | 67 | var index = ItemViewModels.IndexOf(SelectedViewModel); 68 | if (index == -1 || (index + 1) >= ItemViewModels.Count) 69 | { 70 | return; 71 | } 72 | 73 | index++; 74 | SelectedViewModel.IsSelected = false; 75 | SelectedViewModel = ItemViewModels.ElementAt(index); 76 | SelectedViewModel.IsSelected = true; 77 | } 78 | 79 | public void OnMouseEnter() 80 | { 81 | IsMouseHover = true; 82 | } 83 | 84 | public void OnMouseLeave() 85 | { 86 | IsMouseHover = false; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/SnippetViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System.Linq; 4 | using Caliburn.Micro; 5 | using GitLurker.Core.Models; 6 | using GitLurker.UI.Services; 7 | 8 | public class SnippetViewModel : PropertyChangedBase 9 | { 10 | #region Fields 11 | 12 | private Snippet _snippet; 13 | 14 | #endregion 15 | 16 | #region Constructors 17 | 18 | public SnippetViewModel(Snippet snippet) 19 | { 20 | _snippet = snippet; 21 | Hotkey = new HotkeyViewModel(snippet.Hotkey, (k, m) => Modified = true, "Hotkey"); 22 | 23 | PropertyChanged += SnippetViewModel_PropertyChanged; 24 | } 25 | 26 | #endregion 27 | 28 | #region Properties 29 | 30 | public string SnippetName 31 | { 32 | get => _snippet.Name; 33 | set 34 | { 35 | _snippet.Name = value; 36 | NotifyOfPropertyChange(); 37 | } 38 | } 39 | 40 | public string Value 41 | { 42 | get => _snippet.Value; 43 | set 44 | { 45 | _snippet.Value = value; 46 | NotifyOfPropertyChange(); 47 | } 48 | } 49 | 50 | public bool Modified 51 | { 52 | get => field; 53 | set 54 | { 55 | field = value; 56 | NotifyOfPropertyChange(); 57 | } 58 | } 59 | 60 | public HotkeyViewModel Hotkey { get; init; } 61 | 62 | #endregion 63 | 64 | #region Methods 65 | 66 | public void Save() 67 | { 68 | Modified = false; 69 | 70 | var file = IoC.Get(); 71 | 72 | var existingSnippet = file.Entity.Snippets.FirstOrDefault(s => s.Id == _snippet.Id); 73 | if (existingSnippet == null) 74 | { 75 | file.AddSnippet(_snippet); 76 | } 77 | else 78 | { 79 | existingSnippet.Value = _snippet.Value; 80 | existingSnippet.Name = _snippet.Name; 81 | existingSnippet.Hotkey = _snippet.Hotkey; 82 | } 83 | 84 | file.Save(); 85 | 86 | IoC.Get().Close(); 87 | } 88 | 89 | private void SnippetViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 90 | { 91 | if (e.PropertyName == nameof(Modified)) 92 | { 93 | return; 94 | } 95 | 96 | Modified = true; 97 | } 98 | 99 | #endregion 100 | } 101 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/PatreonViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System.Diagnostics; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Caliburn.Micro; 7 | using GitLurker.UI.Messages; 8 | using GitLurker.UI.Services; 9 | using Lurker.Patreon; 10 | 11 | public class PatreonViewModel : FlyoutScreenBase, IHandle 12 | { 13 | #region Fields 14 | 15 | private PatreonService _patronService; 16 | private IEventAggregator _eventAggregator; 17 | private PatreonSettingsViewModel _settings; 18 | 19 | #endregion 20 | 21 | public PatreonViewModel(PatreonService service, IEventAggregator eventAggregator, PatreonSettingsViewModel settings, FlyoutService flyoutService) 22 | : base(flyoutService) 23 | { 24 | _patronService = service; 25 | _eventAggregator = eventAggregator; 26 | _settings = settings; 27 | 28 | _eventAggregator.SubscribeOnPublishedThread(this); 29 | } 30 | 31 | #region Properties 32 | 33 | public bool NeedJoin => IsLoggedIn && !IsPledged; 34 | 35 | public string PatreonId => _patronService.PatreonId; 36 | 37 | public bool IsPledged => _patronService.IsPledged; 38 | 39 | public bool IsNotPledged => !IsPledged; 40 | 41 | public bool IsNotLoggedIn => string.IsNullOrEmpty(PatreonId); 42 | 43 | public bool IsLoggedIn => !IsNotLoggedIn; 44 | 45 | public PatreonSettingsViewModel Settings => _settings; 46 | 47 | #endregion 48 | 49 | #region Methods 50 | 51 | public Task HandleAsync(PatronMessage message, CancellationToken cancellationToken) 52 | { 53 | Notify(); 54 | 55 | return Task.CompletedTask; 56 | } 57 | 58 | public async void Login() 59 | { 60 | await _patronService.LoginAsync(); 61 | await _patronService.CheckPledgeStatusAsync("3779584"); 62 | 63 | Notify(); 64 | 65 | await _eventAggregator.PublishOnCurrentThreadAsync(new PatronMessage()); 66 | } 67 | 68 | public async void Pledge() 69 | { 70 | if (await _patronService.CheckPledgeStatusAsync("3779584")) 71 | { 72 | Notify(); 73 | 74 | return; 75 | } 76 | 77 | var psi = new ProcessStartInfo 78 | { 79 | FileName = "https://www.patreon.com/poelurker", 80 | UseShellExecute = true 81 | }; 82 | Process.Start(psi); 83 | } 84 | 85 | private void Notify() 86 | { 87 | NotifyOfPropertyChange(() => NeedJoin); 88 | NotifyOfPropertyChange(() => PatreonId); 89 | NotifyOfPropertyChange(() => IsPledged); 90 | NotifyOfPropertyChange(() => IsNotPledged); 91 | NotifyOfPropertyChange(() => IsNotLoggedIn); 92 | NotifyOfPropertyChange(() => IsLoggedIn); 93 | } 94 | 95 | #endregion 96 | } 97 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/AudioLibraryViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System; 4 | using System.Collections.ObjectModel; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using Caliburn.Micro; 8 | using GitLurker.UI.Services; 9 | using Lurker.Audio; 10 | 11 | public class AudioLibraryViewModel : ItemListViewModelBase, IItemListViewModel 12 | { 13 | #region Fields 14 | 15 | private MouseService _mouseService; 16 | private AudioSessionService _audioSessionService; 17 | private ObservableCollection _audioSessionViewModels; 18 | 19 | #endregion 20 | 21 | #region Constructors 22 | 23 | public AudioLibraryViewModel(MouseService mouseService) 24 | { 25 | _mouseService = mouseService; 26 | _audioSessionService = new AudioSessionService(); 27 | _audioSessionViewModels = []; 28 | } 29 | 30 | 31 | #endregion 32 | 33 | #region Properties 34 | 35 | public override ObservableCollection ItemViewModels => _audioSessionViewModels; 36 | 37 | #endregion 38 | 39 | #region Methods 40 | 41 | public bool Close() 42 | { 43 | Clear(); 44 | return true; 45 | } 46 | 47 | public void EnterLongPressed() 48 | { 49 | } 50 | 51 | public void NextTabPressed() 52 | { 53 | } 54 | 55 | public Task Open(bool skipModifier) 56 | { 57 | return Task.FromResult(false); 58 | } 59 | 60 | public async Task RefreshItems() 61 | { 62 | Clear(); 63 | await Task.Run(() => 64 | { 65 | foreach (var session in _audioSessionService.GetSessions()) 66 | { 67 | Execute.OnUIThread(() => _audioSessionViewModels.Add(new AudioSessionViewModel(session, _mouseService))); 68 | } 69 | }); 70 | } 71 | 72 | public void Search(string term) 73 | { 74 | Clear(); 75 | 76 | if (string.IsNullOrEmpty(term)) 77 | { 78 | ShowRecent(); 79 | return; 80 | } 81 | 82 | var sessions = _audioSessionService.GetSessions(); 83 | var startWith = sessions.Where(s => s.Name.StartsWith(term, StringComparison.OrdinalIgnoreCase)); 84 | var contain = sessions.Where(r => r.Name.Contains(term, StringComparison.OrdinalIgnoreCase)).ToList(); 85 | contain.InsertRange(0, startWith); 86 | 87 | var matches = contain.Distinct().Take(5); 88 | 89 | foreach (var session in matches) 90 | { 91 | ItemViewModels.Add(new AudioSessionViewModel(session, _mouseService)); 92 | } 93 | } 94 | 95 | public void ShowRecent() 96 | { 97 | _ = RefreshItems(); 98 | } 99 | 100 | #endregion 101 | } 102 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/NugetSettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using Caliburn.Micro; 4 | using GitLurker.Core.Models; 5 | 6 | public class NugetSettingsViewModel : PropertyChangedBase 7 | { 8 | #region Fields 9 | 10 | private SettingsFile _settingsFile; 11 | 12 | #endregion 13 | 14 | #region Constructors 15 | 16 | public NugetSettingsViewModel(SettingsFile settingsFile) 17 | { 18 | _settingsFile = settingsFile; 19 | NugetApiKey = _settingsFile.Entity.NugetApiKey; 20 | PropertyChanged += NugetSettingsViewModel_PropertyChanged; 21 | } 22 | 23 | #endregion 24 | 25 | #region Properties 26 | 27 | public bool Modified 28 | { 29 | get => field; 30 | set 31 | { 32 | field = value; 33 | NotifyOfPropertyChange(); 34 | } 35 | } 36 | 37 | public string NugetApiKey 38 | { 39 | get => _settingsFile.Entity.NugetApiKey; 40 | set 41 | { 42 | _settingsFile.Entity.NugetApiKey = value; 43 | NotifyOfPropertyChange(); 44 | } 45 | } 46 | 47 | public string LocalSource 48 | { 49 | get => _settingsFile.Entity.LocalNugetSource; 50 | set 51 | { 52 | _settingsFile.Entity.LocalNugetSource = value; 53 | NotifyOfPropertyChange(); 54 | } 55 | } 56 | 57 | public string RemoteSource 58 | { 59 | get => _settingsFile.Entity.RemoteNugetSource; 60 | set 61 | { 62 | _settingsFile.Entity.RemoteNugetSource = value; 63 | NotifyOfPropertyChange(); 64 | } 65 | } 66 | 67 | public bool HasNugetSource => _settingsFile.HasNugetSource(); 68 | 69 | #endregion 70 | 71 | #region Methods 72 | 73 | public void ToggleLocalNuget() 74 | { 75 | string path = null; 76 | if (!HasNugetSource) 77 | { 78 | using var dialog = new System.Windows.Forms.FolderBrowserDialog(); 79 | var result = dialog.ShowDialog(); 80 | 81 | if (result != System.Windows.Forms.DialogResult.OK) 82 | { 83 | return; 84 | } 85 | 86 | path = dialog.SelectedPath; 87 | } 88 | 89 | LocalSource = path; 90 | NotifyOfPropertyChange(() => HasNugetSource); 91 | _settingsFile.Save(); 92 | } 93 | 94 | public void Save() 95 | { 96 | Modified = false; 97 | _settingsFile.Save(); 98 | } 99 | 100 | private void NugetSettingsViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 101 | { 102 | if (e.PropertyName == nameof(Modified) || e.PropertyName == nameof(LocalSource)) 103 | { 104 | return; 105 | } 106 | 107 | Modified = true; 108 | } 109 | 110 | #endregion 111 | } 112 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/ActionBarView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 13 | 14 | 27 | 28 | 29 | 37 | 38 | 39 | 40 | 41 | 42 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/FileView.xaml: -------------------------------------------------------------------------------- 1 | 11 | 15 | 16 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 41 | 48 | 49 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/AudioSessionViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System; 4 | using System.Threading.Tasks; 5 | using System.Windows; 6 | using System.Windows.Controls; 7 | using System.Windows.Input; 8 | using System.Windows.Interop; 9 | using System.Windows.Media.Imaging; 10 | using GitLurker.UI.Models; 11 | using GitLurker.UI.Services; 12 | using Lurker.Audio; 13 | 14 | public class AudioSessionViewModel : ItemViewModelBase 15 | { 16 | private int _currentVolume; 17 | private ProgressBar _progressBar; 18 | private MousePosition _currentMousePosition; 19 | private MouseService _mouseService; 20 | private AudioSession _session; 21 | 22 | public AudioSessionViewModel(AudioSession session, MouseService mouseService) 23 | { 24 | _session = session; 25 | _mouseService = mouseService; 26 | } 27 | 28 | public BitmapSource IconSource 29 | { 30 | get 31 | { 32 | var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap( 33 | _session.Icon.GetHbitmap(), 34 | IntPtr.Zero, 35 | Int32Rect.Empty, 36 | BitmapSizeOptions.FromEmptyOptions()); 37 | 38 | return bitmapSource; 39 | } 40 | } 41 | 42 | public bool VolumeVisible => _currentMousePosition != null; 43 | 44 | public string SessionName => _session.Name; 45 | 46 | public int Volume 47 | { 48 | get => _session.Volume; 49 | set 50 | { 51 | _session.Volume = value; 52 | NotifyOfPropertyChange(); 53 | } 54 | } 55 | 56 | public override string Id => _session.Id; 57 | 58 | 59 | public void MouseDown(MouseButtonEventArgs e) 60 | { 61 | var position = e.GetPosition(e.Source as UIElement); 62 | _progressBar = e.Source as ProgressBar; 63 | 64 | if (_progressBar != null) 65 | { 66 | var volume = position.X / _progressBar.ActualWidth * 100; 67 | Volume = Convert.ToInt32(volume); 68 | _currentVolume = Volume; 69 | } 70 | 71 | _currentMousePosition = _mouseService.GetCurrentPosition(); 72 | _mouseService.MousePositionChanged += MouseService_MousePositionChanged; 73 | NotifyOfPropertyChange(() => VolumeVisible); 74 | } 75 | 76 | public async void OnMouseLeave() 77 | { 78 | _mouseService.MousePositionChanged -= MouseService_MousePositionChanged; 79 | _currentMousePosition = null; 80 | _currentVolume = 0; 81 | 82 | await Task.Delay(800); 83 | NotifyOfPropertyChange(() => VolumeVisible); 84 | } 85 | 86 | private void MouseService_MousePositionChanged(object sender, MousePosition e) 87 | { 88 | if (_currentMousePosition == null || _progressBar == null) 89 | { 90 | return; 91 | } 92 | 93 | var difference = e.X - _currentMousePosition.X; 94 | var i = difference / _progressBar.ActualWidth * 100; 95 | 96 | Volume = _currentVolume + Convert.ToInt32(i); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Converters/ModifierConverter.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.Converters; 2 | 3 | using System; 4 | using System.Windows.Data; 5 | using System.Windows.Markup; 6 | 7 | public class ModifierConverter : MarkupExtension, IValueConverter 8 | { 9 | #region Declarations 10 | 11 | private static ModifierConverter _instance; 12 | 13 | #endregion 14 | 15 | #region Constructors 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | public ModifierConverter() 21 | { 22 | } 23 | 24 | #endregion 25 | 26 | #region Methods 27 | 28 | /// 29 | /// When implemented in a derived class, returns an object that is provided as the value of the target property for this markup extension. 30 | /// 31 | /// A service provider helper that can provide services for the markup extension. 32 | /// 33 | /// The object value to set on the property where the extension is applied. 34 | /// 35 | public override object ProvideValue(IServiceProvider serviceProvider) 36 | { 37 | return _instance ??= new ModifierConverter(); 38 | } 39 | 40 | /// 41 | /// Converts a value. 42 | /// 43 | /// The value produced by the binding source. 44 | /// The type of the binding target property. 45 | /// The converter parameter to use. 46 | /// The culture to use in the converter. 47 | /// 48 | /// A converted value. If the method returns null, the valid null value is used. 49 | /// 50 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 51 | { 52 | var myModifiers = (Winook.Modifiers)Enum.Parse(typeof(Winook.Modifiers), parameter.ToString()); 53 | var currentModifiers = (Winook.Modifiers)Enum.Parse(typeof(Winook.Modifiers), value.ToString()); 54 | 55 | return myModifiers == currentModifiers ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed; 56 | } 57 | 58 | /// 59 | /// Converts a value. 60 | /// 61 | /// The value that is produced by the binding target. 62 | /// The type to convert to. 63 | /// The converter parameter to use. 64 | /// The culture to use in the converter. 65 | /// 66 | /// A converted value. If the method returns null, the valid null value is used. 67 | /// 68 | /// Not implemented. 69 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 70 | { 71 | throw new NotImplementedException(); 72 | } 73 | 74 | #endregion 75 | } 76 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/ConsoleView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/AudioSessionView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 13 | 14 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 41 | 49 | 50 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/CommitActionView.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 38 | 39 | 40 | 41 | 42 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/ActionViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Caliburn.Micro; 7 | using GitLurker.UI.Services; 8 | using MahApps.Metro.IconPacks; 9 | 10 | public class ActionViewModel : PropertyChangedBase 11 | { 12 | #region Fields 13 | 14 | private Guid _id; 15 | private Func _action; 16 | private Func _holdAction; 17 | private PackIconControlBase _icon; 18 | private bool _permanent; 19 | private DebounceService _debounceService; 20 | private CancellationTokenSource _tokenSource; 21 | 22 | #endregion 23 | 24 | #region Constructors 25 | 26 | public ActionViewModel(Func action, Func holdAction, PackIconControlBase icon, bool permanent, Guid id) 27 | { 28 | _action = action; 29 | _holdAction = holdAction; 30 | 31 | icon.Height = 30; 32 | icon.Width = 30; 33 | _icon = icon; 34 | _permanent = permanent; 35 | _id = id; 36 | _debounceService = new DebounceService(); 37 | } 38 | 39 | #endregion 40 | 41 | #region Properties 42 | 43 | public Guid Id => _id; 44 | 45 | public PackIconControlBase Icon => _icon; 46 | 47 | public bool Permanent => _permanent; 48 | 49 | public bool IsEnable => !IsDisable; 50 | 51 | public bool IsDisable 52 | { 53 | get => field; 54 | set 55 | { 56 | field = value; 57 | NotifyOfPropertyChange(); 58 | NotifyOfPropertyChange(() => IsEnable); 59 | } 60 | } 61 | 62 | public bool IsActive 63 | { 64 | get => field; 65 | set 66 | { 67 | field = value; 68 | NotifyOfPropertyChange(); 69 | } 70 | } 71 | 72 | public int HoldProgress 73 | { 74 | get => field; 75 | set 76 | { 77 | field = value; 78 | NotifyOfPropertyChange(); 79 | } 80 | } 81 | 82 | #endregion 83 | 84 | #region Methods 85 | 86 | public async void OnMouseUp() 87 | { 88 | CancelHold(); 89 | 90 | var progress = HoldProgress; 91 | HoldProgress = 0; 92 | 93 | var action = progress == 100 ? _holdAction : _action; 94 | await action(); 95 | } 96 | 97 | public void OnMouseDown() 98 | { 99 | if (_holdAction == null) 100 | { 101 | return; 102 | } 103 | 104 | _tokenSource = new CancellationTokenSource(); 105 | _debounceService.Debounce(300, () => Execute.OnUIThread(async () => 106 | { 107 | while (HoldProgress < 100 && _tokenSource != null) 108 | { 109 | HoldProgress+=2; 110 | await Task.Delay(20); 111 | } 112 | })); 113 | } 114 | 115 | public void OnMouseLeave() 116 | { 117 | CancelHold(); 118 | HoldProgress = 0; 119 | } 120 | 121 | private void CancelHold() 122 | { 123 | if (_tokenSource != null) 124 | { 125 | _tokenSource.Cancel(); 126 | _tokenSource.Dispose(); 127 | _tokenSource = null; 128 | } 129 | } 130 | 131 | #endregion 132 | } 133 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/SnippetTileView.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | 18 | 29 | 30 | 31 | 34 | 35 | 36 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/SettingsFile.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using System; 4 | using System.Linq; 5 | using Lurker.AppData; 6 | 7 | public class SettingsFile : AppDataFileBase 8 | { 9 | #region Fields 10 | 11 | private static readonly int MaxRecentCount = 5; 12 | 13 | #endregion 14 | 15 | #region Properties 16 | 17 | protected override string FileName => "Workspaces.json"; 18 | 19 | protected override string FolderName => "GitLurker"; 20 | 21 | #endregion 22 | 23 | #region Methods 24 | 25 | public void AddSnippet(Snippet snippet) 26 | => Entity.Snippets.Add(snippet); 27 | 28 | public void RemoveSnippet(Snippet snippet) 29 | { 30 | var existingSnippet = Entity.Snippets.FirstOrDefault(s => s.Id == snippet.Id); 31 | if (existingSnippet != null) 32 | { 33 | Entity.Snippets.Remove(existingSnippet); 34 | } 35 | } 36 | 37 | public void AddRecent(string folder) 38 | { 39 | var recentRepos = Entity.RecentRepos; 40 | var index = recentRepos.IndexOf(folder); 41 | if (index == -1) 42 | { 43 | if (recentRepos.Count >= MaxRecentCount) 44 | { 45 | recentRepos.RemoveAt(MaxRecentCount - 1); 46 | } 47 | } 48 | else 49 | { 50 | recentRepos.RemoveAt(index); 51 | } 52 | 53 | Entity.RecentRepos.Insert(0, folder); 54 | Save(); 55 | } 56 | 57 | public void RemoveRecent(string folder) 58 | { 59 | var recentRepos = Entity.RecentRepos; 60 | var index = recentRepos.IndexOf(folder); 61 | if (index == -1) 62 | { 63 | return; 64 | } 65 | 66 | recentRepos.RemoveAt(index); 67 | Save(); 68 | } 69 | 70 | public void RemoveWorkspace(string folderPath) 71 | { 72 | var workspace = Entity.Workspaces.FirstOrDefault(w => w == folderPath); 73 | if (workspace == null) 74 | { 75 | return; 76 | } 77 | 78 | Entity.Workspaces.Remove(workspace); 79 | Save(); 80 | } 81 | 82 | public bool HasNugetSource() => !string.IsNullOrEmpty(Entity.LocalNugetSource); 83 | 84 | public Mode GetNextMode() 85 | { 86 | var modes = Enum.GetValues(typeof(Mode)).Cast().ToList(); 87 | var currentIndex = modes.IndexOf(Entity.Mode); 88 | 89 | var turnOn = false; 90 | 91 | var nextMode = Mode.Git; 92 | while (!turnOn) 93 | { 94 | var nextIndex = currentIndex + 1; 95 | if (nextIndex >= modes.Count) 96 | { 97 | nextIndex = 0; 98 | } 99 | 100 | nextMode = modes[nextIndex]; 101 | currentIndex = modes.IndexOf(nextMode); 102 | 103 | switch (nextMode) 104 | { 105 | case Mode.Audio: 106 | turnOn = Entity.AudioEnabled; 107 | break; 108 | case Mode.Game: 109 | turnOn = Entity.SteamEnabled; 110 | break; 111 | case Mode.Git: 112 | turnOn = true; 113 | break; 114 | } 115 | } 116 | 117 | return nextMode; 118 | } 119 | 120 | #endregion 121 | } 122 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/HotkeyViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using Caliburn.Micro; 4 | using GitLurker.Core.Models; 5 | using GitLurker.UI.Services; 6 | using MahApps.Metro.IconPacks; 7 | using Winook; 8 | 9 | public class HotkeyViewModel : PropertyChangedBase 10 | { 11 | #region Fields 12 | 13 | private string _name; 14 | private Hotkey _hotkey; 15 | private System.Action _save; 16 | 17 | #endregion 18 | 19 | #region Constructors 20 | 21 | public HotkeyViewModel(Hotkey hotkey, System.Action callback, string name) 22 | { 23 | _name = name; 24 | _hotkey = hotkey; 25 | _save = callback; 26 | 27 | if (hotkey != null) 28 | { 29 | HandleIcon(hotkey.KeyCode); 30 | } 31 | } 32 | 33 | public HotkeyViewModel(Hotkey hotkey, System.Action callback) 34 | : this(hotkey, callback, "Open") 35 | { 36 | } 37 | 38 | #endregion 39 | 40 | #region Properties 41 | 42 | public bool NotDefined => !_hotkey.IsDefined(); 43 | 44 | public bool HasModifier => Modifier != Modifiers.None; 45 | 46 | public bool HasKeyCode => KeyCode != KeyCode.None && Icon == null; 47 | 48 | public bool HasIcon => Icon != null; 49 | 50 | public Modifiers Modifier 51 | { 52 | get => _hotkey.Modifier; 53 | private set 54 | { 55 | _hotkey.Modifier = value; 56 | NotifyOfPropertyChange(); 57 | NotifyOfPropertyChange(() => HasModifier); 58 | } 59 | } 60 | 61 | public KeyCode KeyCode 62 | { 63 | get => _hotkey.KeyCode; 64 | private set 65 | { 66 | _hotkey.KeyCode = value; 67 | NotifyOfPropertyChange(); 68 | NotifyOfPropertyChange(() => HasKeyCode); 69 | NotifyOfPropertyChange(() => NotDefined); 70 | } 71 | } 72 | 73 | public PackIconControlBase Icon 74 | { 75 | get => field; 76 | private set 77 | { 78 | field = value; 79 | NotifyOfPropertyChange(); 80 | NotifyOfPropertyChange(() => HasIcon); 81 | NotifyOfPropertyChange(() => HasKeyCode); 82 | } 83 | } 84 | 85 | public string NameValue => _name; 86 | 87 | #endregion 88 | 89 | #region Methods 90 | 91 | public async void SetKeyCode() 92 | { 93 | var dialog = IoC.Get(); 94 | 95 | var task = IoC.Get().GetNextKeyAsync(); 96 | await dialog.ShowProgressAsync("Waiting...", "Press any keys", task); 97 | var result = await task; 98 | 99 | if (result.Key == KeyCode.Escape) 100 | { 101 | return; 102 | } 103 | 104 | Modifier = result.Modifier; 105 | KeyCode = result.Key; 106 | 107 | HandleIcon(KeyCode); 108 | 109 | _save(result.Key, result.Modifier); 110 | } 111 | 112 | private void HandleIcon(KeyCode code) 113 | { 114 | Icon = null; 115 | var codeValue = code.ToString(); 116 | 117 | if (codeValue.ToLower().Contains("launchapplication")) 118 | { 119 | Icon = new PackIconBootstrapIcons() { Kind = PackIconBootstrapIconsKind.Calculator }; 120 | } 121 | } 122 | 123 | #endregion 124 | } 125 | -------------------------------------------------------------------------------- /src/GitLurker.UI/GitLurker.UI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net10.0-windows7.0 6 | true 7 | Resources\GitLurker.ico 8 | 1.3.0 9 | app.manifest 10 | GitLurker 11 | AnyCPU;x64;x86 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | Code 66 | 67 | 68 | Code 69 | 70 | 71 | Code 72 | 73 | 74 | Code 75 | 76 | 77 | 78 | 79 | 80 | Always 81 | 82 | 83 | Always 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Models/Workspace.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Models; 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | using GitLurker.Core.Services; 9 | 10 | public class Workspace : ProcessService 11 | { 12 | #region Fields 13 | 14 | private string _folder; 15 | private List _repositories; 16 | 17 | #endregion 18 | 19 | #region Constructors 20 | 21 | public Workspace(string folderPath) 22 | : base(folderPath) 23 | { 24 | _folder = folderPath; 25 | _repositories = []; 26 | var options = new EnumerationOptions() 27 | { 28 | IgnoreInaccessible = true, 29 | AttributesToSkip = FileAttributes.ReparsePoint, 30 | RecurseSubdirectories = true, 31 | MaxRecursionDepth = 2, 32 | }; 33 | 34 | foreach (var folder in Directory.GetDirectories(_folder, ".git", options)) 35 | { 36 | var parentFolderInformation = Directory.GetParent(folder); 37 | var path = parentFolderInformation.ToString(); 38 | 39 | var parentRepo = _repositories.FirstOrDefault(r => folder.StartsWith(r.Folder)); 40 | if (parentRepo != null) 41 | { 42 | var directoryName = Path.GetFileName(Path.GetDirectoryName(folder)); 43 | var parentDirectoryName = Path.GetFileName(parentRepo.Folder); 44 | if (!directoryName.StartsWith(parentDirectoryName)) 45 | { 46 | continue; 47 | } 48 | } 49 | 50 | // Check if the folder is a git repository. 51 | if (Repository.IsValid(path)) 52 | { 53 | _repositories.Add(new Repository(path, _repositories)); 54 | } 55 | } 56 | } 57 | 58 | #endregion 59 | 60 | #region Properties 61 | 62 | public string Folder => _folder; 63 | 64 | public IEnumerable Repositories => _repositories; 65 | 66 | #endregion 67 | 68 | #region Methods 69 | 70 | public IEnumerable Search(string term) 71 | { 72 | var startWith = Repositories.Where(r => r.Name.ToUpper().StartsWith(term.ToUpper(), StringComparison.InvariantCulture)); 73 | var contain = Repositories.Where(r => r.Name.ToUpper().Contains(term.ToUpper(), StringComparison.InvariantCulture)).ToList(); 74 | contain.InsertRange(0, startWith); 75 | return contain.Distinct(); 76 | } 77 | 78 | public Repository GetRepo(string folderPath) => _repositories.FirstOrDefault(r => r.Folder == folderPath); 79 | 80 | public async Task CloneAsync(string url) 81 | { 82 | await ExecuteCommandAsync($"git clone {url}", true); 83 | var lastSegment = url.Split("/").LastOrDefault(); 84 | 85 | if (string.IsNullOrEmpty(lastSegment)) 86 | { 87 | return null; 88 | } 89 | 90 | var folderName = lastSegment.Replace(".git", string.Empty); 91 | var folderPath = Path.Combine(_folder, folderName); 92 | 93 | if (!Directory.Exists(folderPath)) 94 | { 95 | return null; 96 | } 97 | 98 | return new Repository(folderPath, _repositories); 99 | } 100 | 101 | public void AddRepo(Repository repo) 102 | { 103 | _repositories.Add(repo); 104 | repo.AddToRecent(); 105 | } 106 | 107 | #endregion 108 | } 109 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/CustomActionTileView.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | 18 | 29 | 30 | 31 | 32 | 35 | 36 | 40 | 41 | 42 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/ConsoleViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System; 4 | using System.Collections.ObjectModel; 5 | using Caliburn.Micro; 6 | using GitLurker.Core.Models; 7 | using GitLurker.Core.Services; 8 | using GitLurker.UI.Models; 9 | using GitLurker.UI.Services; 10 | 11 | public class ConsoleViewModel : PropertyChangedBase, IDisposable 12 | { 13 | #region Fields 14 | 15 | private ProcessService _processService; 16 | private ConsoleService _consoleService; 17 | 18 | #endregion 19 | 20 | #region Constructors 21 | 22 | public ConsoleViewModel(ConsoleService service) 23 | { 24 | Lines = new ObservableCollection(); 25 | _consoleService = service; 26 | _consoleService.ExecutionRequested += ConsoleService_ExecutionRequested; 27 | } 28 | 29 | #endregion 30 | 31 | #region Events 32 | 33 | public event EventHandler OnExecute; 34 | 35 | #endregion 36 | 37 | #region Properties 38 | 39 | public ObservableCollection Lines { get; set; } 40 | 41 | public int ExitCode 42 | { 43 | get => field; 44 | set 45 | { 46 | field = value; 47 | NotifyOfPropertyChange(); 48 | } 49 | } 50 | 51 | public bool IsLoading 52 | { 53 | get => field; 54 | set 55 | { 56 | field = value; 57 | NotifyOfPropertyChange(); 58 | } 59 | } 60 | 61 | #endregion 62 | 63 | #region Methods 64 | 65 | public void Dispose() 66 | { 67 | Dispose(true); 68 | GC.SuppressFinalize(this); 69 | } 70 | 71 | protected virtual void Dispose(bool disposing) 72 | { 73 | if (disposing) 74 | { 75 | _consoleService.ExecutionRequested -= ConsoleService_ExecutionRequested; 76 | } 77 | } 78 | 79 | private static bool IsLineInError(string line) 80 | { 81 | if (line.StartsWith("conflict", StringComparison.InvariantCultureIgnoreCase)) 82 | { 83 | return true; 84 | } 85 | 86 | if (line.EndsWith("needs merge", StringComparison.InvariantCultureIgnoreCase)) 87 | { 88 | return true; 89 | } 90 | 91 | return false; 92 | } 93 | 94 | private void Repository_NewExitCode(object sender, int code) 95 | { 96 | IsLoading = false; 97 | OnExecute?.Invoke(this, false); 98 | } 99 | 100 | private void Repository_NewProcessMessage(object sender, CLIEvent e) 101 | { 102 | if (string.IsNullOrEmpty(e.Text)) 103 | { 104 | return; 105 | } 106 | 107 | var consoleLine = new ConsoleLine 108 | { 109 | Line = e.Text, 110 | IsError = e.IsError, 111 | }; 112 | 113 | if (IsLineInError(e.Text)) 114 | { 115 | consoleLine.IsError = true; 116 | } 117 | 118 | Execute.OnUIThread(() => Lines.Add(consoleLine)); 119 | } 120 | 121 | private void ConsoleService_ExecutionRequested(object sender, ProcessService process) 122 | { 123 | if (process == null) 124 | { 125 | return; 126 | } 127 | 128 | if (_processService != null) 129 | { 130 | Execute.OnUIThread(() => 131 | { 132 | Lines.Clear(); 133 | }); 134 | _processService.NewProcessMessage -= Repository_NewProcessMessage; 135 | } 136 | 137 | IsLoading = true; 138 | OnExecute?.Invoke(this, true); 139 | _processService = process; 140 | _processService.NewProcessMessage += Repository_NewProcessMessage; 141 | _processService.NewExitCode += Repository_NewExitCode; 142 | } 143 | 144 | #endregion 145 | } 146 | -------------------------------------------------------------------------------- /src/GitLurker.UI/App.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | #1565C0 20 | 21 | 22 | 23 | 45 | 46 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/GitLurker.UI/Views/GameView.xaml: -------------------------------------------------------------------------------- 1 | 11 | 14 | 15 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 37 | 44 | 45 | 53 | 61 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Extensions; 2 | 3 | using System; 4 | using System.Linq; 5 | 6 | public static class StringExtension 7 | { 8 | private static readonly string[] LineSeparators = ["\r\n", "\r", "\n"]; 9 | private static char WildCard = '*'; 10 | 11 | /// 12 | /// Splits the specified split value. 13 | /// 14 | /// The value. 15 | /// The split value. 16 | /// Split the current string using another string 17 | public static string[] Split(this string value, string splitValue) 18 | { 19 | return value.Split(new string[] { splitValue }, StringSplitOptions.RemoveEmptyEntries); 20 | } 21 | 22 | /// 23 | /// Gets the lines. 24 | /// 25 | /// The value. 26 | /// The lines. 27 | public static string[] GetLines(this string value) 28 | { 29 | return value.Split(LineSeparators, StringSplitOptions.None); 30 | } 31 | 32 | /// 33 | /// Gets the line after. 34 | /// 35 | /// The value. 36 | /// The marker. 37 | /// The line. 38 | public static string GetLineAfter(this string value, string marker) 39 | { 40 | var index = value.IndexOf(marker); 41 | if (index == -1) 42 | { 43 | return null; 44 | } 45 | 46 | var textAfter = value.Substring(index + marker.Length); 47 | return textAfter.Split("\n").First().Trim(); 48 | } 49 | 50 | /// 51 | /// Gets the line before. 52 | /// 53 | /// The value. 54 | /// The marker. 55 | /// The line 56 | public static string GetLineBefore(this string value, string marker) 57 | { 58 | var index = value.IndexOf(marker); 59 | if (index == -1) 60 | { 61 | return null; 62 | } 63 | 64 | var textBefore = value.Substring(0, index); 65 | return textBefore.Split(System.Environment.NewLine).Last().Trim(); 66 | } 67 | 68 | /// 69 | /// Gets the line. 70 | /// 71 | /// The value. 72 | /// The marker. 73 | /// The full line of the marker 74 | public static string GetLine(this string value, string marker) 75 | { 76 | var index = value.IndexOf(marker); 77 | if (index == -1) 78 | { 79 | return null; 80 | } 81 | 82 | var textBefore = value.Substring(0, index + marker.Length); 83 | return textBefore.Split(LineSeparators, StringSplitOptions.None).Last().Trim(); 84 | } 85 | 86 | /// 87 | /// Matches the specified criteria. 88 | /// 89 | /// The value. 90 | /// The criteria. 91 | /// If match 92 | public static bool Match(this string value, string criteria) 93 | { 94 | if (string.IsNullOrEmpty(criteria)) 95 | { 96 | return false; 97 | } 98 | 99 | var results = criteria.Split(WildCard); 100 | var firstResult = results.First(); 101 | if (!string.IsNullOrEmpty(firstResult)) 102 | { 103 | if (results.Length == 1) 104 | { 105 | return value == firstResult; 106 | } 107 | 108 | if (!value.StartsWith(firstResult)) 109 | { 110 | return false; 111 | } 112 | } 113 | 114 | var index = value.IndexOf(firstResult); 115 | value = value.Substring(index + firstResult.Length); 116 | 117 | results = results.Skip(1).ToArray(); 118 | 119 | foreach (var result in results) 120 | { 121 | var resultIndex = value.IndexOf(result); 122 | if (resultIndex == -1) 123 | { 124 | return false; 125 | } 126 | 127 | value = value.Substring(resultIndex + result.Length); 128 | } 129 | 130 | return true; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/ActionBarViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System; 4 | using System.Collections.ObjectModel; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using Caliburn.Micro; 8 | using GitLurker.Core.Models; 9 | using GitLurker.UI.Services; 10 | using MahApps.Metro.IconPacks; 11 | 12 | public class ActionBarViewModel : PropertyChangedBase 13 | { 14 | #region Fields 15 | 16 | private Repository _repo; 17 | private ConsoleService _consoleService; 18 | private CustomActionSettingsFile _actionsFile; 19 | 20 | #endregion 21 | 22 | #region Constructors 23 | 24 | public ActionBarViewModel(Repository repo) 25 | { 26 | _repo = repo; 27 | _actionsFile = IoC.Get(); 28 | _consoleService = IoC.Get(); 29 | 30 | SetActions(); 31 | } 32 | 33 | #endregion 34 | 35 | #region Properties 36 | 37 | public ObservableCollection Actions { get; set; } 38 | 39 | public bool Busy 40 | { 41 | get => field; 42 | 43 | set 44 | { 45 | field = value; 46 | NotifyOfPropertyChange(); 47 | NotifyOfPropertyChange(() => NotBusy); 48 | } 49 | } 50 | 51 | public bool NotBusy => !Busy; 52 | 53 | #endregion 54 | 55 | #region Methods 56 | 57 | public void RemoveActions() 58 | { 59 | Execute.OnUIThread(() => 60 | { 61 | var notPermanentActions = Actions.Where(a => !a.Permanent).ToArray(); 62 | foreach (var action in notPermanentActions) 63 | { 64 | Actions.Remove(action); 65 | } 66 | }); 67 | } 68 | 69 | public void AddAction(Func> task, PackIconControlBase icon) 70 | => AddAction(task, null, icon, openConsole: false, permanent: true); 71 | 72 | public void AddAction(Func> task, PackIconControlBase icon, bool openConsole) 73 | => AddAction(task, null, icon, openConsole, permanent: true); 74 | 75 | public void AddAction(Func> task, Func> holdTask, PackIconControlBase icon, bool openConsole, bool permanent) 76 | { 77 | // Block the ability to insert the same action 78 | var existingAction = Actions.FirstOrDefault(a => a.Icon.Data == icon.Data); 79 | if (existingAction != null) 80 | { 81 | return; 82 | } 83 | 84 | var id = Guid.NewGuid(); 85 | async Task execute(Func> t) 86 | { 87 | if (Busy) 88 | { 89 | return; 90 | } 91 | 92 | SetDisable(true, id); 93 | _consoleService.Listen(_repo); 94 | 95 | if (openConsole) 96 | { 97 | _consoleService.Show(); 98 | } 99 | 100 | var result = await t(); 101 | 102 | _repo.AddToRecent(); 103 | SetDisable(false, id); 104 | } 105 | 106 | Actions.Insert(0, new ActionViewModel(() => execute(task), holdTask == null ? null : () => execute(holdTask), icon, permanent, id)); 107 | } 108 | 109 | private void SetActions() 110 | { 111 | Actions = []; 112 | Execute.OnUIThread(() => AddAction(_repo.PullAsync, new PackIconMaterial() { Kind = PackIconMaterialKind.ChevronDown })); 113 | 114 | foreach (var action in _actionsFile.GetActions(_repo.Folder)) 115 | { 116 | if (Enum.TryParse(action.Icon, out var kind)) 117 | { 118 | var icon = new PackIconMaterial() { Kind = kind }; 119 | AddAction(() => _repo.ExecuteCommandAsync(action.Command, true), icon, action.OpenConsole); 120 | } 121 | } 122 | 123 | if (_repo.HasFrontEnd) 124 | { 125 | var icon = new PackIconSimpleIcons 126 | { 127 | Kind = PackIconSimpleIconsKind.VisualStudioCode, 128 | }; 129 | 130 | AddAction(_repo.OpenFrontEnd, icon); 131 | } 132 | } 133 | 134 | public void SetDisable(bool value, Guid actionId) 135 | { 136 | foreach (var action in Actions) 137 | { 138 | if (action.Id == actionId) 139 | { 140 | continue; 141 | } 142 | 143 | action.IsDisable = value; 144 | } 145 | 146 | var activeAction = Actions.FirstOrDefault(a => a.Id == actionId); 147 | if (activeAction != null) 148 | { 149 | activeAction.IsActive = value; 150 | } 151 | } 152 | 153 | #endregion 154 | } 155 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/CommitActionViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System.Collections.ObjectModel; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using Caliburn.Micro; 8 | using GitLurker.Core.Models; 9 | using GitLurker.UI.Services; 10 | 11 | internal class CommitActionViewModel : PropertyChangedBase, IItemListViewModel 12 | { 13 | private Repository _repository; 14 | private ObservableCollection _fileViewModels; 15 | private bool _mouseOver; 16 | private string _message; 17 | private string _selecteFiledId; 18 | 19 | public CommitActionViewModel(Repository repo) 20 | { 21 | _repository = repo; 22 | _fileViewModels = []; 23 | } 24 | 25 | public FileViewModel SelectedFileViewModel 26 | { 27 | get => field; 28 | private set 29 | { 30 | field = value; 31 | NotifyOfPropertyChange(() => HasSelectedFile); 32 | } 33 | } 34 | 35 | public bool HasSelectedFile => SelectedFileViewModel != null || _mouseOver; 36 | 37 | public ObservableCollection FileViewModels => _fileViewModels; 38 | 39 | public void OnMouseEnter() 40 | { 41 | _mouseOver = true; 42 | NotifyOfPropertyChange(() => HasSelectedFile); 43 | } 44 | 45 | public void OnMouseLeave() 46 | { 47 | _mouseOver = false; 48 | NotifyOfPropertyChange(() => HasSelectedFile); 49 | } 50 | 51 | public async Task Open(bool skipModifier) 52 | { 53 | if (SelectedFileViewModel != null) 54 | { 55 | SelectedFileViewModel.Open(); 56 | SelectedFileViewModel = null; 57 | 58 | return true; 59 | } 60 | 61 | if (!string.IsNullOrEmpty(_message)) 62 | { 63 | IoC.Get().Listen(_repository); 64 | await _repository.SyncAsync(_message); 65 | } 66 | 67 | return false; 68 | } 69 | 70 | public void Search(string term) 71 | { 72 | if (SelectedFileViewModel != null) 73 | { 74 | SelectedFileViewModel.IsSelected = false; 75 | SelectedFileViewModel = null; 76 | _selecteFiledId = null; 77 | } 78 | 79 | _message = term; 80 | } 81 | 82 | public void Clear() 83 | { 84 | Execute.OnUIThread(() => _fileViewModels.Clear()); 85 | } 86 | 87 | public bool Close() 88 | { 89 | return true; 90 | } 91 | 92 | public void EnterLongPressed() 93 | { 94 | } 95 | 96 | public void MoveDown() 97 | { 98 | if (SelectedFileViewModel == null) 99 | { 100 | SelectedFileViewModel = _fileViewModels.FirstOrDefault(); 101 | if (SelectedFileViewModel != null) 102 | { 103 | _selecteFiledId = SelectedFileViewModel.Select(); 104 | } 105 | 106 | return; 107 | } 108 | 109 | SelectedFileViewModel = _fileViewModels.FirstOrDefault(g => g.Id == SelectedFileViewModel.Id); 110 | 111 | var index = _fileViewModels.IndexOf(SelectedFileViewModel); 112 | if (index == -1 || (index + 1) >= _fileViewModels.Count) 113 | { 114 | return; 115 | } 116 | 117 | index++; 118 | SelectedFileViewModel.IsSelected = false; 119 | SelectedFileViewModel = _fileViewModels.ElementAt(index); 120 | _selecteFiledId = SelectedFileViewModel.Select(); 121 | } 122 | 123 | public void MoveUp() 124 | { 125 | if (SelectedFileViewModel == null) 126 | { 127 | return; 128 | } 129 | 130 | SelectedFileViewModel = _fileViewModels.FirstOrDefault(g => g.Id == SelectedFileViewModel.Id); 131 | var index = _fileViewModels.IndexOf(SelectedFileViewModel); 132 | if (index <= 0) 133 | { 134 | return; 135 | } 136 | 137 | index--; 138 | SelectedFileViewModel.IsSelected = false; 139 | SelectedFileViewModel = _fileViewModels.ElementAt(index); 140 | _selecteFiledId = SelectedFileViewModel.Select(); 141 | } 142 | 143 | public void NextTabPressed() 144 | { 145 | } 146 | 147 | public Task RefreshItems() 148 | { 149 | return Task.CompletedTask; 150 | } 151 | 152 | public void ShowRecent() 153 | { 154 | foreach (var file in _repository.GetFilesChanged().OrderBy(f => Path.GetFileName(f.FilePath))) 155 | { 156 | var viewModel = new FileViewModel(file, _repository); 157 | if (_selecteFiledId == file.FilePath) 158 | { 159 | viewModel.IsSelected = true; 160 | SelectedFileViewModel = viewModel; 161 | } 162 | 163 | _fileViewModels.Add(viewModel); 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/GitLurker.Core/Services/ProcessService.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.Core.Services; 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.IO; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using CliWrap.EventStream; 10 | using GitLurker.Core.Models; 11 | 12 | public class ProcessService 13 | { 14 | #region Fields 15 | 16 | private string _folder; 17 | 18 | #endregion 19 | 20 | #region Constructors 21 | 22 | public ProcessService(string folder) 23 | { 24 | _folder = folder; 25 | } 26 | 27 | #endregion 28 | 29 | #region Events 30 | 31 | public event EventHandler NewProcessMessage; 32 | 33 | public event EventHandler NewExitCode; 34 | 35 | #endregion 36 | 37 | #region Methods 38 | 39 | public Task ExecuteCommandAsync(string arguments) => ExecuteCommandAsync(arguments, false, _folder, CancellationToken.None); 40 | 41 | public Task ExecuteCommandAsync(string arguments, bool listen) => ExecuteCommandAsync(arguments, listen, _folder, CancellationToken.None); 42 | 43 | public Task ExecuteCommandAsync(string arguments, bool listen, string workingDirectory, CancellationToken token) 44 | { 45 | if (!string.IsNullOrEmpty(_folder) && !Directory.Exists(_folder)) 46 | { 47 | if (listen) 48 | { 49 | NewExitCode?.Invoke(this, -1); 50 | } 51 | 52 | return Task.FromResult(new ExecutionResult()); 53 | } 54 | 55 | var taskCompletionSource = new TaskCompletionSource(); 56 | var data = new List(); 57 | 58 | var command = CliWrap.Cli 59 | .Wrap("cmd.exe") 60 | .WithWorkingDirectory(workingDirectory) 61 | .WithArguments($"/C {arguments}"); 62 | 63 | 64 | _ = Task.Run(async () => 65 | { 66 | try 67 | { 68 | await foreach (var cmdEvent in command.ListenAsync(token)) 69 | { 70 | switch (cmdEvent) 71 | { 72 | case StandardErrorCommandEvent error: 73 | HandleProcessMessage(error.Text, false, data, listen); 74 | break; 75 | case StandardOutputCommandEvent standard: 76 | HandleProcessMessage(standard.Text, false, data, listen); 77 | break; 78 | case ExitedCommandEvent exit: 79 | if (listen) 80 | { 81 | NewExitCode?.Invoke(this, exit.ExitCode); 82 | } 83 | 84 | taskCompletionSource.SetResult(new ExecutionResult() 85 | { 86 | Output = data, 87 | ExitCode = exit.ExitCode, 88 | }); 89 | return; 90 | } 91 | } 92 | } 93 | catch (Exception) 94 | { 95 | if (listen) 96 | { 97 | NewExitCode?.Invoke(this, -1); 98 | } 99 | 100 | taskCompletionSource.SetResult(new ExecutionResult() 101 | { 102 | Output = data, 103 | ExitCode = -1, 104 | }); 105 | } 106 | }, token); 107 | 108 | 109 | return taskCompletionSource.Task; 110 | } 111 | 112 | protected void OpenFile(string filePath) 113 | { 114 | new Process() 115 | { 116 | StartInfo = new ProcessStartInfo(filePath) 117 | { 118 | UseShellExecute = true, 119 | } 120 | }.Start(); 121 | } 122 | 123 | protected FileInfo[] GetFiles(string extention, int maxRecursionDepth = 2) 124 | { 125 | if (!Directory.Exists(_folder)) 126 | { 127 | return []; 128 | } 129 | 130 | return new DirectoryInfo(_folder).GetFiles($"*{extention}", new EnumerationOptions() 131 | { 132 | IgnoreInaccessible = true, 133 | AttributesToSkip = FileAttributes.ReparsePoint, 134 | RecurseSubdirectories = true, 135 | MaxRecursionDepth = maxRecursionDepth, 136 | }); 137 | } 138 | 139 | protected void SetExitCode(int code) 140 | => NewExitCode?.Invoke(this, code); 141 | 142 | private void HandleProcessMessage(string text, bool isError, List data, bool listen) 143 | { 144 | data.Add(text); 145 | 146 | if (listen && text != null) 147 | { 148 | NewProcessMessage?.Invoke(this, new CLIEvent() 149 | { 150 | Text = text, 151 | IsError = isError, 152 | }); 153 | } 154 | } 155 | 156 | #endregion 157 | } 158 | -------------------------------------------------------------------------------- /src/GitLurker.UI/ViewModels/CustomActionViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace GitLurker.UI.ViewModels; 2 | 3 | using System; 4 | using System.Collections.ObjectModel; 5 | using System.Linq; 6 | using Caliburn.Micro; 7 | using GitLurker.Core.Models; 8 | using GitLurker.Core.Services; 9 | using GitLurker.UI.Services; 10 | using MahApps.Metro.IconPacks; 11 | 12 | public class CustomActionViewModel : PropertyChangedBase 13 | { 14 | #region Fields 15 | 16 | private static readonly PackIconMaterialKind[] IconKinds = Enum.GetValues(typeof(PackIconMaterialKind)).Cast().ToArray(); 17 | private CustomAction _action; 18 | private RepositoryService _repositoryService; 19 | private bool _isNew; 20 | 21 | #endregion 22 | 23 | #region Constructors 24 | 25 | public CustomActionViewModel(CustomAction action) 26 | : this(action, false) 27 | { 28 | 29 | } 30 | 31 | public CustomActionViewModel(CustomAction action, bool isNew) 32 | { 33 | _action = action; 34 | _isNew = isNew; 35 | _repositoryService = IoC.Get(); 36 | if (string.IsNullOrEmpty(action.Icon)) 37 | { 38 | SelectedIcon = PackIconMaterialKind.Cog; 39 | } 40 | else 41 | { 42 | SelectedIcon = Enum.Parse(action.Icon); 43 | } 44 | 45 | PropertyChanged += CustomActionViewModel_PropertyChanged; 46 | Icons = new ObservableCollection(IconKinds); 47 | 48 | var repos = _repositoryService.GetAllRepo().OrderBy(r => r.Name); 49 | Repositories = new ObservableCollection(repos); 50 | 51 | var selectedRepos = repos.Where(r => _action.Repositories.Contains(r.Folder)); 52 | SelectedRepositories = new ObservableCollection(selectedRepos); 53 | } 54 | 55 | #endregion 56 | 57 | #region Properties 58 | 59 | public ObservableCollection SelectedRepositories { get; set; } 60 | 61 | public ObservableCollection Icons { get; set; } 62 | 63 | public ObservableCollection Repositories { get; set; } 64 | 65 | public Repository SelectedRepository 66 | { 67 | get => field; 68 | set 69 | { 70 | field = value; 71 | AddRepository(value); 72 | NotifyOfPropertyChange(); 73 | } 74 | } 75 | 76 | public PackIconMaterialKind SelectedIcon 77 | { 78 | get => field; 79 | set 80 | { 81 | field = value; 82 | NotifyOfPropertyChange(); 83 | } 84 | } 85 | 86 | public string ActionName 87 | { 88 | get => _action.Name; 89 | set 90 | { 91 | _action.Name = value; 92 | NotifyOfPropertyChange(); 93 | } 94 | } 95 | 96 | public bool Modified 97 | { 98 | get => field; 99 | set 100 | { 101 | field = value; 102 | NotifyOfPropertyChange(); 103 | } 104 | } 105 | 106 | public string Command 107 | { 108 | get => _action.Command; 109 | set 110 | { 111 | _action.Command = value; 112 | NotifyOfPropertyChange(); 113 | } 114 | } 115 | 116 | public bool OpenConsole 117 | { 118 | get => _action.OpenConsole; 119 | set 120 | { 121 | _action.OpenConsole = value; 122 | NotifyOfPropertyChange(); 123 | } 124 | } 125 | 126 | public bool ExcludeRepositories 127 | { 128 | get => _action.ExcludeRepositories; 129 | set 130 | { 131 | _action.ExcludeRepositories = value; 132 | NotifyOfPropertyChange(); 133 | } 134 | } 135 | 136 | #endregion 137 | 138 | #region Methods 139 | 140 | public void Save() 141 | { 142 | Modified = false; 143 | 144 | _action.Icon = SelectedIcon.ToString(); 145 | var file = IoC.Get(); 146 | 147 | if (_isNew) 148 | { 149 | _isNew = false; 150 | file.AddAction(_action); 151 | } 152 | else 153 | { 154 | file.Save(); 155 | } 156 | 157 | IoC.Get().Close(); 158 | } 159 | 160 | public void ToggleExcludeRepositories() => ExcludeRepositories = !ExcludeRepositories; 161 | 162 | public void ToggleConsole() => OpenConsole = !OpenConsole; 163 | 164 | public void AddRepository(Repository repo) 165 | { 166 | if (_action.AddRepository(repo)) 167 | { 168 | SelectedRepositories.Add(repo); 169 | } 170 | } 171 | 172 | public void RemoveRepository(Repository repo) 173 | { 174 | if (_action.RemoveRepository(repo)) 175 | { 176 | Modified = true; 177 | SelectedRepositories.Remove(repo); 178 | } 179 | } 180 | 181 | private void CustomActionViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 182 | { 183 | if (e.PropertyName == nameof(Modified)) 184 | { 185 | return; 186 | } 187 | 188 | Modified = true; 189 | } 190 | 191 | #endregion 192 | } 193 | --------------------------------------------------------------------------------