Browse Source

add maintenance window

Melon 1 year ago
parent
commit
1647767d7b

+ 2 - 2
fisp.sln

@@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio Version 17
 VisualStudioVersion = 17.6.33723.286
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "libfisp", "libfisp\libfisp.csproj", "{1115A6B5-20DE-4574-BD8A-E546B2079C67}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "libfisp", "libfisp\libfisp.csproj", "{1115A6B5-20DE-4574-BD8A-E546B2079C67}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "fisp", "fisp\fisp.csproj", "{D993C152-6AED-4869-B97C-E0A6E9421941}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fisp", "fisp\fisp.csproj", "{D993C152-6AED-4869-B97C-E0A6E9421941}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+ 1 - 1
fisp/App.xaml

@@ -4,6 +4,6 @@
              xmlns:local="clr-namespace:fisp"
              StartupUri="MainWindow.xaml">
     <Application.Resources>
-         
+        <ResourceDictionary Source="pack://application:,,,/BusyIndicator;component/Theme/Default.xaml"/>
     </Application.Resources>
 </Application>

+ 55 - 50
fisp/MainWindow.xaml

@@ -3,65 +3,70 @@
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-        xmlns:local="clr-namespace:fisp.Controls"
+        xmlns:busyIndicator="https://github.com/moh3ngolshani/BusyIndicator"
         mc:Ignorable="d"
         Title="FLYINSONO PUBLISH TOOL" Height="200" Width="640" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" Loaded="OnLoaded">
-    <Grid>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="Auto" />
-        </Grid.RowDefinitions>
-        <StackPanel Margin="8" Grid.Row="0" Orientation="Horizontal">
-            <TextBlock Margin="0,4,4,4" Text="Target: " FontSize="14"></TextBlock>
-            <ComboBox x:Name="TargetMethod" Width="100" SelectedValue="Embedded" Height="32" Margin="0,0,8,0" Padding="4,4,4,4" VerticalContentAlignment="Center" SelectionChanged="ComboBox_SelectionChanged">
-                <ComboBoxItem Content="Embedded"></ComboBoxItem>
-                <ComboBoxItem Content="Public" ></ComboBoxItem>
-            </ComboBox>
-            <TextBlock VerticalAlignment="Center" Text="Folder:" FontSize="14"/>
-            <TextBox x:Name="SourceFolder" Height="32" Margin="8,0,0,0" Width="300" IsReadOnly="True" VerticalContentAlignment="Center" Padding="2" FontSize="14"/>
-            <Button Content="..." Width="64" Click="OnChooseSourceFolderClick"/>
-        </StackPanel>
-        <StackPanel Grid.Row="1" Margin="8" Orientation="Horizontal">
-            <TextBlock Margin="16,0,0,0" VerticalAlignment="Center" Text="Package Name:" FontSize="14"/>
-            <TextBox x:Name="PackageName" Margin="6" BorderBrush="Transparent" BorderThickness="0" IsReadOnly="true" Text="0.0.0.0" Foreground="YellowGreen" FontSize="18" TextChanged="PackageName_TextChanged"/>
-            <Button Content="Package" FontSize="14" Margin="8,0,8,0" Click="OnPackageClick"></Button>
-            <TextBlock x:Name="PackageConsole" Visibility="Collapsed" VerticalAlignment="Center" />
-        </StackPanel>
-        <!--CDN上传部分 Start-->
-        <Grid Grid.Row="2" x:Name="GridPublish" Visibility="Collapsed">
+    <busyIndicator:BusyMask x:Name="BusyIndicator" 
+                        IsBusy="False" 
+                        IndicatorType="ThreeDots" 
+                        BusyContent="Please wait..." 
+                        BusyContentMargin="0,20,0,0" 
+                        IsBusyAtStartup="False" >
+        <Grid>
             <Grid.RowDefinitions>
-                <RowDefinition Height="Auto" />
+                <RowDefinition Height="40" />
                 <RowDefinition Height="Auto" />
                 <RowDefinition Height="Auto" />
                 <RowDefinition Height="Auto" />
             </Grid.RowDefinitions>
