/// <summary>
        /// Processes valid assets to know which buttons to display
        /// </summary>
        /// <returns></returns>
        public async Task ProcessAssets(ContentType storageType, string pathToCheckWith, string storageLocationBase, FGORegion region)
        {
            List <string> validSha = new List <string>();

            _translations?.Clear();
            _guiObjects?.Clear();

            var installedScriptString = Preferences.Get($"InstalledScript_{region}", null);

            if (installedScriptString != null)
            {
                _installedBundle = JsonConvert.DeserializeObject <TranslationList>(installedScriptString);

                foreach (var scriptBundle in _installedBundle.Scripts)
                {
                    validSha.Add(scriptBundle.Value.TranslatedSHA1); // Add existing
                }
            }
            else
            {
                _installedBundle = null;
            }

            foreach (var scriptBundleSet in _handshake.Response.Translations)
            {
                foreach (var scriptBundle in scriptBundleSet.Scripts)
                {
                    validSha.Add(scriptBundle.Value.TranslatedSHA1); // Add all valid sha1s
                }
            }

            if (_handshake.Response.Translations.Count > 0)
            {
                foreach (var scriptBundleSet in _handshake.Response.Translations)
                {
                    ConcurrentBag <Tuple <long, long> > results = new ConcurrentBag <Tuple <long, long> >();

                    await scriptBundleSet.Scripts.ParallelForEachAsync(async scriptBundle =>
                    {
                        // Check hashes
                        var filePath = Path.Combine(pathToCheckWith, scriptBundle.Key);

                        var fileContentsResult = await _cm.GetFileContents(storageType, filePath, storageLocationBase);

                        if (scriptBundle.Key.Contains('/') || scriptBundle.Key.Contains('\\')) // for security purposes, don't allow directory traversal
                        {
                            throw new FileNotFoundException();
                        }


                        TranslationFileStatus status;

                        var fileNotExists = fileContentsResult.Error == FileErrorCode.NotExists;
                        if (!fileNotExists)
                        {
                            var sha1 = ScriptUtil.Sha1(fileContentsResult.FileContents); // SHA of file currently in use

                            if (sha1 == scriptBundle.Value.GameSHA1)                     // Not modified
                            {
                                status = TranslationFileStatus.NotModified;
                            }
                            else if (sha1 == scriptBundle.Value.TranslatedSHA1) // English is installed
                            {
                                status = TranslationFileStatus.Translated;
                            }
                            else if (validSha.Contains(sha1) && (_installedBundle == null || (_installedBundle != null && scriptBundleSet.Group != _installedBundle.Group)))
                            {
                                status = TranslationFileStatus.DifferentTranslation;
                            }
                            else if (_installedBundle != null && scriptBundleSet.Group == _installedBundle.Group)
                            {
                                status = TranslationFileStatus.UpdateAvailable;
                            }
                            else
                            {
                                status = TranslationFileStatus.Invalid;
                            }
                        }
                        else
                        {
                            status = TranslationFileStatus.Missing;
                        }

                        scriptBundle.Value.Status = status;

                        results.Add(new Tuple <long, long>(scriptBundle.Value.LastModified, scriptBundle.Value.Size));
                    }, maxDegreeOfParallelism : 4);

                    long lastModified = results.Max(m => m.Item1);
                    long totalSize    = results.Sum(s => s.Item2);

                    scriptBundleSet.TotalSize = totalSize;
                    _translations.Add(scriptBundleSet.Group, scriptBundleSet);
                    var statusString = InstallerUtil.GenerateStatusString(scriptBundleSet.Scripts);
                    var timespan     = DateTime.UtcNow.Subtract(DateTime.SpecifyKind(DateTimeOffset.FromUnixTimeSeconds((long)lastModified).DateTime,
                                                                                     DateTimeKind.Utc));
                    var  lastUpdated  = InstallerUtil.PeriodOfTimeOutput(timespan);
                    bool enableButton = statusString.Item1 != AppResources.StatusInstalled;
                    var  i1           = scriptBundleSet.Group;

                    if (!scriptBundleSet.Hidden)
                    {
                        _guiObjects.Add(new TranslationGUIObject()
                        {
                            BundleID       = scriptBundleSet.Group,
                            BundleHidden   = scriptBundleSet.Hidden,
                            InstallEnabled = enableButton,
                            InstallClick   = new Command(async() => await Install(region, i1),
                                                         () => enableButton && ButtonsEnabled),
                            Name              = scriptBundleSet.Name,
                            Status            = statusString.Item1,
                            TextColor         = statusString.Item2,
                            LastUpdated       = lastUpdated,
                            ButtonInstallText = statusString.Item1 != AppResources.StatusInstalled
                                ? AppResources.InstallText
                                : AppResources.InstalledText
                        });
                    }
                }

                LoadTranslationList();
            }
            else
            {
                LoadingText.Text = String.Format(AppResources.NoScriptsAvailable);
                SwitchErrorObjects(true);
                return;
            }
        }
        public async Task UpdateTranslationList()
        {
            _cm.ClearCache();
            if (_isCurrentlyUpdating)
            {
                return;
            }
            _isCurrentlyUpdating = true;

            try
            {
                ReleaseScheduleLayout.IsVisible = false;
                RetryButton.IsVisible           = false;
                LoadingLayout.IsVisible         = true;
                TranslationListView.IsVisible   = false;
                MasterButtons.IsVisible         = false;
                Refresh.IsRefreshing            = true;
                //SwitchButtons(false);
                SwitchErrorObjects(false);
                ActivityIndicatorLoading.IsRunning = true;
                Refresh.IsEnabled = false;
                RevertButton.Text = AppResources.UninstallText;
                ActivityIndicatorLoading.VerticalOptions   = LayoutOptions.Center;
                ActivityIndicatorLoading.HorizontalOptions = LayoutOptions.Center;

                LoadingText.Text              = AppResources.LoadingPleaseWait;
                LoadingText.VerticalOptions   = LayoutOptions.CenterAndExpand;
                LoadingText.HorizontalOptions = LayoutOptions.CenterAndExpand;

                //await Task.Delay(1000);


                _storageLocation = Preferences.Get("StorageLocation", "");

                if (!string.IsNullOrEmpty(_storageLocation) || !_cm.CheckBasicAccess())
                {
                    _android11Access = true;
                }

                if (!_android11Access)
                {
                    _installedFgoInstances = _cm.GetInstalledGameApps(ContentType.DirectAccess);
                }
                else
                {
                    _installedFgoInstances = _cm.GetInstalledGameApps(ContentType.StorageFramework, _storageLocation);
                }

                //TranslationName.Text = Region == FGORegion.Jp
                //? String.Format(AppResources.InstallerTitle, "JP") + $": {handshake.Data.Response.AppVer}"
                //: String.Format(AppResources.InstallerTitle, "NA") + $": {handshake.Data.Response.AppVer}";

                // Check region is installed
                if (_installedFgoInstances.All(w => w.Region != Region))
                {
                    LoadingText.Text = String.Format(AppResources.NoFGOFound,
                                                     $"Fate/Grand Order {Region.ToString().ToUpper()}");
                    SwitchErrorObjects(true);
                    return;
                }

                foreach (var instance in _installedFgoInstances.ToList())
                {
                    var filePath = _android11Access
                        ? $"data/{instance.Path}/files/data/d713/{_assetList}"
                        : $"{instance.Path}/files/data/d713/{_assetList}";
                    var assetStorage = await _cm.GetFileContents(
                        _android11Access?ContentType.StorageFramework : ContentType.DirectAccess,
                        filePath, _storageLocation);


                    if (!assetStorage.Successful)
                    {
                        _installedFgoInstances.Remove(instance);
                    }

                    instance.LastModified = assetStorage.LastModified;

                    if (assetStorage?.FileContents != null)
                    {
                        var base64 = "";
                        using var inputStream = new MemoryStream(assetStorage.FileContents);
                        using (var reader = new StreamReader(inputStream, Encoding.ASCII))
                        {
                            base64 = await reader.ReadToEndAsync();
                        }

                        instance.AssetStorage = base64;
                    }
                    else
                    {
                        instance.AssetStorage = null;
                    }
                }

                var instanceDict =
                    _installedFgoInstances.OrderByDescending(o => o.LastModified).FirstOrDefault(w => w.Region == Region);

                if (instanceDict == null)
                {
                    LoadingText.Text = String.Format(AppResources.NoFGOInstallationFound2,
                                                     $"Fate/Grand Order {Region.ToString().ToUpper()}");
                    SwitchErrorObjects(true);
                    return;
                }

                var rest      = new RestfulAPI();
                var handshake = await rest.GetHandshakeApiResponse(Region, instanceDict.AssetStorage);

                _handshake = handshake.Data;


                if (handshake.Data == null || handshake.Data.Status != 200)
                {
                    LoadingText.Text = handshake.Data == null
                        ? AppResources.TryAgainLater
                        : $"{AppResources.TranslateAPIError}\n{handshake.Data?.Message}";
                    SwitchErrorObjects(true);
                    return;
                }

                if (handshake.Data.Response.AssetStatus != HandshakeAssetStatus.Missing &&
                    handshake.Data.Response.AssetStatus != HandshakeAssetStatus.UpToDate)
                {
                    var warningTitle = AppResources.Warning + $" ({Region.ToString().ToUpper()})";
                    switch (handshake.Data.Response.AssetStatus)
                    {
                    case HandshakeAssetStatus.Missing:
                        break;

                    case HandshakeAssetStatus.UpToDate:
                        break;

                    case HandshakeAssetStatus.UpdateRequired:
                        await DisplayAlert(warningTitle, AppResources.AssetWarningOutOfDate, AppResources.OK);

                        break;

                    case HandshakeAssetStatus.TimeTraveler:
                        await DisplayAlert(warningTitle, AppResources.AssetWarningFutureUnreleased, AppResources.OK);

                        break;

                    case HandshakeAssetStatus.Unrecognized:
                        await DisplayAlert(warningTitle, AppResources.AssetWarningUnrecognised, AppResources.OK);

                        break;

                    case HandshakeAssetStatus.Corrupt:
                        await DisplayAlert(warningTitle, AppResources.AssetWarningCorrupted, AppResources.OK);

                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }

                var baseFilePath = _android11Access
                    ? $"data/{instanceDict.Path}/files/data/d713/"
                    : $"{instanceDict.Path}/files/data/d713/";


                await ProcessAssets(_android11Access?ContentType.StorageFramework : ContentType.DirectAccess,
                                    baseFilePath, _storageLocation, Region);

                // Add top bar
                if (_handshake.Response.LiveStatus != null && _handshake.Response.LiveStatus.Enabled)
                {
                    ReleaseScheduleLayout.IsVisible = true;
                    ReleaseScheduleChapter.Text     = _handshake.Response.LiveStatus.CurrentRelease;
                    if (_handshake.Response.LiveStatus.NextReleaseDate < DateTime.UtcNow)
                    {
                        DisplayNextUpdateTime.IsVisible = false;
                    }
                    else
                    {
                        var timespan    = _handshake.Response.LiveStatus.NextReleaseDate.Subtract(DateTime.UtcNow);
                        var lastUpdated = InstallerUtil.PeriodOfTimeOutput(timespan, 0, "");
                        ReleaseScheduleTimeRemaining.Text = lastUpdated;
                    }

                    ReleaseSchedulePercent.Text = _handshake.Response.LiveStatus.PercentDone;
                    ReleaseScheduleTitle.Text   = _handshake.Response.LiveStatus.Title;

                    var announcementJson = Preferences.Get("AnnouncementData", null);

                    if (announcementJson != null)
                    {
                        var json =
                            JsonConvert.DeserializeObject <VersionAPIResponse.TranslationAnnouncements>(
                                announcementJson);

                        if (json.IsSpecialAnnouncement)
                        {
                            ReleaseTap.Tapped += OpenAnnouncementOnClicked;
                        }
                    }
                }


                LoadingLayout.IsVisible       = false;
                TranslationListView.IsVisible = true;
                MasterButtons.IsVisible       = true;
                Refresh.IsRefreshing          = false;
                SwitchErrorObjects(false);
                ActivityIndicatorLoading.IsRunning = false;
                Refresh.IsEnabled = true;
                SwitchButtons(true);
            }
            catch (Exception ex)
            {
                await DisplayAlert(AppResources.InternalError,
                                   String.Format(AppResources.InternalErrorDetails, ex.ToString()), AppResources.OK);

                _isCurrentlyUpdating = false;
                SwitchErrorObjects(true);
            }

            _isCurrentlyUpdating = false;
        }