2024-05-21 16:55:15 +02:00
|
|
|
// Copyright (c) Microsoft Corporation
|
|
|
|
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
|
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Drawing.Drawing2D;
|
|
|
|
|
using System.Drawing.Imaging;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text.Json.Serialization;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows.Media.Imaging;
|
2024-05-28 18:21:30 +02:00
|
|
|
using ManagedCommon;
|
2024-05-24 15:36:01 +02:00
|
|
|
using ProjectsEditor.Utils;
|
2024-05-21 16:55:15 +02:00
|
|
|
|
|
|
|
|
namespace ProjectsEditor.Models
|
|
|
|
|
{
|
|
|
|
|
public class Project : INotifyPropertyChanged
|
|
|
|
|
{
|
|
|
|
|
[JsonIgnore]
|
|
|
|
|
public string EditorWindowTitle { get; set; }
|
|
|
|
|
|
|
|
|
|
public string Id { get; set; }
|
|
|
|
|
|
|
|
|
|
private string _name;
|
|
|
|
|
|
|
|
|
|
public string Name
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_name = value;
|
|
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(Name)));
|
2024-06-17 15:21:13 +02:00
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(CanBeSaved)));
|
2024-05-21 16:55:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public long CreationTime { get; set; } // in seconds
|
|
|
|
|
|
|
|
|
|
public long LastLaunchedTime { get; set; } // in seconds
|
|
|
|
|
|
|
|
|
|
public bool IsShortcutNeeded { get; set; }
|
|
|
|
|
|
|
|
|
|
public string LastLaunched
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
string lastLaunched = ProjectsEditor.Properties.Resources.LastLaunched + ": ";
|
|
|
|
|
if (LastLaunchedTime == 0)
|
|
|
|
|
{
|
|
|
|
|
return lastLaunched + ProjectsEditor.Properties.Resources.Never;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int SECOND = 1;
|
|
|
|
|
const int MINUTE = 60 * SECOND;
|
|
|
|
|
const int HOUR = 60 * MINUTE;
|
|
|
|
|
const int DAY = 24 * HOUR;
|
|
|
|
|
const int MONTH = 30 * DAY;
|
|
|
|
|
|
|
|
|
|
DateTime lastLaunchDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(LastLaunchedTime);
|
|
|
|
|
|
|
|
|
|
var now = DateTime.UtcNow.Ticks;
|
|
|
|
|
var ts = DateTime.UtcNow - lastLaunchDateTime;
|
|
|
|
|
double delta = Math.Abs(ts.TotalSeconds);
|
|
|
|
|
|
|
|
|
|
if (delta < 1 * MINUTE)
|
|
|
|
|
{
|
|
|
|
|
return lastLaunched + ProjectsEditor.Properties.Resources.Recently;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (delta < 2 * MINUTE)
|
|
|
|
|
{
|
|
|
|
|
return lastLaunched + ProjectsEditor.Properties.Resources.OneMinuteAgo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (delta < 45 * MINUTE)
|
|
|
|
|
{
|
|
|
|
|
return lastLaunched + ts.Minutes + " " + ProjectsEditor.Properties.Resources.MinutesAgo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (delta < 90 * MINUTE)
|
|
|
|
|
{
|
|
|
|
|
return lastLaunched + ProjectsEditor.Properties.Resources.OneHourAgo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (delta < 24 * HOUR)
|
|
|
|
|
{
|
|
|
|
|
return lastLaunched + ts.Hours + " " + ProjectsEditor.Properties.Resources.HoursAgo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (delta < 48 * HOUR)
|
|
|
|
|
{
|
|
|
|
|
return lastLaunched + ProjectsEditor.Properties.Resources.Yesterday;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (delta < 30 * DAY)
|
|
|
|
|
{
|
|
|
|
|
return lastLaunched + ts.Days + " " + ProjectsEditor.Properties.Resources.DaysAgo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (delta < 12 * MONTH)
|
|
|
|
|
{
|
|
|
|
|
int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30));
|
|
|
|
|
return lastLaunched + (months <= 1 ? ProjectsEditor.Properties.Resources.OneMonthAgo : months + " " + ProjectsEditor.Properties.Resources.MonthsAgo);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365));
|
|
|
|
|
return lastLaunched + (years <= 1 ? ProjectsEditor.Properties.Resources.OneYearAgo : years + " " + ProjectsEditor.Properties.Resources.YearsAgo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-17 15:21:13 +02:00
|
|
|
public bool CanBeSaved
|
|
|
|
|
{
|
2024-06-27 18:58:16 +02:00
|
|
|
get => Name.Length > 0 && Applications.Count > 0;
|
2024-06-17 15:21:13 +02:00
|
|
|
}
|
|
|
|
|
|
2024-05-21 17:45:07 +02:00
|
|
|
private bool _isPopupVisible;
|
2024-05-21 16:55:15 +02:00
|
|
|
|
|
|
|
|
[JsonIgnore]
|
|
|
|
|
public bool IsPopupVisible
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2024-05-21 17:45:07 +02:00
|
|
|
return _isPopupVisible;
|
2024-05-21 16:55:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
2024-05-21 17:45:07 +02:00
|
|
|
_isPopupVisible = value;
|
2024-05-21 16:55:15 +02:00
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsPopupVisible)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<Application> Applications { get; set; }
|
|
|
|
|
|
|
|
|
|
public List<object> ApplicationsListed
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
List<object> applicationsListed = new List<object>();
|
|
|
|
|
ILookup<MonitorSetup, Application> apps = Applications.Where(x => !x.Minimized).ToLookup(x => x.MonitorSetup);
|
|
|
|
|
foreach (var appItem in apps.OrderBy(x => x.Key.MonitorDpiUnawareBounds.Left).ThenBy(x => x.Key.MonitorDpiUnawareBounds.Top))
|
|
|
|
|
{
|
2024-06-28 13:07:30 +02:00
|
|
|
MonitorHeaderRow headerRow = new MonitorHeaderRow { MonitorName = appItem.Key.MonitorInfo, SelectString = Properties.Resources.SelectAllAppsOnMonitor + " " + appItem.Key.MonitorInfo };
|
|
|
|
|
applicationsListed.Add(headerRow);
|
2024-05-21 16:55:15 +02:00
|
|
|
foreach (Application app in appItem)
|
|
|
|
|
{
|
|
|
|
|
applicationsListed.Add(app);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var minimizedApps = Applications.Where(x => x.Minimized);
|
|
|
|
|
if (minimizedApps.Any())
|
|
|
|
|
{
|
2024-06-28 13:07:30 +02:00
|
|
|
MonitorHeaderRow headerRow = new MonitorHeaderRow { MonitorName = Properties.Resources.Minimized_Apps, SelectString = Properties.Resources.SelectAllMinimizedApps };
|
|
|
|
|
applicationsListed.Add(headerRow);
|
2024-05-21 16:55:15 +02:00
|
|
|
foreach (Application app in minimizedApps)
|
|
|
|
|
{
|
|
|
|
|
applicationsListed.Add(app);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return applicationsListed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[JsonIgnore]
|
|
|
|
|
public string AppsCountString
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2024-06-27 18:58:16 +02:00
|
|
|
int count = Applications.Count;
|
2024-06-14 10:50:26 +02:00
|
|
|
return count.ToString(CultureInfo.InvariantCulture) + " " + (count == 1 ? Properties.Resources.App : Properties.Resources.Apps);
|
2024-05-21 16:55:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<MonitorSetup> Monitors { get; set; }
|
|
|
|
|
|
2024-06-24 09:34:47 +02:00
|
|
|
private BitmapImage _previewIcons;
|
2024-05-21 16:55:15 +02:00
|
|
|
private BitmapImage _previewImage;
|
2024-06-24 09:34:47 +02:00
|
|
|
private double _previewImageWidth;
|
2024-05-21 16:55:15 +02:00
|
|
|
|
2024-05-21 17:48:58 +02:00
|
|
|
public Project(Project selectedProject)
|
2024-05-21 16:55:15 +02:00
|
|
|
{
|
2024-05-21 17:48:58 +02:00
|
|
|
Name = selectedProject.Name;
|
2024-06-24 09:34:47 +02:00
|
|
|
PreviewIcons = selectedProject.PreviewIcons;
|
2024-05-21 17:48:58 +02:00
|
|
|
PreviewImage = selectedProject.PreviewImage;
|
|
|
|
|
IsShortcutNeeded = selectedProject.IsShortcutNeeded;
|
2024-05-21 16:55:15 +02:00
|
|
|
|
|
|
|
|
int screenIndex = 1;
|
|
|
|
|
|
|
|
|
|
Monitors = new List<MonitorSetup>();
|
2024-05-21 17:48:58 +02:00
|
|
|
foreach (var item in selectedProject.Monitors.OrderBy(x => x.MonitorDpiAwareBounds.Left).ThenBy(x => x.MonitorDpiAwareBounds.Top))
|
2024-05-21 16:55:15 +02:00
|
|
|
{
|
2024-06-24 09:34:47 +02:00
|
|
|
Monitors.Add(new MonitorSetup($"Screen {screenIndex}", item.MonitorInstanceId, item.MonitorNumber, item.Dpi, item.MonitorDpiAwareBounds, item.MonitorDpiUnawareBounds));
|
2024-05-21 16:55:15 +02:00
|
|
|
screenIndex++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Applications = new List<Application>();
|
2024-05-21 17:48:58 +02:00
|
|
|
foreach (var item in selectedProject.Applications)
|
2024-05-21 16:55:15 +02:00
|
|
|
{
|
|
|
|
|
Applications.Add(new Application()
|
|
|
|
|
{
|
2024-05-27 16:33:13 +02:00
|
|
|
AppName = item.AppName,
|
2024-05-21 16:55:15 +02:00
|
|
|
AppPath = item.AppPath,
|
|
|
|
|
AppTitle = item.AppTitle,
|
|
|
|
|
CommandLineArguments = item.CommandLineArguments,
|
2024-05-27 16:33:13 +02:00
|
|
|
PackageFullName = item.PackageFullName,
|
2024-05-21 16:55:15 +02:00
|
|
|
Minimized = item.Minimized,
|
|
|
|
|
Maximized = item.Maximized,
|
|
|
|
|
MonitorNumber = item.MonitorNumber,
|
2024-06-10 10:19:57 +02:00
|
|
|
IsNotFound = item.IsNotFound,
|
2024-05-21 16:55:15 +02:00
|
|
|
Position = new Application.WindowPosition() { X = item.Position.X, Y = item.Position.Y, Height = item.Position.Height, Width = item.Position.Width },
|
|
|
|
|
Parent = this,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Project()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-24 09:34:47 +02:00
|
|
|
public BitmapImage PreviewIcons
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _previewIcons;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_previewIcons = value;
|
|
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(PreviewIcons)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-21 16:55:15 +02:00
|
|
|
public BitmapImage PreviewImage
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _previewImage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_previewImage = value;
|
|
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(PreviewImage)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-24 09:34:47 +02:00
|
|
|
public double PreviewImageWidth
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _previewImageWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
_previewImageWidth = value;
|
|
|
|
|
OnPropertyChanged(new PropertyChangedEventArgs(nameof(PreviewImageWidth)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-21 16:55:15 +02:00
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
|
|
|
|
|
|
public void OnPropertyChanged(PropertyChangedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
PropertyChanged?.Invoke(this, e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async void Initialize()
|
|
|
|
|
{
|
2024-06-24 09:34:47 +02:00
|
|
|
PreviewIcons = await Task.Run(() => DrawHelper.DrawPreviewIcons(this));
|
|
|
|
|
Rectangle commonBounds = GetCommonBounds();
|
|
|
|
|
PreviewImage = await Task.Run(() => DrawHelper.DrawPreview(this, commonBounds));
|
|
|
|
|
PreviewImageWidth = commonBounds.Width / (commonBounds.Height * 1.2 / 200);
|
2024-05-21 16:55:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Rectangle GetCommonBounds()
|
|
|
|
|
{
|
2024-06-24 10:38:08 +02:00
|
|
|
double minX = Monitors.First().MonitorDpiAwareBounds.Left;
|
|
|
|
|
double minY = Monitors.First().MonitorDpiAwareBounds.Top;
|
|
|
|
|
double maxX = Monitors.First().MonitorDpiAwareBounds.Right;
|
|
|
|
|
double maxY = Monitors.First().MonitorDpiAwareBounds.Bottom;
|
|
|
|
|
for (int monitorIndex = 1; monitorIndex < Monitors.Count; monitorIndex++)
|
2024-05-21 16:55:15 +02:00
|
|
|
{
|
2024-06-24 10:38:08 +02:00
|
|
|
Monitor monitor = Monitors[monitorIndex];
|
|
|
|
|
minX = Math.Min(minX, monitor.MonitorDpiAwareBounds.Left);
|
|
|
|
|
minY = Math.Min(minY, monitor.MonitorDpiAwareBounds.Top);
|
|
|
|
|
maxX = Math.Max(maxX, monitor.MonitorDpiAwareBounds.Right);
|
|
|
|
|
maxY = Math.Max(maxY, monitor.MonitorDpiAwareBounds.Bottom);
|
2024-05-21 16:55:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|