-            <Grid Margin="8" Grid.Row="0">
+            <Button Grid.Row="0" x:Name="ButtonMaintenance" Content="Maintenance" Margin="8,8,8,8" Click="OnMaintenanceClick"></Button>
+            <StackPanel Margin="8" Grid.Row="1" Orientation="Horizontal">
+                <TextBlock Margin="0,4,4,4" Text="Target: " FontSize="14"></TextBlock>
+                <ComboBox x:Name="ComboBoxChannel" Width="100" SelectedValue="Embedded" Height="32" Margin="0,0,8,0" Padding="4,4,4,4" VerticalContentAlignment="Center" SelectionChanged="OnChannelSelectionChanged">
+                    <ComboBoxItem Content="Embedded"></ComboBoxItem>
+                    <ComboBoxItem Content="Public" ></ComboBoxItem>
+                </ComboBox>
+                <TextBlock VerticalAlignment="Center" Text="Folder:" FontSize="14"/>
+                <TextBox x:Name="SourceFolder" Height="32" Margin="8,0,0,0" Width="300" IsReadOnly="True" VerticalContentAlignment="Center" Padding="2" FontSize="14"/>
+                <Button Content="..." Width="64" Click="OnChooseSourceFolderClick"/>
+            </StackPanel>
+            <StackPanel Grid.Row="2" Margin="8" Orientation="Horizontal">
+                <TextBlock Margin="16,0,0,0" VerticalAlignment="Center" Text="Package Name:" FontSize="14"/>
+                <TextBox x:Name="PackageName" Margin="6" BorderBrush="Transparent" BorderThickness="0" IsReadOnly="true" Text="0.0.0.0" Foreground="YellowGreen" FontSize="18" TextChanged="OnPackageNameChanged"/>
+                <Button x:Name="ButtonPackage" Content="Package" FontSize="14" Margin="8,0,8,0" Click="OnPackageClick"></Button>
+                <TextBlock x:Name="PackageConsole" Visibility="Collapsed" VerticalAlignment="Center" />
+            </StackPanel>
+            <!--CDN上传部分 Start-->
+            <Grid Grid.Row="3" x:Name="GridPublish" Visibility="Collapsed">
                 <Grid.RowDefinitions>
-                    <RowDefinition Height="Auto"/>
-                    <RowDefinition Height="Auto"/>
-                    <RowDefinition Height="16"/>
-                    <RowDefinition Height="Auto"/>
-                    <RowDefinition Height="Auto"/>
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
+                    <RowDefinition Height="Auto" />
                 </Grid.RowDefinitions>
-                <TextBlock Grid.Row="0" Text="Uploading Progress" FontSize="18" FontWeight="Bold"/>
-                <StackPanel Grid.Row="1">
-                    <TextBlock Margin="0,4,4,4" x:Name="UploadingProgressText"/>
-                    <ProgressBar x:Name="UploadingProgress" Height="36"  VerticalAlignment="Center"/>
-                </StackPanel>
-                <TextBlock Grid.Row="3" Text="Total Progress" FontSize="18" FontWeight="Bold"/>
-                <StackPanel Grid.Row="4">
-                    <TextBlock Margin="0,4,4,4" x:Name="TotalProgressText"/>
-                    <ProgressBar x:Name="TotalProgress" Height="36"  VerticalAlignment="Center"/>
-                </StackPanel>
+                <Grid Margin="8" Grid.Row="0">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="Auto"/>
+                        <RowDefinition Height="Auto"/>
+                        <RowDefinition Height="16"/>
+                        <RowDefinition Height="Auto"/>
+                        <RowDefinition Height="Auto"/>
+                    </Grid.RowDefinitions>
+                    <TextBlock Grid.Row="0" Text="Uploading Progress" FontSize="18" FontWeight="Bold"/>
+                    <StackPanel Grid.Row="1">
+                        <TextBlock Margin="0,4,4,4" x:Name="UploadingProgressText"/>
+                        <ProgressBar x:Name="UploadingProgress" Height="36"  VerticalAlignment="Center"/>
+                    </StackPanel>
+                    <TextBlock Grid.Row="3" Text="Total Progress" FontSize="18" FontWeight="Bold"/>
+                    <StackPanel Grid.Row="4">
+                        <TextBlock Margin="0,4,4,4" x:Name="TotalProgressText"/>
+                        <ProgressBar x:Name="TotalProgress" Height="36"  VerticalAlignment="Center"/>
+                    </StackPanel>
+                </Grid>
+                <TextBox  Grid.Row="1" x:Name="PublishUrl" Margin="6" BorderBrush="Transparent" BorderThickness="0" IsReadOnly="true" Text="https://app.fis.plus/flyinsono20230711/" Foreground="Blue" FontSize="18"/>
+                <Button Grid.Row="2" x:Name="ButtonPublish" Height="48" Margin="8" Content="PUBLISH" VerticalAlignment="Center" FontSize="24" FontWeight="Bold" Click="OnPlulishClick"/>
             </Grid>
