Better TimeZone entry in System Settings (#1254)

* Better timezone labels in System TimeZone

Replace with GtkEntry with auto-complete

Also removed async task as now loading is fast

Address Thog's comments

self-nit: Remove string alias

Address AcK's comments

* Improve parsing
* Optimize and fix string matching

Address jD's comments

* Also, make abbreviations searchable
* Optimize EntryCompletion's MatchFunc

* nit: Result.IsFailure()

* Fix potential crash on opening Settings window w/o FW installed
This commit is contained in:
mageven 2020-07-21 09:44:42 +05:30 committed by GitHub
parent 21dfa4974a
commit 4aa47a66c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 190 additions and 68 deletions

View file

@ -10,6 +10,7 @@ using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.Utilities;
using System;
using System.Collections.Generic;
using System.IO;
@ -117,6 +118,73 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
}
}
public IEnumerable<(int Offset, string Location, string Abbr)> ParseTzOffsets()
{
var tzBinaryContentPath = GetTimeZoneBinaryTitleContentPath();
if (string.IsNullOrEmpty(tzBinaryContentPath))
{
return new[] { (0, "UTC", "UTC") };
}
List<(int Offset, string Location, string Abbr)> outList = new List<(int Offset, string Location, string Abbr)>();
var now = System.DateTimeOffset.Now.ToUnixTimeSeconds();
using (IStorage ncaStorage = new LocalStorage(_virtualFileSystem.SwitchPathToSystemPath(tzBinaryContentPath), FileAccess.Read, FileMode.Open))
using (IFileSystem romfs = new Nca(_virtualFileSystem.KeySet, ncaStorage).OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel))
{
foreach (string locName in LocationNameCache)
{
if (locName.StartsWith("Etc"))
{
continue;
}
if (romfs.OpenFile(out IFile tzif, $"/zoneinfo/{locName}".ToU8Span(), OpenMode.Read).IsFailure())
{
Logger.PrintError(LogClass.ServiceTime, $"Error opening /zoneinfo/{locName}");
continue;
}
using (tzif)
{
TimeZone.ParseTimeZoneBinary(out TimeZoneRule tzRule, tzif.AsStream());
TimeTypeInfo ttInfo;
if (tzRule.TimeCount > 0) // Find the current transition period
{
int fin = 0;
for (int i = 0; i < tzRule.TimeCount; ++i)
{
if (tzRule.Ats[i] <= now)
{
fin = i;
}
}
ttInfo = tzRule.Ttis[tzRule.Types[fin]];
}
else if (tzRule.TypeCount >= 1) // Otherwise, use the first offset in TTInfo
{
ttInfo = tzRule.Ttis[0];
}
else
{
Logger.PrintError(LogClass.ServiceTime, $"Couldn't find UTC offset for zone {locName}");
continue;
}
var abbrStart = tzRule.Chars.AsSpan(ttInfo.AbbreviationListIndex);
int abbrEnd = abbrStart.IndexOf('\0');
outList.Add((ttInfo.GmtOffset, locName, abbrStart.Slice(0, abbrEnd).ToString()));
}
}
}
outList.Sort();
return outList;
}
private bool IsLocationNameValid(string locationName)
{
foreach (string cachedLocationName in LocationNameCache)