diff --git a/Hurl.sln b/Hurl.sln index 7f08d63..6c07c9b 100644 --- a/Hurl.sln +++ b/Hurl.sln @@ -12,6 +12,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hurl.Library", "Source\Hurl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hurl.Settings", "Source\Hurl.Settings\Hurl.Settings.csproj", "{C4DB15A3-1D60-437C-BD29-688E9E280E87}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hurl.Timely", "Source\Hurl.Timely\Hurl.Timely.csproj", "{F3A1BB02-F009-439B-A805-01A57B7F2009}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -72,6 +74,30 @@ Global {C4DB15A3-1D60-437C-BD29-688E9E280E87}.Release|x64.Build.0 = Release|x64 {C4DB15A3-1D60-437C-BD29-688E9E280E87}.Release|x86.ActiveCfg = Release|x64 {C4DB15A3-1D60-437C-BD29-688E9E280E87}.Release|x86.Build.0 = Release|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|Any CPU.ActiveCfg = Debug|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|Any CPU.Build.0 = Debug|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|Any CPU.Deploy.0 = Debug|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|ARM64.Build.0 = Debug|ARM64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|x64.ActiveCfg = Debug|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|x64.Build.0 = Debug|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|x64.Deploy.0 = Debug|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|x86.ActiveCfg = Debug|x86 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|x86.Build.0 = Debug|x86 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Debug|x86.Deploy.0 = Debug|x86 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|Any CPU.ActiveCfg = Release|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|Any CPU.Build.0 = Release|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|Any CPU.Deploy.0 = Release|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|ARM64.ActiveCfg = Release|ARM64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|ARM64.Build.0 = Release|ARM64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|ARM64.Deploy.0 = Release|ARM64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|x64.ActiveCfg = Release|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|x64.Build.0 = Release|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|x64.Deploy.0 = Release|x64 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|x86.ActiveCfg = Release|x86 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|x86.Build.0 = Release|x86 + {F3A1BB02-F009-439B-A805-01A57B7F2009}.Release|x86.Deploy.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/Hurl.BrowserSelector/Controls/ToggleBrowserButton.xaml b/Source/Hurl.BrowserSelector/Controls/ToggleBrowserButton.xaml new file mode 100644 index 0000000..8ce0d2b --- /dev/null +++ b/Source/Hurl.BrowserSelector/Controls/ToggleBrowserButton.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + diff --git a/Source/Hurl.BrowserSelector/Controls/ToggleBrowserButton.xaml.cs b/Source/Hurl.BrowserSelector/Controls/ToggleBrowserButton.xaml.cs new file mode 100644 index 0000000..9d86d62 --- /dev/null +++ b/Source/Hurl.BrowserSelector/Controls/ToggleBrowserButton.xaml.cs @@ -0,0 +1,60 @@ +using Hurl.Library.Models; +using System.Collections.ObjectModel; +using System.Windows; +using System.Windows.Controls; + +namespace Hurl.BrowserSelector.Controls +{ + public partial class ToggleBrowserButton : UserControl + { + public ToggleBrowserButton() + { + InitializeComponent(); + // Example: Browsers should be set externally, e.g. via binding or code + } + + public static readonly DependencyProperty SelectedBrowserProperty = + DependencyProperty.Register( + nameof(SelectedBrowser), + typeof(Browser), + typeof(ToggleBrowserButton), + new PropertyMetadata(null)); + + public Browser SelectedBrowser + { + get => (Browser)GetValue(SelectedBrowserProperty); + set => SetValue(SelectedBrowserProperty, value); + } + + public static readonly RoutedEvent BrowserToggledEvent = + EventManager.RegisterRoutedEvent( + nameof(BrowserToggled), + RoutingStrategy.Bubble, + typeof(RoutedEventHandler), + typeof(ToggleBrowserButton)); + + public event RoutedEventHandler BrowserToggled + { + add => AddHandler(BrowserToggledEvent, value); + remove => RemoveHandler(BrowserToggledEvent, value); + } + + private void ToggleButton_Click(object sender, RoutedEventArgs e) + { + if (Resources["BrowserMenu"] is ContextMenu menu) + { + menu.PlacementTarget = sender as Button; + menu.IsOpen = true; + } + } + + private void BrowserMenuItem_Click(object sender, RoutedEventArgs e) + { + if (((MenuItem)sender).Tag is Browser browser) + { + SelectedBrowser = browser; + RaiseEvent(new RoutedEventArgs(BrowserToggledEvent)); + } + } + } +} diff --git a/Source/Hurl.BrowserSelector/Services/TimelyService.cs b/Source/Hurl.BrowserSelector/Services/TimelyService.cs new file mode 100644 index 0000000..2610123 --- /dev/null +++ b/Source/Hurl.BrowserSelector/Services/TimelyService.cs @@ -0,0 +1,69 @@ +using Hurl.Library; +using Hurl.Library.Models; +using System; +using System.Diagnostics; +using System.IO; + +namespace Hurl.BrowserSelector.Services; + +internal class TimelyService +{ + public static bool CheckAndLaunch(string url) + { + var Path_TempDef = Path.Combine(Constants.APP_SETTINGS_DIR, "TempDefault.json"); + if (File.Exists(Path_TempDef)) + { + var obj = JsonOperations.FromJsonToModel(Path_TempDef); + if (obj?.ValidTill >= DateTime.Now) + { + Process.Start(obj.TargetBrowser.ExePath, url); + Debug.WriteLine(obj.TargetBrowser.ExePath); + return true; + } + else + { + File.Delete(Path_TempDef); + } + } + return false; + } + + public static void Create(int mins, Browser browser) + { + var dataObject = new TemporaryDefaultBrowser() + { + TargetBrowser = browser, + SelectedAt = DateTime.Now, + ValidTill = DateTime.Now.AddMinutes(mins) + }; + + JsonOperations.FromModelToJson(dataObject, Path.Combine(Constants.APP_SETTINGS_DIR, "TempDefault.json")); + } + + public static TemporaryDefaultBrowser? Get() + { + var Path_TempDef = Path.Combine(Constants.APP_SETTINGS_DIR, "TempDefault.json"); + if (File.Exists(Path_TempDef)) + { + var obj = JsonOperations.FromJsonToModel(Path_TempDef); + if (obj?.ValidTill >= DateTime.Now) + { + return obj; + } + else + { + File.Delete(Path_TempDef); + } + } + return null; + } + + internal static void DeleteCurrent() + { + var Path_TempDef = Path.Combine(Constants.APP_SETTINGS_DIR, "TempDefault.json"); + if (File.Exists(Path_TempDef)) + { + File.Delete(Path_TempDef); + } + } +} diff --git a/Source/Hurl.Timely/App.xaml b/Source/Hurl.Timely/App.xaml new file mode 100644 index 0000000..2a91688 --- /dev/null +++ b/Source/Hurl.Timely/App.xaml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/Source/Hurl.Timely/App.xaml.cs b/Source/Hurl.Timely/App.xaml.cs new file mode 100644 index 0000000..0040a1d --- /dev/null +++ b/Source/Hurl.Timely/App.xaml.cs @@ -0,0 +1,50 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Navigation; +using Microsoft.UI.Xaml.Shapes; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.ApplicationModel; +using Windows.ApplicationModel.Activation; +using Windows.Foundation; +using Windows.Foundation.Collections; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace Hurl.Timely +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + public partial class App : Application + { + private Window? _window; + + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + InitializeComponent(); + } + + /// + /// Invoked when the application is launched. + /// + /// Details about the launch request and process. + protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) + { + _window = new MainWindow(); + _window.Activate(); + } + } +} diff --git a/Source/Hurl.Timely/Hurl.Timely.csproj b/Source/Hurl.Timely/Hurl.Timely.csproj new file mode 100644 index 0000000..7545658 --- /dev/null +++ b/Source/Hurl.Timely/Hurl.Timely.csproj @@ -0,0 +1,69 @@ + + + Hurl Timely + Hurl Timely + 0.10.0 + 0.10.0.27 + Copyright (c) 2025 Chanakya + Hurl + Chanakya + U-C-S + Hurl.Timely + WinExe + net9.0-windows10.0.26100.0 + 10.0.17763.0 + Hurl.Timely + app.manifest + x86;x64;ARM64 + win-x86;win-x64;win-arm64 + win-$(Platform).pubxml + true + enable + true + 10.0.26100.56 + 10.0.19041.0 + 10.0.19041.0 + + + + + + + + + + + + + + + + + False + + + + DISABLE_XAML_GENERATED_MAIN + + + + + true + + + + + False + True + False + True + + \ No newline at end of file diff --git a/Source/Hurl.Timely/MainWindow.xaml b/Source/Hurl.Timely/MainWindow.xaml new file mode 100644 index 0000000..e560d45 --- /dev/null +++ b/Source/Hurl.Timely/MainWindow.xaml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + For a period of time + Till a specific time + Until I turn it off + + + + + + + + + + + + + + + Choose the browser + + For a period of time + Till a specific time + Until I turn it off + + + + + + + An existing timed default browser is already running + + + + + diff --git a/Source/Hurl.Timely/MainWindow.xaml.cs b/Source/Hurl.Timely/MainWindow.xaml.cs new file mode 100644 index 0000000..b05fbf7 --- /dev/null +++ b/Source/Hurl.Timely/MainWindow.xaml.cs @@ -0,0 +1,24 @@ +using Microsoft.UI.Xaml; +using System; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace Hurl.Timely +{ + /// + /// An empty window that can be used on its own or navigated to within a Frame. + /// + public sealed partial class MainWindow : Window + { + public MainWindow() + { + this.ExtendsContentIntoTitleBar = true; + + //window.AppWindow.IsShownInSwitchers = false; + this.AppWindow.ResizeClient(new Windows.Graphics.SizeInt32(600, 320)); + + this.InitializeComponent(); + } + } +} diff --git a/Source/Hurl.Timely/Program.cs b/Source/Hurl.Timely/Program.cs new file mode 100644 index 0000000..f5fb7d2 --- /dev/null +++ b/Source/Hurl.Timely/Program.cs @@ -0,0 +1,60 @@ +using Microsoft.Windows.ApplicationModel.DynamicDependency; +using System; + +namespace Hurl.Timely; + +public class Program +{ + [global::System.Runtime.InteropServices.DllImport("Microsoft.ui.xaml.dll")] + [global::System.Runtime.InteropServices.DefaultDllImportSearchPaths(global::System.Runtime.InteropServices.DllImportSearchPath.SafeDirectories)] + private static extern void XamlCheckProcessRequirements(); + + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.UI.Xaml.Markup.Compiler", " 3.0.0.2408")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.STAThreadAttribute] + static void Main(string[] args) + { + InitializeWASDK(); + XamlCheckProcessRequirements(); + + global::WinRT.ComWrappersSupport.InitializeComWrappers(); + global::Microsoft.UI.Xaml.Application.Start((p) => + { + var context = new global::Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext(global::Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread()); + global::System.Threading.SynchronizationContext.SetSynchronizationContext(context); + new App(); + }); + } + + public static bool InitializeWASDK() + { + uint minSupportedMinorVersion = global::Microsoft.WindowsAppSDK.Release.MajorMinor; // 0x00010005 + uint maxSupportedMinorVersion = 0x00010007; + for (uint version = minSupportedMinorVersion; version <= maxSupportedMinorVersion; version++) + { + if (global::Microsoft.Windows.ApplicationModel.DynamicDependency.Bootstrap.TryInitialize(version, out _)) + return true; + } + + // Failure in trying to initialize supported versions. + // Try one last time in the WINDOWSAPPSDK_BOOTSTRAP_AUTO_INITIALIZE way + // that None property does. + try + { + string versionTag = global::Microsoft.WindowsAppSDK.Release.VersionTag; + var minVersion = new PackageVersion(global::Microsoft.WindowsAppSDK.Runtime.Version.UInt64); + var options = global::Microsoft.Windows.ApplicationModel.DynamicDependency.Bootstrap.InitializeOptions.OnNoMatch_ShowUI; + int hr = 0; + if (!global::Microsoft.Windows.ApplicationModel.DynamicDependency.Bootstrap.TryInitialize(minSupportedMinorVersion, versionTag, minVersion, options, out hr)) + { + Environment.Exit(hr); + } + } + catch (Exception ex) + { + throw new Exception("Error in initializing the default version of Windows App Runtime", ex); + } + + return false; + } +} diff --git a/Source/Hurl.Timely/Properties/launchSettings.json b/Source/Hurl.Timely/Properties/launchSettings.json new file mode 100644 index 0000000..c22dce1 --- /dev/null +++ b/Source/Hurl.Timely/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "Hurl.Timely (Package)": { + "commandName": "MsixPackage" + }, + "Hurl.Timely (Unpackaged)": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/Source/Hurl.Timely/app.manifest b/Source/Hurl.Timely/app.manifest new file mode 100644 index 0000000..0f101d5 --- /dev/null +++ b/Source/Hurl.Timely/app.manifest @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + PerMonitorV2 + + + \ No newline at end of file