-            <TextBox  Grid.Row="1" x:Name="PublishUrl" Margin="6" BorderBrush="Transparent" BorderThickness="0" IsReadOnly="true" Text="https://app.fis.plus/flyinsono20230711/" Foreground="Blue" FontSize="18"/>
-            <Button Grid.Row="2" Height="48" Margin="8" Content="PUBLISH" VerticalAlignment="Center" FontSize="24" FontWeight="Bold" Click="OnPlulishClick"/>
+            <!--CDN上传部分 End-->
         </Grid>
-        <!--CDN上传部分 End-->
-        <Viewbox Grid.Row="3" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center">
-            <local:LoadingControl x:Name="Loading" Visibility="Visible"></local:LoadingControl>
-        </Viewbox>
-        <!--<local:Loading x:Name="Loading" Grid.Row="3"  Visibility="Visible"/>-->
-    </Grid>
+    </busyIndicator:BusyMask>
 </Window>

+ 55 - 27
fisp/MainWindow.xaml.cs

@@ -13,7 +13,7 @@ namespace fisp
     public partial class MainWindow : Window
     {
         private PackageHandler? packageHandler;
-        public bool IsEmbedded => TargetMethod.SelectedIndex == 0;
+        public bool IsEmbedded => ComboBoxChannel.SelectedIndex == 0;
 
         public MainWindow()
         {
@@ -22,9 +22,8 @@ namespace fisp
             UploadingProgress.Maximum = 100;
             TotalProgress.Minimum = 0;
             TotalProgress.Maximum = 100;
-            TargetMethod.SelectedIndex = 0;
+            ComboBoxChannel.SelectedIndex = 0;
             PublishUrl.Text = $"https://app.fis.plus/{PackageName.Text}/index.html";
-            Loading.Visibility = Visibility.Collapsed;
         }
 
         private void OnLoaded(object sender, RoutedEventArgs e)
@@ -68,17 +67,19 @@ namespace fisp
             }
 
             HideBusy();
