mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
notofficer fix + audio player volume saved + click notif to open path
This commit is contained in:
parent
23b126a00a
commit
a4f1cc2b2c
|
|
@ -26,10 +26,11 @@ namespace FModel
|
|||
{
|
||||
StartTimer = Stopwatch.StartNew();
|
||||
|
||||
if (FModel.Properties.Settings.Default.UseEnglish)
|
||||
DebugHelper.Init(LogsFilePath); // get old settings too
|
||||
|
||||
if (FModel.Properties.Settings.Default.UseEnglish) // use old settings here
|
||||
Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
|
||||
|
||||
DebugHelper.Init(LogsFilePath);
|
||||
DebugHelper.WriteLine("{0} {1}", "[FModel]", "––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––");
|
||||
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Version]", Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
||||
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Build]", Globals.Build);
|
||||
|
|
@ -64,7 +65,7 @@ namespace FModel
|
|||
{
|
||||
string errorMessage = string.Format(FModel.Properties.Resources.UnhandledExceptionOccured, e.Exception.Message);
|
||||
DebugHelper.WriteException(e.Exception, "thrown in App.xaml.cs by OnDispatcherUnhandledException");
|
||||
DarkMessageBoxHelper.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
DarkMessageBoxHelper.Show(errorMessage, FModel.Properties.Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ namespace FModel.Creator
|
|||
public static SKBitmap GetSoftObjectTexture(SoftObjectProperty s) => GetTexture(s.Value.AssetPathName.String);
|
||||
public static SKBitmap GetTexture(string s)
|
||||
{
|
||||
// FortniteGame/Content/Catalog/DisplayAssets/DA_BattlePassBundle_2020.uasset
|
||||
if (s.Equals("/Game/UI/Foundation/Textures/BattleRoyale/FeaturedItems/Outfit/T_UI_InspectScreen_annualPass"))
|
||||
s += "_1024";
|
||||
|
||||
PakPackage p = GetPropertyPakPackage(s);
|
||||
if (p.HasExport() && !p.Equals(default))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ namespace FModel.Discord
|
|||
{
|
||||
Assets = _assets,
|
||||
Timestamps = _baseTimestamp,
|
||||
Details = string.IsNullOrEmpty(detail) ? _presence.Details : detail,
|
||||
State = string.IsNullOrEmpty(state) ? _presence.State : state
|
||||
Details = string.IsNullOrEmpty(detail) ? _presence?.Details : detail,
|
||||
State = string.IsNullOrEmpty(state) ? _presence?.State : state
|
||||
});
|
||||
_client.Invoke();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System;
|
|||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
|
|
@ -19,44 +20,48 @@ namespace FModel.Grabber.Paks
|
|||
{
|
||||
PopulateBase();
|
||||
|
||||
if (string.IsNullOrEmpty(Properties.Settings.Default.PakPath))
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var launcher = new FLauncher();
|
||||
if ((bool)launcher.ShowDialog())
|
||||
if (string.IsNullOrEmpty(Properties.Settings.Default.PakPath))
|
||||
{
|
||||
Properties.Settings.Default.PakPath = launcher.Path;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
}
|
||||
|
||||
// define the current game thank to the pak path
|
||||
Folders.SetGameName(Properties.Settings.Default.PakPath);
|
||||
|
||||
// Add Pak Files
|
||||
if (Directory.Exists(Properties.Settings.Default.PakPath))
|
||||
{
|
||||
foreach (string pak in Directory.GetFiles(Properties.Settings.Default.PakPath, "*.pak"))
|
||||
{
|
||||
if (!Utils.Paks.IsFileReadLocked(new FileInfo(pak)))
|
||||
var launcher = new FLauncher();
|
||||
if ((bool)launcher.ShowDialog())
|
||||
{
|
||||
PakFileReader pakFile = new PakFileReader(pak);
|
||||
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Registering]", $"{pakFile.FileName} with GUID {pakFile.Info.EncryptionKeyGuid.Hex}");
|
||||
Properties.Settings.Default.PakPath = launcher.Path;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
}
|
||||
|
||||
MenuItems.pakFiles.Add(new PakMenuItemViewModel
|
||||
// define the current game thank to the pak path
|
||||
Folders.SetGameName(Properties.Settings.Default.PakPath);
|
||||
|
||||
// Add Pak Files
|
||||
if (Directory.Exists(Properties.Settings.Default.PakPath))
|
||||
{
|
||||
foreach (string pak in Directory.GetFiles(Properties.Settings.Default.PakPath, "*.pak"))
|
||||
{
|
||||
if (!Utils.Paks.IsFileReadLocked(new FileInfo(pak)))
|
||||
{
|
||||
PakFile = pakFile,
|
||||
IsEnabled = false
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.PakFiles, string.Format(Properties.Resources.PakFileLocked, Path.GetFileNameWithoutExtension(pak)));
|
||||
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Locked]", pak);
|
||||
PakFileReader pakFile = new PakFileReader(pak);
|
||||
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Registering]", $"{pakFile.FileName} with GUID {pakFile.Info.EncryptionKeyGuid.Hex}");
|
||||
|
||||
Application.Current.Dispatcher.Invoke(delegate
|
||||
{
|
||||
MenuItems.pakFiles.Add(new PakMenuItemViewModel
|
||||
{
|
||||
PakFile = pakFile,
|
||||
IsEnabled = false
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
FConsole.AppendText(string.Format(Properties.Resources.PakFileLocked, Path.GetFileNameWithoutExtension(pak)), FColors.Red, true);
|
||||
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Locked]", pak);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
|
||||
private static void PopulateBase()
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace PakReader
|
||||
{
|
||||
static class BinaryHelper
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long Align(long val, long alignment)
|
||||
{
|
||||
return val + alignment - 1 & ~(alignment - 1);
|
||||
}
|
||||
|
||||
public static uint Flip(uint value) => (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 |
|
||||
(value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24;
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ namespace PakReader
|
|||
|
||||
reader.ReadUInt32(); // SourceStringHash
|
||||
|
||||
string EntryLocalizedString = string.Empty;
|
||||
string EntryLocalizedString;
|
||||
if (VersionNumber >= Version.COMPACT)
|
||||
{
|
||||
int LocalizedStringIndex = reader.ReadInt32();
|
||||
|
|
@ -130,18 +130,16 @@ namespace PakReader
|
|||
}
|
||||
else
|
||||
{
|
||||
//throw new IOException($"LocRes has an invalid localized string index for namespace '{Namespace}' and key '{Key}'. This entry will have no translation.");
|
||||
throw new IOException($"LocRes has an invalid localized string index for namespace '{Namespace}' and key '{Key}'. This entry will have no translation.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EntryLocalizedString = reader.ReadFString();
|
||||
}
|
||||
|
||||
if (Key != null) Entries.Add(Key, EntryLocalizedString);
|
||||
Entries.Add(Key, EntryLocalizedString);
|
||||
}
|
||||
|
||||
if (Namespace != null) this.Entries.Add(Namespace, Entries);
|
||||
this.Entries.Add(Namespace, Entries);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -417,18 +417,17 @@ namespace PakReader.Pak
|
|||
// Get the right pointer to start copying the CompressionBlocks information from.
|
||||
|
||||
// Alignment of the compressed blocks
|
||||
var CompressedBlockAlignment = Encrypted ? AESDecryptor.BLOCK_SIZE : 1;
|
||||
var CompressedBlockAlignment = Encrypted ? 16 : 1;
|
||||
|
||||
// CompressedBlockOffset is the starting offset. Everything else can be derived from there.
|
||||
long CompressedBlockOffset = BaseOffset + FPakEntry.GetSize(EPakVersion.LATEST, CompressionMethodIndex, CompressionBlocksCount);
|
||||
for (int CompressionBlockIndex = 0; CompressionBlockIndex < CompressionBlocks.Length; ++CompressionBlockIndex)
|
||||
{
|
||||
CompressionBlocks[CompressionBlockIndex] = new FPakCompressedBlock(CompressedBlockOffset, CompressedBlockOffset + BitConverter.ToUInt32(encodedPakEntries, pakLocation));
|
||||
pakLocation += sizeof(uint);
|
||||
{
|
||||
var toAlign = CompressionBlocks[CompressionBlockIndex].CompressedEnd - CompressionBlocks[CompressionBlockIndex].CompressedStart;
|
||||
CompressedBlockOffset += toAlign + CompressedBlockAlignment - (toAlign % CompressedBlockAlignment);
|
||||
}
|
||||
FPakCompressedBlock CompressionBlock = new FPakCompressedBlock(CompressedBlockOffset, CompressedBlockOffset + BitConverter.ToUInt32(encodedPakEntries, pakLocation));
|
||||
CompressionBlocks[CompressionBlockIndex] = CompressionBlock;
|
||||
CompressedBlockOffset += BinaryHelper.Align(CompressionBlock.CompressedEnd - CompressionBlock.CompressedStart, CompressedBlockAlignment);
|
||||
|
||||
pakLocation += 4;
|
||||
}
|
||||
}
|
||||
return new FPakEntry(this.FileName, name, Offset, Size, UncompressedSize, new byte[20], CompressionBlocks, CompressionBlockSize, CompressionMethodIndex, (byte)((Encrypted ? 0x01 : 0x00) | (Deleted ? 0x02 : 0x00)));
|
||||
|
|
|
|||
|
|
@ -6,17 +6,20 @@ namespace PakReader.Parsers.Objects
|
|||
{
|
||||
public readonly long CompressedStart;
|
||||
public readonly long CompressedEnd;
|
||||
public readonly long Size;
|
||||
|
||||
internal FPakCompressedBlock(BinaryReader reader)
|
||||
{
|
||||
CompressedStart = reader.ReadInt64();
|
||||
CompressedEnd = reader.ReadInt64();
|
||||
Size = CompressedEnd - CompressedStart;
|
||||
}
|
||||
|
||||
internal FPakCompressedBlock(long start, long end)
|
||||
{
|
||||
CompressedStart = start;
|
||||
CompressedEnd = end;
|
||||
Size = end - start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,52 +136,67 @@ namespace PakReader.Parsers.Objects
|
|||
{
|
||||
lock (stream)
|
||||
{
|
||||
stream.Position = Offset + StructSize;
|
||||
if (Encrypted)
|
||||
if (CompressionMethodIndex == 0U)
|
||||
{
|
||||
var data = new byte[(Size & 15) == 0 ? Size : ((Size / 16) + 1) * 16];
|
||||
stream.Read(data, 0, data.Length);
|
||||
byte[] decrypted = AESDecryptor.DecryptAES(data, key);
|
||||
|
||||
if (CompressionMethodIndex != 0U)
|
||||
stream.Position = Offset + StructSize;
|
||||
if (Encrypted)
|
||||
{
|
||||
using var m = new MemoryStream(decrypted, 0, decrypted.Length)
|
||||
{
|
||||
Position = 0
|
||||
};
|
||||
Decompress(m, compressionMethods, decrypted);
|
||||
var data = new byte[(Size & 15) == 0 ? Size : (Size / 16 + 1) * 16];
|
||||
stream.Read(data, 0, data.Length);
|
||||
return new ArraySegment<byte>(AESDecryptor.DecryptAES(data, key), 0, (int)UncompressedSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = new byte[UncompressedSize];
|
||||
stream.Read(data, 0, data.Length);
|
||||
return new ArraySegment<byte>(data);
|
||||
}
|
||||
|
||||
return new ArraySegment<byte>(decrypted, 0, decrypted.Length <= (int)UncompressedSize ? decrypted.Length : (int)UncompressedSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = new byte[UncompressedSize];
|
||||
if (CompressionMethodIndex == 0U)
|
||||
stream.Read(data, 0, data.Length);
|
||||
else
|
||||
Decompress(stream, compressionMethods, data);
|
||||
|
||||
Decompress(stream, key, compressionMethods, data);
|
||||
return new ArraySegment<byte>(data);
|
||||
}
|
||||
}
|
||||
throw new NotImplementedException("Decompression not yet implemented");
|
||||
}
|
||||
|
||||
private void Decompress(Stream stream, string[] compressionMethods, byte[] outData)
|
||||
private void Decompress(Stream stream, byte[] key, string[] compressionMethods, byte[] outData)
|
||||
{
|
||||
if (compressionMethods == null || compressionMethods.Length == 0)
|
||||
throw new IndexOutOfRangeException("CompressionMethods are null or empty");
|
||||
throw new ArgumentOutOfRangeException(nameof(compressionMethods), "CompressionMethods are null or empty");
|
||||
|
||||
var compressionMethod = compressionMethods[CompressionMethodIndex - 1]; // -1 because we dont have 'NAME_None' in the array
|
||||
Stream compressionStream = compressionMethod.ToLower() switch
|
||||
string compressionMethod = compressionMethods[CompressionMethodIndex - 1]; // -1 because we dont have 'NAME_None' in the array
|
||||
int bytesRead = 0;
|
||||
for (int i = 0; i < CompressionBlocks.Length; i++)
|
||||
{
|
||||
"zlib" => new ZlibStream(stream, CompressionMode.Decompress, true),
|
||||
"gzip" => new GZipStream(stream, CompressionMode.Decompress, true),
|
||||
_ => throw new NotImplementedException($"Decompression not yet implemented ({compressionMethod})")
|
||||
};
|
||||
compressionStream.Read(outData, 0, outData.Length);
|
||||
compressionStream.Dispose();
|
||||
stream.Position = Offset + CompressionBlocks[i].CompressedStart;
|
||||
int uncompressedSize = (int)Math.Min(CompressionBlockSize, outData.Length - bytesRead);
|
||||
|
||||
byte[] blockBbuffer;
|
||||
if (Encrypted)
|
||||
{
|
||||
blockBbuffer = new byte[BinaryHelper.Align(CompressionBlocks[i].Size, AESDecryptor.BLOCK_SIZE)];
|
||||
stream.Read(blockBbuffer, 0, blockBbuffer.Length);
|
||||
blockBbuffer = AESDecryptor.DecryptAES(blockBbuffer, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
blockBbuffer = new byte[CompressionBlocks[i].Size];
|
||||
stream.Read(blockBbuffer, 0, blockBbuffer.Length);
|
||||
}
|
||||
|
||||
using var blockMs = new MemoryStream(blockBbuffer, false);
|
||||
using Stream compressionStream = compressionMethod switch
|
||||
{
|
||||
"Zlib" => new ZlibStream(blockMs, CompressionMode.Decompress),
|
||||
"Gzip" => new GZipStream(blockMs, CompressionMode.Decompress),
|
||||
_ => throw new NotImplementedException($"Decompression not yet implemented ({compressionMethod})")
|
||||
};
|
||||
|
||||
bytesRead += compressionStream.Read(outData, bytesRead, uncompressedSize);
|
||||
}
|
||||
}
|
||||
|
||||
public static long GetSize(EPakVersion version, uint CompressionMethodIndex = 0, uint CompressionBlocksCount = 0)
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@
|
|||
<value>Немецкий</value>
|
||||
</data>
|
||||
<data name="Hello" xml:space="preserve">
|
||||
<value>Здравсвтуйте</value>
|
||||
<value>Здравствуйте</value>
|
||||
</data>
|
||||
<data name="Help" xml:space="preserve">
|
||||
<value>Помощь</value>
|
||||
|
|
|
|||
12
FModel/Properties/Settings.Designer.cs
generated
12
FModel/Properties/Settings.Designer.cs
generated
|
|
@ -227,6 +227,18 @@ namespace FModel.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("0.5")]
|
||||
public string AudioPlayerVolume {
|
||||
get {
|
||||
return ((string)(this["AudioPlayerVolume"]));
|
||||
}
|
||||
set {
|
||||
this["AudioPlayerVolume"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@
|
|||
<Setting Name="AudioPlayerDevice" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="AudioPlayerVolume" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">0.5</Value>
|
||||
</Setting>
|
||||
<Setting Name="AutoExport" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
|
|
|
|||
|
|
@ -1172,12 +1172,12 @@
|
|||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Padding" Value="1"/>
|
||||
|
||||
|
||||
<!-- FModel ViewModel Support -->
|
||||
<Setter Property="Content" Value="{Binding Content}"/>
|
||||
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
|
||||
<!-- End FModel ViewModel Support -->
|
||||
|
||||
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
|
|
@ -1211,7 +1211,6 @@
|
|||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
|
||||
<Setter Property="Background" Value="{StaticResource ButtonBackground}"/>
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ namespace FModel.Utils
|
|||
if (autoSave)
|
||||
FConsole.AppendText(string.Format(Properties.Resources.DataExported, name), FColors.Green, true);
|
||||
else
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.DataExported, name));
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.DataExported, name), string.Empty, fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -370,7 +370,7 @@ namespace FModel.Utils
|
|||
if (autoSave)
|
||||
FConsole.AppendText(string.Format(Properties.Resources.DataExported, name), FColors.Green, true);
|
||||
else
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.DataExported, name));
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.DataExported, name, string.Empty, fullPath));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ namespace FModel.Utils
|
|||
{
|
||||
mainError = true;
|
||||
StatusBarVm.statusBarViewModel.Set(e.Message, Properties.Resources.Error);
|
||||
FConsole.AppendText(string.Format(Properties.Resources.StaticKeyNotWorking, $"0x{sKey}"), FColors.Red);
|
||||
FConsole.AppendText(string.Format(Properties.Resources.StaticKeyNotWorking, $"0x{sKey}"), FColors.Red, true);
|
||||
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[AES]", $"0x{sKey} is NOT!!!! working with user's pak files");
|
||||
}
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ namespace FModel.Utils
|
|||
}
|
||||
}
|
||||
|
||||
menuItem.IsEnabled = menuItem.PakFile.AesKey != null;
|
||||
menuItem.IsEnabled = menuItem.PakFile.AesKey != null || !menuItem.PakFile.Info.bEncryptedIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,11 +58,10 @@ namespace FModel.Utils
|
|||
foreach (var namespac in new LocResReader(asset).Entries)
|
||||
{
|
||||
if (!_fortniteLocalizationDict.ContainsKey(namespac.Key))
|
||||
_fortniteLocalizationDict[namespac.Key] = new Dictionary<string, string>();
|
||||
_fortniteLocalizationDict.Add(namespac.Key, new Dictionary<string, string>());
|
||||
|
||||
foreach (var key in namespac.Value)
|
||||
if (!string.IsNullOrEmpty(key.Value))
|
||||
_fortniteLocalizationDict[namespac.Key][key.Key] = key.Value;
|
||||
_fortniteLocalizationDict[namespac.Key][key.Key] = key.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ namespace FModel.ViewModels.AvalonEdit
|
|||
if (File.Exists(saveFileDialog.FileName))
|
||||
{
|
||||
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[AvalonEditViewModel]", $"{vm.OwerName} successfully saved");
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, Properties.Resources.DataSaved);
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, Properties.Resources.DataSaved, string.Empty, saveFileDialog.FileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ namespace FModel.ViewModels.ImageBox
|
|||
if (File.Exists(saveFileDialog.FileName))
|
||||
{
|
||||
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[AvalonEditViewModel]", $"{vm.Name} successfully saved");
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, Properties.Resources.ImageSaved);
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, Properties.Resources.ImageSaved, string.Empty, saveFileDialog.FileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ namespace FModel.ViewModels.MenuItem
|
|||
{
|
||||
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[CDN]", $"Downloaded {Header} in {downloadTimer.ElapsedMilliseconds} ms");
|
||||
StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.DownloadSuccess, Header), Properties.Resources.Success);
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.DownloadSuccess, Header), "/FModel;component/Resources/check-circle.ico");
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.DownloadSuccess, Header), "/FModel;component/Resources/check-circle.ico", path);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -202,7 +202,7 @@ namespace FModel.ViewModels.MenuItem
|
|||
{
|
||||
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[BackupMenuItemViewModel]", "[Create]", $"{_backupFileName} successfully created");
|
||||
StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.CreateSuccess, _backupFileName), Properties.Resources.Success);
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.CreateSuccess, _backupFileName), "/FModel;component/Resources/check-circle.ico");
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.CreateSuccess, _backupFileName), "/FModel;component/Resources/check-circle.ico", _backupFilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,11 +11,12 @@ namespace FModel.ViewModels.Notifier
|
|||
|
||||
public override NotificationDisplayPart DisplayPart => _displayPart ?? (_displayPart = new CustomNotifier(this));
|
||||
|
||||
public NotifierViewModel(string title, string message, string icon, MessageOptions messageOptions) : base(message, messageOptions)
|
||||
public NotifierViewModel(string title, string message, string icon, string path, MessageOptions messageOptions) : base(message, messageOptions)
|
||||
{
|
||||
Title = title;
|
||||
Message = message;
|
||||
Icon = icon;
|
||||
Path = path;
|
||||
}
|
||||
|
||||
private string _title;
|
||||
|
|
@ -51,6 +52,17 @@ namespace FModel.ViewModels.Notifier
|
|||
}
|
||||
}
|
||||
|
||||
private string _path;
|
||||
public string Path
|
||||
{
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using FModel.Windows.SoundPlayer.Visualization;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
|
||||
namespace FModel.ViewModels.SoundPlayer
|
||||
|
|
@ -38,7 +39,7 @@ namespace FModel.ViewModels.SoundPlayer
|
|||
private string _content;
|
||||
private string _bytes;
|
||||
private string _duration;
|
||||
private float _volume = 0.5f;
|
||||
private float _volume = float.Parse(Properties.Settings.Default.AudioPlayerVolume, CultureInfo.InvariantCulture.NumberFormat);
|
||||
|
||||
public ObservableCollection<Device> Devices
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
xmlns:core="clr-namespace:ToastNotifications.Core;assembly=ToastNotifications"
|
||||
mc:Ignorable="d" Background="#FF232930"
|
||||
d:DesignHeight="60" d:DesignWidth="250"
|
||||
d:DataContext="{d:DesignInstance vm:NotifierViewModel, IsDesignTimeCreatable=False}">
|
||||
d:DataContext="{d:DesignInstance vm:NotifierViewModel, IsDesignTimeCreatable=False}"
|
||||
MouseLeftButtonUp="NotificationDisplayPart_MouseLeftButtonUp">
|
||||
<Grid>
|
||||
<Border BorderThickness="2" BorderBrush="#7F748198">
|
||||
<Grid Margin="4">
|
||||
|
|
@ -20,11 +21,14 @@
|
|||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Image Grid.RowSpan="2" Source="{Binding Icon}"/>
|
||||
<TextBlock Text="{Binding Title}" FontWeight="Bold" Foreground="White" Grid.Column="2" FontFamily="Calibri" />
|
||||
<TextBlock Text="{Binding Message}" FontWeight="Light" Foreground="White" Grid.Row="1" Grid.Column="2" TextWrapping="Wrap"/>
|
||||
<Image x:Name="OpenPath_Img" Grid.Row="2" Grid.Column="2" Source="/Resources/open-in-new.png" Visibility="Hidden"
|
||||
Width="12" Height="12" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using FModel.ViewModels.Notifier;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
using ToastNotifications.Core;
|
||||
|
||||
namespace FModel.Windows.CustomNotifier
|
||||
|
|
@ -11,7 +13,20 @@ namespace FModel.Windows.CustomNotifier
|
|||
public CustomNotifier(NotifierViewModel notifier)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!string.IsNullOrEmpty(notifier.Path))
|
||||
OpenPath_Img.Visibility = System.Windows.Visibility.Visible;
|
||||
|
||||
Bind(notifier);
|
||||
}
|
||||
|
||||
private void NotificationDisplayPart_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is CustomNotifier c && c.DataContext is NotifierViewModel n)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(n.Path))
|
||||
Process.Start(new ProcessStartInfo { FileName = "explorer.exe", Arguments = $"/select, \"{n.Path.Replace('/', '\\')}\"", UseShellExecute = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ namespace FModel.Windows.CustomNotifier
|
|||
{
|
||||
public static class CustomNotifierHelper
|
||||
{
|
||||
public static void ShowCustomMessage(this Notifier notifier, string title, string message, string icon = null, MessageOptions messageOptions = null)
|
||||
public static void ShowCustomMessage(this Notifier notifier, string title, string message, string icon = null, string path = null, MessageOptions messageOptions = null)
|
||||
{
|
||||
notifier.Notify(() => new NotifierViewModel(title, message, string.IsNullOrEmpty(icon) ? "/FModel;component/FModel.ico" : icon, messageOptions));
|
||||
notifier.Notify(() => new NotifierViewModel(title, message, string.IsNullOrEmpty(icon) ? "/FModel;component/FModel.ico" : icon, path, messageOptions));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ namespace FModel.Windows.ImagesMerger
|
|||
if (File.Exists(saveFileDialog.FileName))
|
||||
{
|
||||
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[ImagesMerger]", "Preview successfully saved");
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, Properties.Resources.ImageSaved);
|
||||
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, Properties.Resources.ImageSaved, string.Empty, saveFileDialog.FileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ namespace FModel.Windows.SoundPlayer.Visualization
|
|||
set
|
||||
{
|
||||
volume = value;
|
||||
Properties.Settings.Default.AudioPlayerVolume = volume.ToString();
|
||||
Properties.Settings.Default.Save();
|
||||
|
||||
if (_soundOut != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ This software uses the following open source packages:
|
|||
- [Autoupdater.NET.Official](https://github.com/ravibpatel/AutoUpdater.NET)
|
||||
- [AvalonEdit](https://github.com/icsharpcode/AvalonEdit)
|
||||
- [CSCore](https://github.com/filoe/cscore)
|
||||
- [DotNetZip](https://github.com/haf/DotNetZip.Semverd)
|
||||
- [DiscordRichPresence](https://github.com/Lachee/discord-rpc-csharp)
|
||||
- [Extended.Wpf.Toolkit](https://github.com/xceedsoftware/wpftoolkit)
|
||||
- [K4os.Compression.LZ4.Streams](https://github.com/MiloszKrajewski/K4os.Compression.LZ4)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user