private async Task LoadConfigs()
        {
            if (configLoading)
            {
                return;
            }
            configLoading = true;
            try
            {
                var dir   = await HostedUtils.HostedConfigFolderTask;
                var files = await dir.GetFilesAsync();

                var configs = await Task.WhenAll(files.Select(f => HostedUtils.GetHostedConfigAsync(f)));

                hostedConfigListItems.Clear();
                foreach (var config in configs)
                {
                    hostedConfigListItems.Add(new HostedConfigListItem(config));
                }
            }
            catch (Exception ex)
            {
                await UiUtils.NotifyUser("Error loading hosted config list: " + ex.ToString());

                Frame.GoBack();
            }
            finally
            {
                configLoading = false;
            }
        }
        public async Task Rename(string newName)
        {
            HostedConfig.Name = newName;
            await HostedUtils.SaveHostedConfigAsync(HostedConfig);

            TriggerUpdate(HostedConfigChangedEventArgs);
        }
        public Task <Snapshot> UpdateAsync()
        {
            if (!LoadSnapshotTask.Task.IsCompleted)
            {
                return(LoadSnapshotTask.Task);
            }
            Snapshot oldSnapshot = null;

            if (LoadSnapshotTask.Task.Status == TaskStatus.RanToCompletion)
            {
                oldSnapshot = LoadSnapshotTask.Task.Result;
            }
            var task = HostedUtils.UpdateSnapshotAsync(HostedConfig, oldSnapshot);

            LoadSnapshotTask = new SnapshotTask()
            {
                Task = task
            };
            TriggerUpdate(LoadSnapshotTaskChangedEventArgs);
            _ = StartLoadTask(task);
            return(task);
        }
        private async Task AddSubscribeAsync()
        {
            var cancellationToken = LoadSnapshotCancellationSource.Token;
            var config            = new HostedConfig();

            // Create source
            switch (sourcePivot.SelectedIndex)
            {
            case 0:
                // URL
                if (string.IsNullOrWhiteSpace(urlText.Text))
                {
                    throw new OperationCanceledException("Empty input");
                }
                if (!Uri.IsWellFormedUriString(urlText.Text, UriKind.Absolute))
                {
                    throw new InvalidDataException("The URL is invalid");
                }
                var urlSource = new UrlSource()
                {
                    Url = urlText.Text
                };
                config.Source = urlSource;
                break;

            case 1:
                // File
                if (!(previewFileNameText.DataContext is StorageFile file))
                {
                    file = await FileOpenPicker.PickSingleFileAsync();
                }
                if (file == null)
                {
                    throw new InvalidDataException("No file is chosen");
                }
                config.Source = new FileSource(file);
                break;

            default:
                throw new NotSupportedException("The source type is not supported yet");
            }

            // Create format
            Snapshot snapshot;

            cancellationToken.ThrowIfCancellationRequested();
            switch (((NewHostedConfigType)hostedTypeGridView.SelectedItem).Id)
            {
            case "ssd":
                config.Format = new Ssd();
                break;

            case "clash":
                config.Format = new Clash();
                break;

            default:
                throw new NotSupportedException("The hosted config type is not supported yet");
            }
            using (var source = await config.Source.FetchAsync().AsTask(cancellationToken))
            {
                snapshot = await source.DecodeAsync(config.Format).AsTask(cancellationToken);
            }
            config.Name = config.Source.GetFileName();

            // Save
            cancellationToken.ThrowIfCancellationRequested();
            var configFile = await HostedUtils.SaveHostedConfigAsync(config);

            try
            {
                _ = CachedFileManager.CompleteUpdatesAsync(configFile);
                cancellationToken.ThrowIfCancellationRequested();
                // No need to update local file
                _ = await HostedUtils.SaveSnapshotAsync(snapshot, config);
            }
            catch (Exception)
            {
                // Rollback if snapshot is not saved
                await configFile.DeleteAsync();

                throw;
            }

            if (Frame.CanGoBack)
            {
                Frame.GoBack();
            }
            var newItem = new HostedConfigListItem(config, snapshot);
            await Task.Delay(300);

            HostedConfigListItems?.Add(newItem);
            await Task.Delay(800);

            HostedConfigListPage.itemForBackNavigation = newItem;
            Frame.Navigate(typeof(HostedConfigPage), newItem);
        }
 public HostedConfigListItem(HostedConfig config)
 {
     HostedConfig = config;
     _            = StartLoadTask(HostedUtils.GetSnapshotFromHostConfigAsync(config));
 }