+
+            MessageBox.Show("Package successed!", "Package result", MessageBoxButton.OK, MessageBoxImage.Information);
         }
 
         private void OnPlulishClick(object sender, RoutedEventArgs e)
         {
             if (packageHandler == null) return;
 
-            ShowBusy();
+            LockActions();
             libfisp.fisp publisher = new libfisp.fisp();
             try
             {
-                var task = publisher.UploadDir(packageHandler.DistFolder, PackageName.Text);
+                var task = publisher.UploadDir(packageHandler.DistFolder, packageHandler.FullBuildName);
                 task.UploadingProgress += (s, e) =>
                 {
                     Dispatcher.Invoke(() =>
@@ -99,7 +100,7 @@ namespace fisp
                 {
                     Dispatcher.Invoke(() =>
                     {
-                        HideBusy();
+                        UnlockActions();
                         MessageBox.Show("Publish successed!", "Publish result", MessageBoxButton.OK, MessageBoxImage.Information);
                     });
                 };
@@ -107,19 +108,19 @@ namespace fisp
                 {
                     Dispatcher.Invoke(() =>
                     {
-                        HideBusy();
+                        UnlockActions();
                         MessageBox.Show($"Publish failed:\n\n{m}", "Publish result", MessageBoxButton.OK, MessageBoxImage.Error);
                     });
                 };
             }
             catch (Exception ex)
             {
-                HideBusy();
+                UnlockActions();
                 MessageBox.Show($"Publish failed:\n\n{ex}", "Publish result", MessageBoxButton.OK, MessageBoxImage.Error);
             }
         }
 
-        private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        private void OnChannelSelectionChanged(object sender, SelectionChangedEventArgs e)
         {
             HidePublishPanel();
             PackageConsole.Visibility = Visibility.Collapsed;
@@ -129,7 +130,7 @@ namespace fisp
             }
         }
 
-        private void PackageName_TextChanged(object sender, TextChangedEventArgs e)
+        private void OnPackageNameChanged(object sender, TextChangedEventArgs e)
         {
             if (PublishUrl != null)
             {
@@ -137,42 +138,69 @@ namespace fisp
             }
         }
 
-        private void OnOpenDistFolder(object sender, EventArgs e)
+        private void OnMaintenanceClick(object sender, EventArgs e)
         {
-            try
-            {
-                Process.Start(PackageHandler.WORKSPACE);
-            }
-            catch (Exception)
-            {
-            }
+            new MaintenanceWindow().ShowDialog();
         }
 
+        /// <summary>
+        /// 显示推送面板
+        /// </summary>
         private void ShowPublishPanel()
         {
-            GridPublish.Visibility = Visibility.Visible;
-            Height = 440;
+            if (GridPublish.Visibility != Visibility.Visible)
+            {
+                GridPublish.Visibility = Visibility.Visible;
+                Height = 480;
+            }
+
             PublishUrl.Text = $"https://app.fis.plus/{PackageName.Text}/index.html";
         }
 
+        /// <summary>
+        /// 隐藏推送面板
+        /// </summary>
         private void HidePublishPanel()
         {
-            GridPublish.Visibility = Visibility.Collapsed;
-            Height = 200;
+            if (GridPublish.Visibility == Visibility.Visible)
+            {
+                GridPublish.Visibility = Visibility.Collapsed;
+                Height = 200;
+            }
         }
 
         private void ShowBusy()
         {
-            SourceFolder.IsEnabled = false;
-            TargetMethod.IsEnabled = false;
-            Loading.Visibility = Visibility.Visible;
+            BusyIndicator.IsBusy = true;
         }
 
         private void HideBusy()
+        {
+            BusyIndicator.IsBusy = false;
+        }
+
+        /// <summary>
+        /// 锁住所用操作
+        /// </summary>
+        private void LockActions()
+        {
+            SourceFolder.IsEnabled = false;
+            ComboBoxChannel.IsEnabled = false;
+            ButtonPackage.IsEnabled = false;
+            ButtonMaintenance.IsEnabled = false;
+            ButtonPublish.IsEnabled = false;
+        }
+
+        /// <summary>
+        /// 解锁所有操作
+        /// </summary>
+        private void UnlockActions()
         {
             SourceFolder.IsEnabled = true;
-            TargetMethod.IsEnabled = true;
-            Loading.Visibility = Visibility.Collapsed;
+            ComboBoxChannel.IsEnabled = true;
+            ButtonPackage.IsEnabled = true;
+            ButtonMaintenance.IsEnabled = true;
+            ButtonPublish.IsEnabled = true;
         }
     }
 }

+ 41 - 0
fisp/MaintenanceWindow.xaml

