Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 106 additions & 102 deletions src/Files.App/Helpers/AdaptiveLayoutHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,124 +3,128 @@
using Files.App.ViewModels;
using Files.App.ViewModels.Previews;
using Files.Backend.Services.Settings;
using IniParser.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Storage;
using static Files.App.Constants.AdaptiveLayout;
using IO = System.IO;

namespace Files.App.Helpers
{
public static class AdaptiveLayoutHelpers
{
private static readonly IFoldersSettingsService foldersSettingsService = Ioc.Default.GetRequiredService<IFoldersSettingsService>();

public static bool PredictLayoutMode(FolderSettingsViewModel folderSettings, string path, IList<ListedItem> filesAndFolders)
{
IUserSettingsService userSettingsService = Ioc.Default.GetRequiredService<IUserSettingsService>();
if (!foldersSettingsService.EnableOverridingFolderPreferences)
return false;
if (string.IsNullOrWhiteSpace(path))
return false;
if (folderSettings.IsLayoutModeFixed || !folderSettings.IsAdaptiveLayoutEnabled)
return false;

if (userSettingsService.FoldersSettingsService.EnableOverridingFolderPreferences
&& folderSettings.IsAdaptiveLayoutEnabled
&& !folderSettings.IsLayoutModeFixed)
var layout = GetAdaptiveLayout(path, filesAndFolders);
switch (layout)
{
Action layoutDetails = () => folderSettings.ToggleLayoutModeDetailsView(false);
Action layoutGridView = () => folderSettings.ToggleLayoutModeGridView(folderSettings.GridViewSize);

bool desktopIniFound = false;

if (string.IsNullOrWhiteSpace(path))
{
return false;
}

var iniPath = System.IO.Path.Combine(path, "desktop.ini");
var iniContents = NativeFileOperationsHelper.ReadStringFromFile(iniPath)?.Trim();
if (!string.IsNullOrEmpty(iniContents))
{
var parser = new IniParser.Parser.IniDataParser();
parser.Configuration.ThrowExceptionsOnError = false;
var data = parser.Parse(iniContents);
if (data is not null)
{
var viewModeSection = data.Sections.FirstOrDefault(x => "ViewState".Equals(x.SectionName, StringComparison.OrdinalIgnoreCase));
if (viewModeSection is not null)
{
var folderTypeKey = viewModeSection.Keys.FirstOrDefault(s => "FolderType".Equals(s.KeyName, StringComparison.OrdinalIgnoreCase));
if (folderTypeKey is not null)
{
var setLayout = (folderTypeKey.Value) switch
{
"Documents" => layoutDetails,
"Pictures" => layoutGridView,
"Music" => layoutDetails,
"Videos" => layoutGridView,
_ => layoutDetails
};
setLayout();
desktopIniFound = true;
}
}
}
}

if (desktopIniFound)
{
case Layouts.Detail:
folderSettings.ToggleLayoutModeDetailsView(false);
return true;
}
if (filesAndFolders.Count == 0)
{
case Layouts.Grid:
folderSettings.ToggleLayoutModeGridView(folderSettings.GridViewSize);
return true;
default:
return false;
}

int allItemsCount = filesAndFolders.Count;

int mediaCount;
int imagesCount;
int foldersCount;
int miscFilesCount;

float mediaPercentage;
float imagesPercentage;
float foldersPercentage;
float miscFilesPercentage;

mediaCount = filesAndFolders.Where((item) =>
{
return !string.IsNullOrEmpty(item.FileExtension) && MediaPreviewViewModel.ContainsExtension(item.FileExtension.ToLowerInvariant());
}).Count();
imagesCount = filesAndFolders.Where((item) =>
{
return !string.IsNullOrEmpty(item.FileExtension) && ImagePreviewViewModel.ContainsExtension(item.FileExtension.ToLowerInvariant());
}).Count();
foldersCount = filesAndFolders.Where((item) => item.PrimaryItemAttribute == StorageItemTypes.Folder).Count();
miscFilesCount = allItemsCount - (mediaCount + imagesCount + foldersCount);

mediaPercentage = (float)((float)mediaCount / (float)allItemsCount) * 100.0f;
imagesPercentage = (float)((float)imagesCount / (float)allItemsCount) * 100.0f;
foldersPercentage = (float)((float)foldersCount / (float)allItemsCount) * 100.0f;
miscFilesPercentage = (float)((float)miscFilesCount / (float)allItemsCount) * 100.0f;

// Decide layout mode

// Mostly files + folders, lesser media and image files | Mostly folders
if ((foldersPercentage + miscFilesPercentage) > Constants.AdaptiveLayout.LargeThreshold)
{
layoutDetails();
}
// Mostly images, probably an images folder
else if (imagesPercentage > Constants.AdaptiveLayout.ExtraLargeThreshold
|| (imagesPercentage > Constants.AdaptiveLayout.MediumThreshold
&& (mediaPercentage + miscFilesPercentage + foldersPercentage) > Constants.AdaptiveLayout.SmallThreshold
&& (miscFilesPercentage + foldersPercentage) < Constants.AdaptiveLayout.ExtraSmallThreshold))
{
layoutGridView();
}
else
{
layoutDetails();
}

return true;
}
}

private static Layouts GetAdaptiveLayout(string path, IList<ListedItem> filesAndFolders)
{
var pathLayout = GetPathLayout(path);
if (pathLayout is not Layouts.None)
return pathLayout;

return GetContentLayout(filesAndFolders);
}

private static Layouts GetPathLayout(string path)
{
var iniPath = IO.Path.Combine(path, "desktop.ini");

var iniContents = NativeFileOperationsHelper.ReadStringFromFile(iniPath)?.Trim();
if (string.IsNullOrEmpty(iniContents))
return Layouts.None;

var parser = new IniParser.Parser.IniDataParser();
parser.Configuration.ThrowExceptionsOnError = false;
var data = parser.Parse(iniContents);
if (data is null)
return Layouts.None;

var viewModeSection = data.Sections.FirstOrDefault(IsViewState);
if (viewModeSection is null)
return Layouts.None;

return false;
var folderTypeKey = viewModeSection.Keys.FirstOrDefault(IsFolderType);
if (folderTypeKey is null)
return Layouts.None;

return folderTypeKey.Value switch
{
"Pictures" => Layouts.Grid,
"Videos" => Layouts.Grid,
_ => Layouts.Detail,
};

static bool IsViewState(SectionData data)
=> "ViewState".Equals(data.SectionName, StringComparison.OrdinalIgnoreCase);

static bool IsFolderType(KeyData data)
=> "FolderType".Equals(data.KeyName, StringComparison.OrdinalIgnoreCase);
}

private static Layouts GetContentLayout(IList<ListedItem> filesAndFolders)
{
int itemCount = filesAndFolders.Count;
if (filesAndFolders.Count is 0)
return Layouts.None;

float folderPercentage = 100f * filesAndFolders.Count(IsFolder) / itemCount;
float imagePercentage = 100f * filesAndFolders.Count(IsImage) / itemCount;
float mediaPercentage = 100f * filesAndFolders.Count(IsMedia) / itemCount;
float miscPercentage = 100f - (folderPercentage + imagePercentage + mediaPercentage);

if (folderPercentage + miscPercentage > LargeThreshold)
return Layouts.Detail;
if (imagePercentage > ExtraLargeThreshold)
return Layouts.Grid;
if (imagePercentage <= MediumThreshold)
return Layouts.Detail;
if (100f - imagePercentage <= SmallThreshold)
return Layouts.Detail;
if (folderPercentage + miscPercentage <= ExtraSmallThreshold)
return Layouts.Detail;
return Layouts.Grid;

static bool IsFolder(ListedItem item)
=> item.PrimaryItemAttribute is StorageItemTypes.Folder;

static bool IsImage(ListedItem item)
=> !string.IsNullOrEmpty(item.FileExtension)
&& ImagePreviewViewModel.ContainsExtension(item.FileExtension.ToLowerInvariant());

static bool IsMedia(ListedItem item)
=> !string.IsNullOrEmpty(item.FileExtension)
&& MediaPreviewViewModel.ContainsExtension(item.FileExtension.ToLowerInvariant());
}

private enum Layouts
{
None,
Detail,
Grid,
}
}
}
}