diff --git a/App.config b/App.config index a362e17..4071362 100644 --- a/App.config +++ b/App.config @@ -23,11 +23,11 @@ - + - + @@ -35,7 +35,7 @@ - + @@ -49,6 +49,14 @@ + + + + + + + + diff --git a/FrmMainApp.cs b/FrmMainApp.cs index aea4a50..b66169e 100644 --- a/FrmMainApp.cs +++ b/FrmMainApp.cs @@ -12,6 +12,7 @@ using System.Text.Json; using System.Threading.Tasks; using System.Windows.Forms; +using AutoUpdaterDotNET; using geoTagNinja; using GeoTagNinja.Helpers; using GeoTagNinja.Model; @@ -342,10 +343,31 @@ private async void FrmMainApp_Load(object sender, Request_Map_NavigateGo(); await HelperAPIVersionCheckers.CheckForNewVersions(); + LaunchAutoUpdater(); Logger.Info(message: "OnLoad: Done."); } + /// + /// This fires up the autoupdater + /// + private static void LaunchAutoUpdater() + { + HelperNonStatic updateHelper = new(); + // AutoUpdater.InstalledVersion = new Version(version: "1.2"); // here for testing only. + + AutoUpdater.Synchronous = + true; // needs to be true otherwise the single pipe instance crashes. (well, I think _that_ crashes, something does.) + AutoUpdater.ParseUpdateInfoEvent += + updateHelper.AutoUpdaterOnParseUpdateInfoEvent; + AutoUpdater.CheckForUpdateEvent += updateHelper.AutoUpdaterOnCheckForUpdateEvent; + + string updateJsonPath = + Path.Combine(path1: HelperVariables.UserDataFolderPath, + path2: "updateJsonData.json"); + AutoUpdater.Start(appCast: Path.Combine(updateJsonPath)); + } + /// /// When the app closes we want to make sure there's nothing in the write-queue. @@ -751,16 +773,15 @@ void ShowLocToMapDialog() // via https://stackoverflow.com/a/17385937/3968494 List getLocToMapDialogChoice = - DialogWithCheckBox.DisplayAndReturnList( + DialogWithOrWithoutCheckBox.DisplayAndReturnList( labelText: HelperDataLanguageTZ.DataReadDTObjectText( objectType: ControlType.Label, objectName: "lbl_QuestionAddToponomy" ), caption: GenericGetMessageBoxCaption( captionType: MessageBoxCaption.Question.ToString()), - checkboxesDictionary: checkboxDictionary, buttonsDictionary: buttonsDictionary, - orientation: "Horizontal"); + orientation: "Horizontal", checkboxesDictionary: checkboxDictionary); _showLocToMapDialogChoice = getLocToMapDialogChoice.Contains(item: "yes"); _rememberLocToMapDialogChoice = @@ -1462,7 +1483,6 @@ private async Task InitialiseWebView() #endregion - #region File /// @@ -1568,7 +1588,6 @@ private void tmi_File_Quit_Click(object sender, #endregion - #region FrmMainApp's TaskBar Stuff /// @@ -2238,14 +2257,14 @@ private void lvw_FileList_UpdateTagsFromWeb(string strGpsLatitude, // ReSharper disable once InconsistentNaming List APIHandlingChoice = - DialogWithCheckBox.DisplayAndReturnList( + DialogWithOrWithoutCheckBox.DisplayAndReturnList( labelText: GenericGetMessageBoxText( messageBoxName: "mbx_FrmMainApp_QuestionNoRowsFromAPI"), caption: GenericGetMessageBoxCaption( captionType: MessageBoxCaption.Question.ToString()), - checkboxesDictionary: checkboxDictionary, buttonsDictionary: buttonsDictionary, - orientation: "Horizontal"); + orientation: "Horizontal", + checkboxesDictionary: checkboxDictionary); if (APIHandlingChoice.Contains(value: "yes")) { diff --git a/FrmSettings.cs b/FrmSettings.cs index 8bf0c34..9a0ab76 100644 --- a/FrmSettings.cs +++ b/FrmSettings.cs @@ -1126,8 +1126,7 @@ private void dgv_CustomRules_RowValidating(object sender, "mbx_FrmSettings_dgv_CustomRules_CustomOutcomeCannotBeEmpty"), caption: HelperControlAndMessageBoxHandling .GenericGetMessageBoxCaption( - captionType: HelperControlAndMessageBoxHandling - .MessageBoxCaption.Information.ToString()), + captionType: HelperControlAndMessageBoxHandling.MessageBoxCaption.Information.ToString()), buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning); customMessageBox.ShowDialog(); @@ -1187,15 +1186,15 @@ private void btn_ExportSettings_Click(object sender, Dictionary buttonsDictionary = GetButtonsDictionary(); // ReSharper disable once InconsistentNaming - List ItemsToExport = DialogWithCheckBox.DisplayAndReturnList( + List ItemsToExport = DialogWithOrWithoutCheckBox.DisplayAndReturnList( labelText: HelperControlAndMessageBoxHandling.GenericGetMessageBoxText( messageBoxName: "mbx_FrmSettings_QuestionWhatToExport"), caption: HelperControlAndMessageBoxHandling.GenericGetMessageBoxCaption( captionType: HelperControlAndMessageBoxHandling.MessageBoxCaption.Question - .ToString()), - checkboxesDictionary: checkboxDictionary, + .ToString()), buttonsDictionary: buttonsDictionary, - orientation: "Vertical"); + orientation: "Vertical", + checkboxesDictionary: checkboxDictionary); // ignore the whole thing if "no" is part of the output // probably impossible that _neither_ of them are in the list but in case i missed something... @@ -1234,8 +1233,7 @@ private void btn_ExportSettings_Click(object sender, ex.Message, caption: HelperControlAndMessageBoxHandling .GenericGetMessageBoxCaption( - captionType: HelperControlAndMessageBoxHandling - .MessageBoxCaption.Error.ToString()), + captionType: HelperControlAndMessageBoxHandling.MessageBoxCaption.Error.ToString()), buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error); customMessageBox.ShowDialog(); @@ -1267,15 +1265,15 @@ private void btn_ImportSettings_Click(object sender, Dictionary buttonsDictionary = GetButtonsDictionary(); // ReSharper disable once InconsistentNaming - List ItemsToImport = DialogWithCheckBox.DisplayAndReturnList( + List ItemsToImport = DialogWithOrWithoutCheckBox.DisplayAndReturnList( labelText: HelperControlAndMessageBoxHandling.GenericGetMessageBoxText( messageBoxName: "mbx_FrmSettings_QuestionWhatToImport"), caption: HelperControlAndMessageBoxHandling.GenericGetMessageBoxCaption( captionType: HelperControlAndMessageBoxHandling.MessageBoxCaption .Question.ToString()), - checkboxesDictionary: checkboxDictionary, buttonsDictionary: buttonsDictionary, - orientation: "Vertical"); + orientation: "Vertical", + checkboxesDictionary: checkboxDictionary); // ignore the whole thing if "no" is part of the output // probably impossible that _neither_ of them are in the list but in case i missed something... @@ -1339,14 +1337,17 @@ private void PromptUserToRestartApp() }; // ReSharper disable once InconsistentNaming - List displayAndReturnList = DialogWithoutCheckBox.DisplayAndReturnList( - labelText: HelperControlAndMessageBoxHandling.GenericGetMessageBoxText( - messageBoxName: "mbx_FrmSettings_PleaseRestartApp"), - caption: HelperControlAndMessageBoxHandling.GenericGetMessageBoxCaption( - captionType: HelperControlAndMessageBoxHandling.MessageBoxCaption.Question - .ToString()), - buttonsDictionary: buttonsDictionary, - orientation: "Horizontal"); + List displayAndReturnList = + DialogWithOrWithoutCheckBox.DisplayAndReturnList( + labelText: HelperControlAndMessageBoxHandling.GenericGetMessageBoxText( + messageBoxName: "mbx_FrmSettings_PleaseRestartApp"), + caption: HelperControlAndMessageBoxHandling.GenericGetMessageBoxCaption( + captionType: HelperControlAndMessageBoxHandling.MessageBoxCaption + .Question + .ToString()), + buttonsDictionary: buttonsDictionary, + orientation: "Horizontal", + checkboxesDictionary: new Dictionary()); // basically this triggers an error in debug mode but works ok in prod. #if !DEBUG diff --git a/GeoTagNinja.csproj b/GeoTagNinja.csproj index a0dd3f6..2dc5658 100644 --- a/GeoTagNinja.csproj +++ b/GeoTagNinja.csproj @@ -28,7 +28,7 @@ latest - AnyCPU + x64 true full false @@ -37,7 +37,7 @@ prompt 4 preview - true + false AnyCPU @@ -62,6 +62,9 @@ app.manifest + + packages\Autoupdater.NET.Official.1.8.5\lib\net45\AutoUpdater.NET.dll + packages\CommandLineParser.2.9.1\lib\net461\CommandLine.dll @@ -80,24 +83,25 @@ packages\Magick.NET.Core.13.3.0\lib\netstandard20\Magick.NET.Core.dll - - packages\Microsoft.Bcl.AsyncInterfaces.7.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll packages\Microsoft.Bcl.HashCode.1.1.1\lib\net461\Microsoft.Bcl.HashCode.dll - - packages\Microsoft.Data.Sqlite.Core.7.0.10\lib\netstandard2.0\Microsoft.Data.Sqlite.dll + + + packages\Microsoft.Data.Sqlite.Core.8.0.4\lib\netstandard2.0\Microsoft.Data.Sqlite.dll - - packages\Microsoft.Web.WebView2.1.0.1938.49\lib\net45\Microsoft.Web.WebView2.Core.dll + + packages\Microsoft.Web.WebView2.1.0.2478.35\lib\net45\Microsoft.Web.WebView2.Core.dll - - packages\Microsoft.Web.WebView2.1.0.1938.49\lib\net45\Microsoft.Web.WebView2.WinForms.dll + + packages\Microsoft.Web.WebView2.1.0.2478.35\lib\net45\Microsoft.Web.WebView2.WinForms.dll - - packages\Microsoft.Web.WebView2.1.0.1938.49\lib\net45\Microsoft.Web.WebView2.Wpf.dll + + packages\Microsoft.Web.WebView2.1.0.2478.35\lib\net45\Microsoft.Web.WebView2.Wpf.dll packages\Microsoft.WindowsAPICodePack.Core.1.1.0\lib\Microsoft.WindowsAPICodePack.dll @@ -112,18 +116,19 @@ packages\NLog.5.2.3\lib\net46\NLog.dll + packages\RestSharp.110.2.0\lib\net471\RestSharp.dll - - packages\SQLitePCLRaw.core.2.1.6\lib\netstandard2.0\SQLitePCLRaw.core.dll + + packages\SQLitePCLRaw.core.2.1.8\lib\netstandard2.0\SQLitePCLRaw.core.dll packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll - - packages\System.Collections.Immutable.7.0.0\lib\net462\System.Collections.Immutable.dll + + packages\System.Collections.Immutable.8.0.0\lib\net462\System.Collections.Immutable.dll @@ -152,14 +157,15 @@ True True - - packages\System.Text.Encoding.CodePages.7.0.0\lib\net462\System.Text.Encoding.CodePages.dll + + + packages\System.Text.Encoding.CodePages.8.0.0\lib\net462\System.Text.Encoding.CodePages.dll - - packages\System.Text.Encodings.Web.7.0.0\lib\net462\System.Text.Encodings.Web.dll + + packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll - - packages\System.Text.Json.7.0.3\lib\net462\System.Text.Json.dll + + packages\System.Text.Json.8.0.3\lib\net462\System.Text.Json.dll packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll @@ -173,6 +179,7 @@ + packages\TimeZoneConverter.6.1.0\lib\net462\TimeZoneConverter.dll @@ -205,12 +212,12 @@ FrmManageFavourites.cs + Form - @@ -299,7 +306,7 @@ FileListView.cs - + FrmAboutBox.cs Designer @@ -448,7 +455,7 @@ PreserveNewest - PreserveNewest + Always PreserveNewest @@ -468,12 +475,12 @@ - + - + \ No newline at end of file diff --git a/Helpers/HelperAPIVersionCheckers.cs b/Helpers/HelperAPIVersionCheckers.cs index 3883c21..05fdb7e 100644 --- a/Helpers/HelperAPIVersionCheckers.cs +++ b/Helpers/HelperAPIVersionCheckers.cs @@ -1,5 +1,5 @@ using System; -using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; @@ -138,6 +138,7 @@ private static int API_GenericGetGTNVersionFromWeb() /// /// Checks for new versions of GTN and ExifTool. /// + [SuppressMessage(category: "ReSharper", checkId: "InconsistentNaming")] internal static async Task CheckForNewVersions() { FrmMainApp.Logger.Debug(message: "Starting"); @@ -174,6 +175,7 @@ internal static async Task CheckForNewVersions() int checkUpdateVal = 604800; //604800 is a week's worth of seconds #if DEBUG checkUpdateVal = 86400; // 86400 is a day's worth of seconds + //checkUpdateVal = 1; #endif if (nowUnixTime > lastCheckUnixTime + checkUpdateVal || @@ -220,13 +222,25 @@ await DownloadCurrentExifToolVersion( // Done w ExifTool and move on to checking GTN stuff // current version may be something like "0.5.8251.40825" // Assembly.GetExecutingAssembly().GetName().Version.Build is just "8251" - // ReSharper disable once InconsistentNaming + string currentGTNVersionBuildMajor = Assembly.GetExecutingAssembly() + .GetName() + .Version.Major + .ToString( + provider: CultureInfo + .InvariantCulture); + + string currentGTNVersionBuildMinor = Assembly.GetExecutingAssembly() + .GetName() + .Version.Minor + .ToString( + provider: CultureInfo + .InvariantCulture); + int currentGTNVersionBuild = Assembly.GetExecutingAssembly() .GetName() .Version.Build; HelperVariables.OperationAPIReturnedOKResponse = true; - // ReSharper disable once InconsistentNaming int newestOnlineGTNVersion = 0; try { @@ -237,30 +251,10 @@ await DownloadCurrentExifToolVersion( // ignore } - if (newestOnlineGTNVersion > currentGTNVersionBuild) - { - CustomMessageBox customMessageBox = new( - text: HelperControlAndMessageBoxHandling.GenericGetMessageBoxText( - messageBoxName: - "mbx_FrmMainApp_InfoNewGTNVersionExists") + - newestOnlineGTNVersion, - caption: HelperControlAndMessageBoxHandling - .GenericGetMessageBoxCaption( - captionType: HelperControlAndMessageBoxHandling.MessageBoxCaption.Warning.ToString()), - buttons: MessageBoxButtons.YesNo, - icon: MessageBoxIcon.Asterisk) - ; - DialogResult dialogResult = customMessageBox.ShowDialog(); - if (dialogResult == DialogResult.Yes) - { - Process.Start( - fileName: - "https://github.com/nemethviktor/GeoTagNinja/releases/download/b" + - newestOnlineGTNVersion.ToString( - provider: CultureInfo.InvariantCulture) + - "/GeoTagNinja_Setup.msi"); - } - } + CreateJsonForUpdate(localMajor: currentGTNVersionBuildMajor, + localMinor: currentGTNVersionBuildMinor, + remoteBuild: newestOnlineGTNVersion.ToString( + provider: CultureInfo.InvariantCulture)); // write back to SQL HelperDataApplicationSettings.DataWriteSQLiteSettings( @@ -303,4 +297,35 @@ private static async Task DownloadCurrentExifToolVersion(string version) // ignore } } + + private static void CreateJsonForUpdate(string localMajor, + string localMinor, + string remoteBuild) + { + // Create JSON object + var jsonObject = new + { + // don't care/can't query remote major and minor + version = $"{localMajor}.{localMinor}.{remoteBuild}.0", + url = + $"https://github.com/nemethviktor/GeoTagNinja/releases/download/b{remoteBuild}/GeoTagNinja_Setup.msi", + changelog = + $"https://github.com/nemethviktor/GeoTagNinja/blob/b{remoteBuild}/changelog.md" + }; + + string jsonContent = + JsonConvert.SerializeObject(value: jsonObject, + formatting: Formatting.Indented); + + string updateJsonPath = + Path.Combine(path1: HelperVariables.UserDataFolderPath, + path2: "updateJsonData.json"); + + if (File.Exists(path: updateJsonPath)) + { + File.Delete(path: updateJsonPath); + } + + File.WriteAllText(path: updateJsonPath, contents: jsonContent); + } } \ No newline at end of file diff --git a/Helpers/HelperExifExifToolOperator.cs b/Helpers/HelperExifExifToolOperator.cs index 58be1b4..a2ca729 100644 --- a/Helpers/HelperExifExifToolOperator.cs +++ b/Helpers/HelperExifExifToolOperator.cs @@ -150,7 +150,7 @@ await Task.Run(action: () => { RemoveDirElementFromDe3AndCopyDataToOriginal( dirElemToDrop: dirElemFileToDrop, - frmMainAppInstance); + frmMainAppInstance: frmMainAppInstance); } if (Path.GetExtension(path: fileNameWithoutPath) == @@ -175,7 +175,7 @@ await Task.Run(action: () => { RemoveDirElementFromDe3AndCopyDataToOriginal( dirElemToDrop: dirElemFileToDrop, - frmMainAppInstance); + frmMainAppInstance: frmMainAppInstance); if (!processOriginalFile && writeXmpSideCar) { string pathOfFile = @@ -190,6 +190,7 @@ await Task.Run(action: () => pathOfFile); RemoveDirElementFromDe3AndCopyDataToOriginal( dirElemToDrop: dirElemFileToDrop, + frmMainAppInstance: frmMainAppInstance); } } @@ -210,7 +211,8 @@ await Task.Run(action: () => length: fileNameWithoutPath.LastIndexOf( value: '.')))) { - bool pathIsLikelyUTF = fileNameWithPath.Any(c => c > 127); + bool pathIsLikelyUTF = + fileNameWithPath.Any(predicate: c => c > 127); MessageBox.Show(text: data.Data + (pathIsLikelyUTF ? Environment.NewLine + @@ -238,13 +240,14 @@ await Task.Run(action: () => prcExifTool.OutputDataReceived += (_, data) => { - if (data.Data != null && data.Data.Length > 0) + if (data.Data != null && + data.Data.Length > 0) { - HelperVariables._sOutputMsg += + HelperVariables._sOutputAndErrorMsg += data.Data.ToString() + Environment.NewLine; } - decimal.TryParse(s: HelperVariables._sOutputMsg + decimal.TryParse(s: HelperVariables._sOutputAndErrorMsg .Replace(oldValue: "\r", newValue: "") .Replace(oldValue: "\n", newValue: ""), provider: CultureInfo.InvariantCulture, @@ -259,20 +262,46 @@ await Task.Run(action: () => prcExifTool.OutputDataReceived += (_, data) => { - if (data.Data != null && data.Data.Length > 0) + if (data.Data is + { + Length: > 0 + } && + // this piece of info is irrelevant and confusing to the user + !data.Data.ToString() + .EndsWith( + value: + ".xmp does not exist") && + // this piece of info is irrelevant and confusing to the user + !data.Data.ToString() + .EndsWith( + value: + "is not defined") + ) { - HelperVariables._sOutputMsg += + HelperVariables._sOutputAndErrorMsg += data.Data.ToString() + Environment.NewLine; } }; + prcExifTool.ErrorDataReceived += (_, + data) => + { + if (data.Data != null && + data.Data.Length > 0) + { + HelperVariables._sOutputAndErrorMsg += "ERROR: " + + data.Data.ToString() + + Environment.NewLine; + } + }; break; default: prcExifTool.OutputDataReceived += (_, data) => { - if (data.Data != null && data.Data.Length > 0) + if (data.Data != null && + data.Data.Length > 0) { - HelperVariables._sOutputMsg += + HelperVariables._sOutputAndErrorMsg += data.Data.ToString() + Environment.NewLine; } }; @@ -280,11 +309,12 @@ await Task.Run(action: () => prcExifTool.ErrorDataReceived += (_, data) => { - if (data.Data != null && data.Data.Length > 0) + if (data.Data != null && + data.Data.Length > 0) { - HelperVariables._sOutputMsg += "ERROR: " + - data.Data.ToString() + - Environment.NewLine; + HelperVariables._sOutputAndErrorMsg += "ERROR: " + + data.Data.ToString() + + Environment.NewLine; } }; break; diff --git a/Helpers/HelperExifReadGetImagePreviews.cs b/Helpers/HelperExifReadGetImagePreviews.cs index cd28db5..d15dd56 100644 --- a/Helpers/HelperExifReadGetImagePreviews.cs +++ b/Helpers/HelperExifReadGetImagePreviews.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Drawing; using System.IO; using System.Text; @@ -125,13 +126,19 @@ internal static async Task GenericCreateImagePreview(string fileNameWithPath, try { - if (fi.Extension.ToLower() == ".heic" || - fi.Extension.ToLower() == ".heif") + List magickExtensionList = + [ + ".heic", + ".heif", + ".webp" + ]; + + if (magickExtensionList.Contains(item: fi.Extension.ToLower())) { // actually the reason i'm not using this for _every_ file is that it's just f...ing slow with NEF files(which is what I have plenty of), so it's prohibitive to run on RAW files. - // since i don't have a better way to deal with HEIC files atm this is as good as it gets. - ConvertHeicToJpeg(heicPath: fileNameWithPath, - jpegPath: generatedFileName); + // since i don't have a better way to deal with HEIC/WEBP files atm this is as good as it gets. + UseMagickImageToGeneratePreview(originalImagePath: fileNameWithPath, + jpegPath: generatedFileName); } else { @@ -200,20 +207,19 @@ internal static async Task GenericCreateImagePreview(string fileNameWithPath, } /// - /// Takes a HEIC file and dumps a JPG. Uses MagickImage. See comment above as to why this isn't being used for all RAW + /// Takes a HEIC/WebP/etc file and dumps a JPG. Uses MagickImage. See comment above as to why this isn't being used for + /// all RAW /// files. (Too slow). /// - /// + /// /// - public static void ConvertHeicToJpeg(string heicPath, - string jpegPath) + private static void UseMagickImageToGeneratePreview(string originalImagePath, + string jpegPath) { - using (MagickImage image = new(fileName: heicPath)) - { - // The AutoOrient() method adjusts the image to respect its orientation. - image.AutoOrient(); - // Save the image as a JPEG. - image.Write(fileName: jpegPath); - } + using MagickImage image = new(fileName: originalImagePath); + // The AutoOrient() method adjusts the image to respect its orientation. + image.AutoOrient(); + // Save the image as a JPEG. + image.Write(fileName: jpegPath); } } \ No newline at end of file diff --git a/Helpers/HelperExifReadTrackData.cs b/Helpers/HelperExifReadTrackData.cs index d629ad4..dce65ae 100644 --- a/Helpers/HelperExifReadTrackData.cs +++ b/Helpers/HelperExifReadTrackData.cs @@ -44,8 +44,8 @@ internal static async Task ExifGetTrackSyncData(string trackFileLocationType, string language, int timeShiftSeconds = 0) { - HelperVariables._sErrorMsg = ""; - HelperVariables._sOutputMsg = ""; + //HelperVariables._sErrorMsg = ""; + HelperVariables._sOutputAndErrorMsg = ""; FrmMainApp frmMainAppInstance = (FrmMainApp)Application.OpenForms[name: "FrmMainApp"]; @@ -429,11 +429,13 @@ await FileListViewReadWrite TextBox tbxText = new(); tbxText.Size = new Size(width: 700, height: 400); - tbxText.Text = HelperVariables._sOutputMsg; + tbxText.Text = HelperVariables._sOutputAndErrorMsg; tbxText.ScrollBars = ScrollBars.Vertical; tbxText.Multiline = true; tbxText.WordWrap = true; tbxText.ReadOnly = true; + tbxText.SelectionStart = 1; + tbxText.SelectionLength = 0; panel.SetFlowBreak(control: tbxText, value: true); panel.Controls.Add(value: tbxText); @@ -458,6 +460,11 @@ await FileListViewReadWrite reportBox.ShowInTaskbar = false; reportBox.StartPosition = FormStartPosition.CenterScreen; + HelperControlThemeManager.SetThemeColour( + themeColour: HelperVariables.UserSettingUseDarkMode + ? ThemeColour.Dark + : ThemeColour.Light, + parentControl: reportBox); reportBox.ShowDialog(); } } diff --git a/Helpers/HelperExifWriteTrackDataToSideCar.cs b/Helpers/HelperExifWriteTrackDataToSideCar.cs index b38d3fc..302f17d 100644 --- a/Helpers/HelperExifWriteTrackDataToSideCar.cs +++ b/Helpers/HelperExifWriteTrackDataToSideCar.cs @@ -43,7 +43,7 @@ internal static async Task ExifWriteTrackDataToSideCar(List trackFileLis Debug.Assert(condition: frmMainAppInstance != null, message: nameof(frmMainAppInstance) + " != null"); string exifArgsForOriginalFile = ""; - // as per https://exiftool.org/forum/index.php?msg=78652 the logic needs to be + // as per https://exiftool.org/forum/index.php?msg=78652 + https://exiftool.org/forum/index.php?topic=16011.new#new the logic needs to be /* -geotag=D:\temp3\2023-02-27.gpx -geotag=D:\temp3\2023-02-28.gpx @@ -54,7 +54,7 @@ internal static async Task ExifWriteTrackDataToSideCar(List trackFileLis GeoMaxExtSecs=1800 D:\temp3\_2280104.ORF D:\temp3\_2280105.ORF - -v2 + -v3 -srcfile C:\Users\nemet\AppData\Roaming\GeoTagNinja\tmpLocFiles\%F.xmp @@ -97,8 +97,8 @@ internal static async Task ExifWriteTrackDataToSideCar(List trackFileLis exifArgsForOriginalFile += imageFilePath + Environment.NewLine; } - // -v2 - exifArgsForOriginalFile += "-v2" + Environment.NewLine; + // -v3 + exifArgsForOriginalFile += "-v3" + Environment.NewLine; // -srcfile exifArgsForOriginalFile += "-srcfile" + Environment.NewLine; // C:\Users\nemet\AppData\Roaming\GeoTagNinja\tmpLocFiles\%F.xmp diff --git a/Helpers/HelperGenericAncillaryListsArrays.cs b/Helpers/HelperGenericAncillaryListsArrays.cs index 80d433b..467eb93 100644 --- a/Helpers/HelperGenericAncillaryListsArrays.cs +++ b/Helpers/HelperGenericAncillaryListsArrays.cs @@ -638,51 +638,11 @@ Code TimeZone STD DST CA Canada/Pacific −08:00 −07:00 CA Canada/Saskatchewan −06:00 −06:00 CA Canada/Yukon −07:00 −07:00 - CET +01:00 +02:00 CL Chile/Continental −04:00 −03:00 CL Chile/EasterIsland −06:00 −05:00 - CST6CDT −06:00 −05:00 CU Cuba −05:00 −04:00 - EET +02:00 +03:00 EG Egypt +02:00 +03:00 IE Eire +01:00 +00:00 - EST −05:00 −05:00 - EST5EDT −05:00 −04:00 - Etc/GMT +00:00 +00:00 - Etc/GMT+0 +00:00 +00:00 - Etc/GMT+1 −01:00 −01:00 - Etc/GMT+10 −10:00 −10:00 - Etc/GMT+11 −11:00 −11:00 - Etc/GMT+12 −12:00 −12:00 - Etc/GMT+2 −02:00 −02:00 - Etc/GMT+3 −03:00 −03:00 - Etc/GMT+4 −04:00 −04:00 - Etc/GMT+5 −05:00 −05:00 - Etc/GMT+6 −06:00 −06:00 - Etc/GMT+7 −07:00 −07:00 - Etc/GMT+8 −08:00 −08:00 - Etc/GMT+9 −09:00 −09:00 - Etc/GMT-0 +00:00 +00:00 - Etc/GMT-1 +01:00 +01:00 - Etc/GMT-10 +10:00 +10:00 - Etc/GMT-11 +11:00 +11:00 - Etc/GMT-12 +12:00 +12:00 - Etc/GMT-13 +13:00 +13:00 - Etc/GMT-14 +14:00 +14:00 - Etc/GMT-2 +02:00 +02:00 - Etc/GMT-3 +03:00 +03:00 - Etc/GMT-4 +04:00 +04:00 - Etc/GMT-5 +05:00 +05:00 - Etc/GMT-6 +06:00 +06:00 - Etc/GMT-7 +07:00 +07:00 - Etc/GMT-8 +08:00 +08:00 - Etc/GMT-9 +09:00 +09:00 - Etc/GMT0 +00:00 +00:00 - Etc/Greenwich +00:00 +00:00 - Etc/UCT +00:00 +00:00 - Etc/Universal +00:00 +00:00 - Etc/UTC +00:00 +00:00 - Etc/Zulu +00:00 +00:00 NL Europe/Amsterdam +01:00 +02:00 AD Europe/Andorra +01:00 +02:00 RU Europe/Astrakhan +04:00 +04:00 @@ -747,16 +707,9 @@ Code TimeZone STD DST HR Europe/Zagreb +01:00 +02:00 UA Europe/Zaporozhye +02:00 +03:00 CH, DE, LI Europe/Zurich +01:00 +02:00 - Factory +00:00 +00:00 GB GB +00:00 +01:00 GB GB-Eire +00:00 +01:00 - GMT +00:00 +00:00 - GMT+0 +00:00 +00:00 - GMT-0 +00:00 +00:00 - GMT0 +00:00 +00:00 - Greenwich +00:00 +00:00 HK Hongkong +08:00 +08:00 - HST −10:00 −10:00 IS Iceland +00:00 +00:00 MG Indian/Antananarivo +03:00 +03:00 IO Indian/Chagos +06:00 +06:00 @@ -775,12 +728,9 @@ Code TimeZone STD DST JP Japan +09:00 +09:00 MH Kwajalein +12:00 +12:00 LY Libya +02:00 +02:00 - MET +01:00 +02:00 MX Mexico/BajaNorte −08:00 −07:00 MX Mexico/BajaSur −07:00 −07:00 MX Mexico/General −06:00 −06:00 - MST −07:00 −07:00 - MST7MDT −07:00 −06:00 US Navajo −07:00 −06:00 NZ NZ +12:00 +13:00 NZ NZ-CHAT +12:45 +13:45 @@ -828,16 +778,6 @@ Code TimeZone STD DST UM Pacific/Wake +12:00 +12:00 WF Pacific/Wallis +12:00 +12:00 FM Pacific/Yap +10:00 +10:00 - PL Poland +01:00 +02:00 - PT Portugal +00:00 +01:00 - CN PRC +08:00 +08:00 - PST8PDT −08:00 −07:00 - TW ROC +08:00 +08:00 - KR ROK +09:00 +09:00 - SG Singapore +08:00 +08:00 - TR Turkey +03:00 +03:00 - UCT +00:00 +00:00 - Universal +00:00 +00:00 US US/Alaska −09:00 −08:00 US US/Aleutian −10:00 −09:00 US US/Arizona −07:00 −07:00 @@ -850,10 +790,6 @@ Code TimeZone STD DST US US/Mountain −07:00 −06:00 US US/Pacific −08:00 −07:00 AS US/Samoa −11:00 −11:00 - UTC +00:00 +00:00 - RU W-SU +03:00 +03:00 - WET +00:00 +01:00 - Zulu +00:00 +00:00 """; @@ -1124,6 +1060,7 @@ internal static string[] AllCompatibleExtensions() "orf Olympus RAW Format (TIFF-based)", "ori Olympus RAW Format (TIFF-based)", "pef Pentax (RAW) Electronic Format (TIFF-based)", + "png Portable Network Graphics", "raf FujiFilm RAW Format", "raw Kyocera Contax N Digital RAW", "rw2 Panasonic RAW 2 (TIFF-based)", @@ -1133,7 +1070,8 @@ internal static string[] AllCompatibleExtensions() "thm Thumbnail image (JPEG)", "tif QuickTime Image File", "tiff Tagged Image File Format", - "wdp Windows HD Photo / Media Photo / JPEG XR (TIFF-based)", + "wdp Windows HD Photo / Media Photo / JPEG XR (TIFF-based)", + "webp WebP Image File", "x3f Sigma/Foveon RAW" }; return result; @@ -1153,7 +1091,8 @@ internal static string[] FileExtensionsThatUseXMP() .Contains(value: "tiff")) { retList.Add(item: extension.Split('\t') - .FirstOrDefault()); + .FirstOrDefault() + ?.Trim()); } } @@ -1178,7 +1117,8 @@ internal static string[] AllCompatibleExtensionsExt() { allowedExtensions[i] = allowedExtensions[i] .Split('\t') - .FirstOrDefault(); + .FirstOrDefault() + ?.Trim(); } return allowedExtensions; diff --git a/Helpers/HelperGenericAppStartup.cs b/Helpers/HelperGenericAppStartup.cs index 7672a9c..297a3a1 100644 --- a/Helpers/HelperGenericAppStartup.cs +++ b/Helpers/HelperGenericAppStartup.cs @@ -318,7 +318,9 @@ public static void AppStartupCheckWebView2() try { string webView2Version = ""; - webView2Version = CoreWebView2Environment.GetAvailableBrowserVersionString(); + webView2Version = + CoreWebView2Environment.GetAvailableBrowserVersionString( + browserExecutableFolder: null); FrmMainApp.Logger.Trace(message: "Check webView2 version is: " + webView2Version); } catch (Exception ex) diff --git a/Helpers/HelperNonStatic.AutoUpdater.cs b/Helpers/HelperNonStatic.AutoUpdater.cs new file mode 100644 index 0000000..302ceab --- /dev/null +++ b/Helpers/HelperNonStatic.AutoUpdater.cs @@ -0,0 +1,92 @@ +using System; +using System.Windows.Forms; +using AutoUpdaterDotNET; +using Newtonsoft.Json; + +namespace GeoTagNinja.Helpers; + +internal partial class HelperNonStatic +{ + internal void AutoUpdaterOnParseUpdateInfoEvent(ParseUpdateInfoEventArgs args) + { + dynamic json = JsonConvert.DeserializeObject(value: args.RemoteData); + args.UpdateInfo = new UpdateInfoEventArgs + { + CurrentVersion = json.version, + ChangelogURL = json.changelog, + DownloadURL = json.url + }; + } + + internal void AutoUpdaterOnCheckForUpdateEvent(UpdateInfoEventArgs args) + { + if (args.Error == null) + { + if (args.IsUpdateAvailable) + { + DialogResult dialogResult; + //if (args.Mandatory.Value) + //{ + // dialogResult = + // MessageBox.Show( + // text: + // $@"There is new version {args.CurrentVersion} available. You are using version {args.InstalledVersion}. This is required update. Press Ok to begin updating the application.", + // caption: @"Update Available", + // buttons: MessageBoxButtons.OK, + // icon: MessageBoxIcon.Information); + //} + //else + { + dialogResult = + MessageBox.Show( + text: + $@"There is new version {args.CurrentVersion} available. You are using version {args.InstalledVersion}. Do you want to update the application now?", + caption: @"Update Available", + buttons: MessageBoxButtons.YesNo, + icon: MessageBoxIcon.Information); + } + + if (dialogResult.Equals(obj: DialogResult.Yes) || + dialogResult.Equals(obj: DialogResult.OK)) + { + try + { + if (AutoUpdater.DownloadUpdate(args: args)) + { + Application.Exit(); + } + } + catch (Exception exception) + { + MessageBox.Show(text: exception.Message, caption: exception + .GetType() + .ToString(), buttons: MessageBoxButtons.OK, + icon: MessageBoxIcon.Error); + } + } + } + //else + //{ + // MessageBox.Show( + // text: @"There is no update available please try again later.", + // caption: @"No update available", + // buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Information); + //} + } + //if (args.Error is WebException) + //{ + // MessageBox.Show( + // text: + // @"There is a problem reaching update server. Please check your internet connection and try again later.", + // caption: @"Update Check Failed", buttons: MessageBoxButtons.OK, + // icon: MessageBoxIcon.Error); + //} + //else + //{ + // MessageBox.Show(text: args.Error.Message, + // caption: args.Error.GetType() + // .ToString(), buttons: MessageBoxButtons.OK, + // icon: MessageBoxIcon.Error); + //} + } +} \ No newline at end of file diff --git a/Helpers/HelperVariables.cs b/Helpers/HelperVariables.cs index 0dd7c7c..cc69871 100644 --- a/Helpers/HelperVariables.cs +++ b/Helpers/HelperVariables.cs @@ -27,8 +27,8 @@ internal static class HelperVariables internal static bool OperationAPIReturnedOKResponse = true; internal static bool OperationNowSelectingAllItems = false; - internal static string _sErrorMsg = ""; - internal static string _sOutputMsg = ""; + //internal static string _sErrorMsg = ""; + internal static string _sOutputAndErrorMsg = ""; internal static string HTMLAddMarker; internal static string HTMLCreatePoints; internal static HashSet<(string strLat, string strLng)> HsMapMarkers = new(); diff --git a/SQLite.Interop.dll b/SQLite.Interop.dll index 322eb05..12de96a 100644 Binary files a/SQLite.Interop.dll and b/SQLite.Interop.dll differ diff --git a/View/DialogAndMessageBoxes/CustomMessageBox.cs b/View/DialogAndMessageBoxes/CustomMessageBox.cs index 6e0dded..39574e8 100644 --- a/View/DialogAndMessageBoxes/CustomMessageBox.cs +++ b/View/DialogAndMessageBoxes/CustomMessageBox.cs @@ -10,6 +10,7 @@ public class CustomMessageBox : Form { private Label _lblMessage; private PictureBox _pictureBox; + private const string NAMEANDTEXT = "CustomMessageBox"; /// /// Initializes a new instance of the CustomMessageBox class. @@ -48,29 +49,48 @@ public CustomMessageBox(string text, CreateButton(text: "Cancel", result: DialogResult.Cancel); break; case MessageBoxButtons.YesNo: - CreateButton(text: "Yes", result: DialogResult.Yes); - CreateButton(text: "No", result: DialogResult.No); + CreateButton(text: "&Yes", result: DialogResult.Yes); + CreateButton(text: "&No", result: DialogResult.No); break; case MessageBoxButtons.YesNoCancel: - CreateButton(text: "Yes", result: DialogResult.Yes); - CreateButton(text: "No", result: DialogResult.No); + CreateButton(text: "&Yes", result: DialogResult.Yes); + CreateButton(text: "&No", result: DialogResult.No); CreateButton(text: "Cancel", result: DialogResult.Cancel); break; case MessageBoxButtons.RetryCancel: - CreateButton(text: "Retry", result: DialogResult.Retry); + CreateButton(text: "&Retry", result: DialogResult.Retry); CreateButton(text: "Cancel", result: DialogResult.Cancel); break; case MessageBoxButtons.AbortRetryIgnore: - CreateButton(text: "Abort", result: DialogResult.Abort); - CreateButton(text: "Retry", result: DialogResult.Retry); - CreateButton(text: "Ignore", result: DialogResult.Ignore); + CreateButton(text: "&Abort", result: DialogResult.Abort); + CreateButton(text: "&Retry", result: DialogResult.Retry); + CreateButton(text: "&Ignore", result: DialogResult.Ignore); break; default: - throw new ArgumentOutOfRangeException(paramName: nameof(buttons), actualValue: buttons, message: null); + throw new ArgumentOutOfRangeException(paramName: nameof(buttons), + actualValue: buttons, + message: null); } PositionButtons(); // Set icon in PictureBox based on MessageBoxIcon value + SetPictureBox(icon: icon); + } + + public sealed override string Text + { + get => base.Text; + set => base.Text = value; + } + + + /// + /// Sets the picture box (icon) for the Form + /// + /// + /// + private void SetPictureBox(MessageBoxIcon icon) + { if (icon == MessageBoxIcon.None) { _pictureBox.Image = null; @@ -109,7 +129,8 @@ public CustomMessageBox(string text, } else { - throw new ArgumentOutOfRangeException(paramName: nameof(icon), actualValue: icon, message: null); + throw new ArgumentOutOfRangeException(paramName: nameof(icon), + actualValue: icon, message: null); } } @@ -145,8 +166,8 @@ private void InitializeComponent() AutoScaleDimensions = new SizeF(width: 6F, height: 13F); AutoScaleMode = AutoScaleMode.Font; ClientSize = new Size(width: 284, height: 261); - Name = "CustomMessageBox"; - Text = "CustomMessageBox"; + Name = NAMEANDTEXT; + Text = NAMEANDTEXT; // Set additional properties FormBorderStyle = FormBorderStyle.FixedDialog; MaximizeBox = false; @@ -173,6 +194,17 @@ private void CreateButton(string text, button.Click += (sender, e) => DialogResult = result; button.Size = new Size(width: ButtonWidth, height: ButtonHeight); + button.UseMnemonic = true; + if (result == DialogResult.OK) + { + AcceptButton = button; + } + + else if (result == DialogResult.Cancel) + { + CancelButton = button; + } + _buttons.Add(item: button); _buttonCount++; } @@ -183,7 +215,9 @@ private void PositionButtons() int startX = (Width - totalWidth) / 2; for (int i = 0; i < _buttonCount; i++) { - _buttons[index: i].Location = new Point(x: startX + i * (ButtonWidth + ButtonSpacing), y: Math.Max(val1: _lblMessage.Bottom, val2: _pictureBox.Bottom) + 10); + _buttons[index: i].Location = new Point( + x: startX + i * (ButtonWidth + ButtonSpacing), + y: Math.Max(val1: _lblMessage.Bottom, val2: _pictureBox.Bottom) + 10); Controls.Add(value: _buttons[index: i]); } } diff --git a/View/DialogAndMessageBoxes/DialogWithCheckBox.cs b/View/DialogAndMessageBoxes/DialogWithOrWithoutCheckBox.cs similarity index 77% rename from View/DialogAndMessageBoxes/DialogWithCheckBox.cs rename to View/DialogAndMessageBoxes/DialogWithOrWithoutCheckBox.cs index 0d454d4..3defe89 100644 --- a/View/DialogAndMessageBoxes/DialogWithCheckBox.cs +++ b/View/DialogAndMessageBoxes/DialogWithOrWithoutCheckBox.cs @@ -6,17 +6,13 @@ namespace GeoTagNinja.View.DialogAndMessageBoxes; -internal class DialogWithCheckBox +internal class DialogWithOrWithoutCheckBox { /// /// Displays a dialog box with a set of checkboxes and buttons. /// /// The text to be displayed at the top of the dialog box. /// The text to be displayed in the title bar of the dialog box. - /// - /// A dictionary where each key-value pair represents a checkbox in the dialog. The key - /// is the text to be displayed next to the checkbox, and the value is the return value when the checkbox is selected. - /// /// /// A dictionary where each key-value pair represents a button in the dialog. The key is /// the text to be displayed on the button, and the value is the return value when the button is clicked. @@ -25,14 +21,18 @@ internal class DialogWithCheckBox /// The layout orientation of the checkboxes and buttons in the dialog. Can be either "Vertical" /// or "Horizontal". /// + /// + /// A dictionary where each key-value pair represents a checkbox in the dialog. The key + /// is the text to be displayed next to the checkbox, and the value is the return value when the checkbox is selected. + /// /// A list of strings representing the return values of the selected checkboxes and clicked button. internal static List DisplayAndReturnList(string labelText, string caption, - Dictionary - checkboxesDictionary, Dictionary buttonsDictionary, - string orientation) + string orientation, + Dictionary + checkboxesDictionary) { List returnChoicesList = new(); Form promptBoxForm = new() @@ -104,20 +104,29 @@ void AddButtons() { KeyValuePair keyValuePair = buttonsDictionary.ElementAt(index: i); - Button btn = new(); - btn.Text = keyValuePair.Key; - switch (keyValuePair.Value.ToLower()) + string btnText = keyValuePair.Key; + Button btn = new() { - case "yes": - case "ok": - promptBoxForm.AcceptButton = btn; - acceptButtonReturnText = keyValuePair.Value; - break; - case "no": - case "cancel": - promptBoxForm.CancelButton = btn; - cancelButtonReturnText = keyValuePair.Value; - break; + UseMnemonic = true, + Text = btnText is "Yes" or "No" + ? "&" + btnText + : btnText + }; + if (btnText.ToLower() + .Contains(value: "yes") || + btnText.ToLower() + .Contains(value: "ok")) + { + promptBoxForm.AcceptButton = btn; + acceptButtonReturnText = keyValuePair.Value; + } + else if (btnText.ToLower() + .Contains(value: "no") || + btnText.ToLower() + .Contains(value: "cancel")) + { + promptBoxForm.CancelButton = btn; + cancelButtonReturnText = keyValuePair.Value; } btn.Click += (s, @@ -148,21 +157,24 @@ void AddButtons() void AddCheckBoxes() { - // add checkboxes - for (int i = 0; i < checkboxesDictionary.Count; i++) + if (checkboxesDictionary.Count > 0) { - KeyValuePair keyValuePair = - checkboxesDictionary.ElementAt(index: i); - CheckBox chk = new(); - chk.Text = keyValuePair.Key; - chk.AutoSize = true; + // add checkboxes + for (int i = 0; i < checkboxesDictionary.Count; i++) + { + KeyValuePair keyValuePair = + checkboxesDictionary.ElementAt(index: i); + CheckBox chk = new(); + chk.Text = keyValuePair.Key; + chk.AutoSize = true; - flowLayoutPanel.Controls.Add(value: chk); + flowLayoutPanel.Controls.Add(value: chk); - if (i == checkboxesDictionary.Count && - orientation == "Vertical") - { - flowLayoutPanel.SetFlowBreak(control: chk, value: true); + if (i == checkboxesDictionary.Count && + orientation == "Vertical") + { + flowLayoutPanel.SetFlowBreak(control: chk, value: true); + } } } } diff --git a/View/DialogAndMessageBoxes/DialogWithoutCheckBox.cs b/View/DialogAndMessageBoxes/DialogWithoutCheckBox.cs deleted file mode 100644 index 171db4f..0000000 --- a/View/DialogAndMessageBoxes/DialogWithoutCheckBox.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Windows.Forms; -using GeoTagNinja.Helpers; - -namespace GeoTagNinja.View.DialogAndMessageBoxes; - -internal class DialogWithoutCheckBox -{ - /// - /// Displays a dialog box without a checkbox and returns a list of user choices. - /// - /// The text to be displayed in the dialog box. - /// The title of the dialog box. - /// - /// A dictionary containing the text and return values of the buttons to be displayed in - /// the dialog box. - /// - /// The orientation of the buttons in the dialog box. Can be either "Vertical" or "Horizontal". - /// - /// A list of strings representing the user's choices. The choices are determined by the buttons clicked by the - /// user. - /// - /// - /// The dialog box is displayed in the center of the screen. The theme of the dialog box is determined by the user's - /// settings. - /// If the user closes the dialog box without making a choice, the function returns a list containing the return value - /// of the "no" or "cancel" button. - /// - internal static List DisplayAndReturnList(string labelText, - string caption, - Dictionary - buttonsDictionary, - string orientation) - { - List returnChoicesList = new(); - Form promptBoxForm = new() - { - Text = caption, - ControlBox = false, - FormBorderStyle = FormBorderStyle.Fixed3D - }; - - // Create the FlowLayoutPanel - FlowLayoutPanel flowLayoutPanel = new(); - // Set the flow direction to top-to-bottom if the orientation is "Vertical" - if (orientation == "Vertical") - { - flowLayoutPanel.FlowDirection = FlowDirection.TopDown; - } - - // apply theme - HelperControlThemeManager.SetThemeColour( - themeColour: HelperVariables.UserSettingUseDarkMode - ? ThemeColour.Dark - : ThemeColour.Light, parentControl: promptBoxForm); - - Label lblText = new(); - lblText.Text = labelText; - lblText.MaximumSize = new Size(width: 300, height: 0); - lblText.AutoSize = true; - flowLayoutPanel.SetFlowBreak(control: lblText, value: true); - flowLayoutPanel.Controls.Add(value: lblText); - - // these are to make my life easier -- gets overwritten further down - string acceptButtonReturnText = "##yes##"; - string cancelButtonReturnText = "##no##"; - - AddButtons(); - flowLayoutPanel.Padding = new Padding(all: 5); - flowLayoutPanel.AutoSize = true; - - promptBoxForm.Controls.Add(value: flowLayoutPanel); - promptBoxForm.AutoSize = true; - promptBoxForm.ShowInTaskbar = false; - - promptBoxForm.StartPosition = FormStartPosition.CenterScreen; - promptBoxForm.ShowDialog(); - - // in case of idiots break glass -- basically if someone ALT+F4s then we reset stuff to "no". - if (!returnChoicesList.Contains(value: acceptButtonReturnText) && - !returnChoicesList.Contains(value: cancelButtonReturnText)) - { - returnChoicesList.Add(item: cancelButtonReturnText); - } - - return returnChoicesList; - - void AddButtons() - { - // add buttons - for (int i = 0; i < buttonsDictionary.Count; i++) - { - KeyValuePair keyValuePair = - buttonsDictionary.ElementAt(index: i); - Button btn = new(); - btn.Text = keyValuePair.Key; - btn.Tag = keyValuePair.Value; - switch (keyValuePair.Value.ToLower()) - { - case "yes": - case "ok": - promptBoxForm.AcceptButton = btn; - acceptButtonReturnText = keyValuePair.Value; - break; - case "no": - case "cancel": - promptBoxForm.CancelButton = btn; - cancelButtonReturnText = keyValuePair.Value; - break; - } - - btn.Click += (s, - e) => - { - if (promptBoxForm.AcceptButton == btn) - { - returnChoicesList.Add(item: acceptButtonReturnText); - } - else if (promptBoxForm.CancelButton == btn) - { - returnChoicesList.Add(item: cancelButtonReturnText); - } - else - { - returnChoicesList.Add(item: btn.Tag.ToString()); - } - - promptBoxForm.Close(); - }; - btn.AutoSize = true; - flowLayoutPanel.Controls.Add(value: btn); - // add flowbreak to the last btn - if (i == buttonsDictionary.Count && - orientation == "Horizontal") - { - flowLayoutPanel.SetFlowBreak(control: btn, value: true); - } - } - } - } -} - - diff --git a/changelog.md b/changelog.md index c2ac2b1..3ced50f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,17 @@ # GeoTagNinja Changelog **Build 8xxx [20240xxx]** +- NEW & UPDATED: + - Dark Mode should now apply to GPX Import Report + - Custom MessageBoxes should now respect hotkeys in certain cases + - Added PNG and WEBP file support + - Added an auto-updater. It's a bit tricky to test but I think it works. Report bugs pls. + - Updated some of the underlying packages; removed x86 references to SQLite + +- BUGS & FIXES: + - Patched GPX Import Report re #105 + +**Build 8834 [20240309]** - NEW & UPDATED: - Paste coordinate-pair string from clipboard into Edit Form (see readme about this or the tooltip in the Edit Form) #100 - Added a button to the Edit Form to move to the next image when there's a multi-selection (Apply & Move to Next) [also #100] diff --git a/packages.config b/packages.config index e9f97fa..52a8523 100644 --- a/packages.config +++ b/packages.config @@ -1,24 +1,25 @@  + - + - - + + - + - + @@ -27,9 +28,9 @@ - - - + + + diff --git a/readme.md b/readme.md index a2f5f73..70dcd18 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,7 @@ GeoTagNinja is an open-source photo geotagger GUI for Windows. GTN uses [exifToo There is a "short" (15 mins) demo on [YouTube](https://youtu.be/ulP1ZG7mH-I) if you feel like watching it. It's from the original (Aug 2022) release but it still covers the main features more or less. It's only gotten better since... -## Download & Install (Windows 7+ only) +## Download & Install (Windows 7+ x64 only) - Download the .msi file from [Releases](https://github.com/nemethviktor/GeoTagNinja/releases) - Find the newest release (topmost, easy) then click on Assets if they are not showing. [There are now Development and Prod releases, both should be stable but if you'd like to be on the safer side, pick the prod updates.] - As of 20221202 I've removed the built-in webView2 installer because it was more of a pain in the backside than benefit. If the app breaks complaining about the lack of webView2, it's available [here](https://go.microsoft.com/fwlink/p/?LinkId=2124703) @@ -141,8 +141,7 @@ Longer: Hypothetically the idea with Destinations is that if there are groups of ## System Requirements -- Windows 7+ is needed. -- SQLite is running x86 but fwiw the app isn't really memory-hungry so it will do. Chances are if you're still on a 1st-gen Intel Core you're not on Windows 7. Hopefully. +- Windows 7+ x64 is needed. - You'll need an ArcGIS API key to use the map search functionality. Register for free [here](https://developers.arcgis.com/) - You'll need a geoNames username and password to use toponomy search. Register for free [here](https://www.geonames.org/) - WebView2 is required but should come with your OS most likely. If not, get it from [here](https://go.microsoft.com/fwlink/p/?LinkId=2124703) \ No newline at end of file