@@ -0,0 +1,41 @@
+<Window x:Class="fisp.MaintenanceWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:fisp" 
+        xmlns:busyIndicator="https://github.com/moh3ngolshani/BusyIndicator"
+        mc:Ignorable="d"
+        Title="Maintenance" Height="600" Width="400"
+         ResizeMode="NoResize" WindowStartupLocation="CenterScreen"
+        Loaded="OnLoaded" Unloaded="OnUnloaded">
+    <busyIndicator:BusyMask x:Name="BusyIndicator" 
+                        IsBusy="False" 
+                        IndicatorType="ThreeDots" 
+                        BusyContent="Please wait..." 
+                        BusyContentMargin="0,20,0,0" 
+                        IsBusyAtStartup="False" >
+        <Grid>
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto"/>
+                <RowDefinition Height="*"/>
+            </Grid.RowDefinitions>
+            <TextBlock Margin="8" Text="Online Folders:" FontSize="14" FontWeight="Bold"/>
+            <ListBox Grid.Row="1" x:Name="OnlineFolderList" Margin="8,0,8,8" HorizontalContentAlignment="Stretch">
+                <ListBox.ItemTemplate>
+                    <DataTemplate>
+                        <Grid HorizontalAlignment="Stretch">
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition Width="*"/>
+                                <ColumnDefinition Width="48"/>
+                            </Grid.ColumnDefinitions>
+                            <TextBlock Grid.Column="0" Text="{Binding}" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Left"/>
+                            <TextBlock Text="Delete" HorizontalAlignment="Center" FontSize="12" TextDecorations="Underline" Cursor="Hand"  Foreground="Red" VerticalAlignment="Center" Grid.Column="1" MouseDown="OnDeleteClick"/>
+                        </Grid>
+                    </DataTemplate>
+                </ListBox.ItemTemplate>
+            </ListBox>
+            <Border Width="0.5" Grid.Row="0" Background="Gray" Grid.RowSpan="2" HorizontalAlignment="Left"/>
+        </Grid>
+    </busyIndicator:BusyMask>
+</Window>

+ 106 - 0
fisp/MaintenanceWindow.xaml.cs

@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace fisp
+{
+    /// <summary>
+    /// MaintenanceWindow.xaml 的交互逻辑
+    /// </summary>
+    public partial class MaintenanceWindow : Window
+    {
+        private bool _maintenanceOn;
+
+        public MaintenanceWindow()
+        {
+            InitializeComponent();
+        }
+
+        private void OnLoaded(object sender, RoutedEventArgs e)
+        {
+            BusyIndicator.IsBusy = true;
+            Task.Run(() =>
+            {
+                libfisp.fisp publisher = new libfisp.fisp();
+                try
+                {
+                    var folders = publisher.ListFolders(string.Empty);
+                    Dispatcher.Invoke(() =>
+                    {
+                        foreach (var folder in folders)
+                        {
+                            OnlineFolderList.Items.Add(folder.Replace("/", ""));
+                        }
+                        BusyIndicator.IsBusy = false;
+                    });
+                }
+                catch (Exception ex)
+                {
+                    Dispatcher.Invoke(() =>
+                    {
+                        BusyIndicator.IsBusy = false;
+                        MessageBox.Show(this, $"Load online folders failed:\n\n{ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
+                    });
+                }
+            });
+        }
+
+        private void OnUnloaded(object sender, RoutedEventArgs e)
+        {
+            OnlineFolderList.Items.Clear();
+        }
+
+        private void OnDeleteClick(object sender, MouseButtonEventArgs e)
+        {
+            var obj = (TextBlock)sender;
+            var folder = (string)obj.DataContext;
+            if (MessageBox.Show(this, "Are you sure you want to delete this folder?", "Warning", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
+            {
+                BusyIndicator.IsBusy = true;
+                libfisp.fisp publisher = new libfisp.fisp();
+                try
+                {
+                    var task = publisher.DeleteFolder(folder + "/");
+                    task.Progress += (s, e) =>
+                    {
+                        Dispatcher.Invoke(() =>
+                        {
+                            BusyIndicator.BusyContent = $"Deleting folder {folder} ... {(int)e}%";
+                        });
+                    };
+                    task.Successed += (s, e) =>
+                    {
+                        Dispatcher.Invoke(() =>
+                        {
+                            OnlineFolderList.Items.Remove(folder);
+                            BusyIndicator.IsBusy = false;
+                        });
+                    };
+                    task.Failed += (s, m) =>
+                    {
+                        Dispatcher.Invoke(() =>
+                        {
+                            BusyIndicator.IsBusy = false;
+                            MessageBox.Show(this, $"Delete folder {folder} failed:\n\n{m}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
+                        });
+                    };
+                }
+                catch (Exception ex)
+                {
+                    BusyIndicator.IsBusy = false;
+                    MessageBox.Show(this, $"Delete folder {folder} failed:\n\n{ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
+                }
+            }
+        }
+    }
+}

+ 11 - 2
fisp/PackageHandler.cs

@@ -16,7 +16,8 @@ namespace fisp
     internal class PackageHandler
     {
         public const string WORKSPACE = "C:/WebPublishWorkspace";
-        private const string CDN_ROOT = "https://static.fis.plus/flyinsono/";
+        private const string CDN_ROOT = "https://app.fis.plus/";
+        private const string GOOGLE_FONTS_CDN = "https://static.fis.plus/flyinsono/GoogleFonts/";
         private static string GOOGLE_FONT_PATH = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources/GoogleFonts.zip");
 
         private FlutterVersionModel? _versionModel;
@@ -66,6 +67,10 @@ namespace fisp
             }
         }
 
+        /// <summary>
+        /// 打包前处理
+        /// </summary>
+        /// <returns></returns>
         internal async Task Handle()
         {
             CreateCleanFolder(DistFolder);
@@ -82,6 +87,10 @@ namespace fisp
             await UpdateIndexLinks();
         }
 
+        /// <summary>
+        /// 打包 - 创建Zip包
+        /// </summary>
+        /// <returns></returns>
         internal async Task GenerateZip()
         {
             await Task.Run(() =>
@@ -120,7 +129,7 @@ namespace fisp
         {
             // example: https://static.fis.plus/flyinsono/GoogleFonts/notoemoji/v32/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob-r0jwvS-FGJCMY.ttf
 
-            var staticRoot = IsEmbedded ? "./GoogleFonts/" : $"{CDN_ROOT}GoogleFonts/";
+            var staticRoot = IsEmbedded ? "./GoogleFonts/" : GOOGLE_FONTS_CDN;
             var filePath = Path.Combine(DistFolder, "main.dart.js");
             string content = File.ReadAllText(filePath, Encoding.UTF8);
 

+ 1 - 0
fisp/fisp.csproj

@@ -8,6 +8,7 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <PackageReference Include="BusyIndicators" Version="2.1.2" />
     <PackageReference Include="WindowsAPICodePack.Shell.CommonFileDialogs.Wpf" Version="1.1.5" />
   </ItemGroup>
 

+ 6 - 0
fisp/fisp.csproj.user

@@ -5,10 +5,16 @@
     <Compile Update="Controls\LoadingControl.xaml.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Update="MaintenanceWindow.xaml.cs">
+      <SubType>Code</SubType>
+    </Compile>
   </ItemGroup>
   <ItemGroup>
     <Page Update="Controls\LoadingControl.xaml">
       <SubType>Designer</SubType>
     </Page>
+    <Page Update="MaintenanceWindow.xaml">
+      <SubType>Designer</SubType>
+    </Page>
   </ItemGroup>
 </Project>

+ 26 - 0
libfisp/DeleteTask.cs

@@ -0,0 +1,26 @@
+namespace libfisp
+{
+    public class DeleteTask
+    {
+        public event EventHandler<double>? Progress;
+
+        public event EventHandler? Successed;
+
+        public event EventHandler<string>? Failed;
+
+        internal void UpdateProgress(double progress)
+        {
+            Progress?.Invoke(this, progress);
+        }
+
+        internal void UpdateSuccess()
+        {
+            Successed?.Invoke(this, EventArgs.Empty);
+        }
+
+        internal void UpdateFailed(string message)
+        {
+            Failed?.Invoke(this, message);
+        }
+    }
+}

+ 80 - 1
libfisp/fisp.cs

@@ -1,6 +1,8 @@
 using COSXML;
 using COSXML.Auth;
+using COSXML.Model.Object;
 using COSXML.Transfer;
+using static COSXML.Model.Tag.ListAllMyBuckets;
 
 namespace libfisp
 {
@@ -17,6 +19,8 @@ namespace libfisp
 
             var config = new CosXmlConfig.Builder()
                 .SetRegion(region)
+                .SetConnectionTimeoutMs(10000)
+                .SetReadWriteTimeoutMs(10000)
                 .SetDebugLog(true)
                 .Build();
 
@@ -49,6 +53,75 @@ namespace libfisp
             }
         }
 
+        public List<string> ListFolders(string prefix)
+        {
+            var request = new COSXML.Model.Bucket.GetBucketRequest(_bucket);
+            if (!string.IsNullOrEmpty(prefix))
+            {
+                request.SetPrefix(prefix);
+            }
+            request.SetDelimiter("/");
+            var result = _cosXml.GetBucket(request);
+            if (result.IsSuccessful())
+            {
+                return result.listBucket.commonPrefixesList.Select(x => x.prefix).ToList();
+            }
+            else
+            {
+                throw new InvalidOperationException("List bucket failed.");
+            }
+        }
+
+        public DeleteTask DeleteFolder(string folderName)
+        {
+            var deleteTask = new DeleteTask();
+            Task.Run(() =>
+            {
+                try
+                {
+                    var isSuccess = true;
+                    var getRequest = new COSXML.Model.Bucket.GetBucketRequest(_bucket);
+                    getRequest.SetPrefix(folderName);
+                    var getResult = _cosXml.GetBucket(getRequest);
+                    if (getResult.IsSuccessful())
+                    {
+                        var files = getResult.listBucket.contentsList.Select(x => x.key).ToArray();
+                        for (var i = 0; i < files.Length; i++)
+                        {
+                            var file = files[i];
+                            var deleteRequest = new DeleteObjectRequest(_bucket, file);
+                            var deleteResult = _cosXml.DeleteObject(deleteRequest);
+                            if (deleteResult.IsSuccessful())
+                            {
+                                deleteTask.UpdateProgress((i + 1) * 100 / files.Length);
+                            }
+                            else
+                            {
+                                deleteTask.UpdateFailed(deleteResult.GetResultInfo());
+                                isSuccess = false;
+                                break;
+                            }
+                        }
+                        if (isSuccess)
+                        {
+                            deleteTask.UpdateSuccess();
+                        }
+                    }
+                    else
+                    {
+                        deleteTask.UpdateFailed("List folders failed.");
+                    }
+                }
+                catch (Exception ex)
+                {
+                    deleteTask.UpdateFailed(ex.Message);
+                }
+            });
+            return deleteTask;
+            
+
+        }
+
         private Dictionary<string, string> GetDirFiles(DirectoryInfo dirInfo, string parentDirName)
         {
             var files = new Dictionary<string, string>();
@@ -70,6 +143,7 @@ namespace libfisp
             return files;
         }
 
+
         public UploadTask UploadFile(string file, string fileName)
         {
             var uploadTask = new UploadTask();
@@ -95,6 +169,7 @@ namespace libfisp
             var uploadTask = new UploadTask();
             Task.Run(async () =>
             {
+                bool isSuccess = true;
                 var files = uploadFiles.Keys.ToArray();
                 for(var i=0;i< files.Length; i++)
                 {
@@ -108,10 +183,14 @@ namespace libfisp
                     else
                     {
                         uploadTask.UpdateFailed(result);
+                        isSuccess = false;
                         break;
                     }
                 }
-                uploadTask.UpdateSuccess();
+                if (isSuccess)
+                {
+                    uploadTask.UpdateSuccess();
+                }
             });
             return uploadTask;
         }