完成用户空间界面UI;完成投稿页面UI;修复已知问题

pull/252/head
leiurayer 3 years ago
parent f42191b5da
commit 3afc5e010f

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2021 FlySelfLog
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -1,6 +1,7 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" <ResourceDictionary
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:DownKyi.ui.images"> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.ui.images">
<DrawingImage x:Key="bilibiliDrawingImage"> <DrawingImage x:Key="bilibiliDrawingImage">
<DrawingImage.Drawing> <DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V1024 H2250 V0 H0 Z"> <DrawingGroup ClipGeometry="M0,0 V1024 H2250 V0 H0 Z">

@ -230,6 +230,20 @@ namespace DownKyi.Core.BiliApi.Users
#endregion #endregion
#region 合集和列表
// TODO
// https://api.bilibili.com/x/polymer/space/seasons_series_list?mid=27899754&page_num=1&page_size=18
// page_size最大值为20
// https://api.bilibili.com/x/polymer/space/seasons_archives_list?mid=23947287&season_id=665&sort_reverse=false&page_num=1&page_size=30
// https://api.bilibili.com/x/series/archives?mid=27899754&series_id=1253087&only_normal=true&sort=desc&pn=1&ps=30
// https://api.bilibili.com/x/series/archives?mid=27899754&series_id=1253087&only_normal=true&sort=asc&pn=1&ps=30
// https://api.bilibili.com/x/series/series?series_id=1253087
#endregion
#region 课程 #region 课程
/// <summary> /// <summary>

@ -164,6 +164,7 @@ namespace DownKyi
containerRegistry.RegisterForNavigation<ViewUserSpace>(ViewUserSpaceViewModel.Tag); containerRegistry.RegisterForNavigation<ViewUserSpace>(ViewUserSpaceViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewMySpace>(ViewMySpaceViewModel.Tag); containerRegistry.RegisterForNavigation<ViewMySpace>(ViewMySpaceViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewPublicFavorites>(ViewPublicFavoritesViewModel.Tag); containerRegistry.RegisterForNavigation<ViewPublicFavorites>(ViewPublicFavoritesViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewPublication>(ViewPublicationViewModel.Tag);
// downloadManager pages // downloadManager pages
containerRegistry.RegisterForNavigation<ViewDownloading>(ViewDownloadingViewModel.Tag); containerRegistry.RegisterForNavigation<ViewDownloading>(ViewDownloadingViewModel.Tag);
@ -197,6 +198,8 @@ namespace DownKyi
/// <param name="callback"></param> /// <param name="callback"></param>
public static void PropertyChangeAsync(Action callback) public static void PropertyChangeAsync(Action callback)
{ {
if (Current == null) { return; }
Current.Dispatcher.Invoke(callback); Current.Dispatcher.Invoke(callback);
} }

@ -0,0 +1,352 @@
<UserControl
x:Class="DownKyi.CustomControl.CustomPager"
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:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:DownKyi.CustomControl"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.Resources>
<DrawingImage x:Key="ToLeftDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V1024 H1024 V0 H0 Z">
<DrawingGroup.Transform>
<TranslateTransform X="0" Y="1.7763568394002505E-15" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="#FF666666" Geometry="F1 M1024,1024z M0,0z M345.49,512L778.27,80.69Q791.47,66.02 791.47,46.95 791.47,27.88 777.54,13.94 763.6,-1.77635683940025E-15 744.53,-1.77635683940025E-15 725.46,-1.77635683940025E-15 710.79,14.67L247.2,478.26Q232.53,492.93 232.53,512 232.53,531.07 247.2,545.74L710.79,1009.33Q725.46,1024 744.53,1024 763.6,1024 777.54,1010.07 791.47,996.13 791.47,977.06 791.47,957.98 778.27,943.31L345.49,512z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ToLeftHoverDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V1024 H1024 V0 H0 Z">
<DrawingGroup.Transform>
<TranslateTransform X="0" Y="1.7763568394002505E-15" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="#FF00A1D6" Geometry="F1 M1024,1024z M0,0z M345.49,512L778.27,80.69Q791.47,66.02 791.47,46.95 791.47,27.88 777.54,13.94 763.6,-1.77635683940025E-15 744.53,-1.77635683940025E-15 725.46,-1.77635683940025E-15 710.79,14.67L247.2,478.26Q232.53,492.93 232.53,512 232.53,531.07 247.2,545.74L710.79,1009.33Q725.46,1024 744.53,1024 763.6,1024 777.54,1010.07 791.47,996.13 791.47,977.06 791.47,957.98 778.27,943.31L345.49,512z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ToRightDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V1024 H1024 V0 H0 Z">
<DrawingGroup.Transform>
<TranslateTransform X="0" Y="1.7763568394002505E-15" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="#FF666666" Geometry="F1 M1024,1024z M0,0z M678.51,512L245.73,80.69Q232.53,66.02 232.53,46.95 232.53,27.88 246.46,13.94 260.4,-1.77635683940025E-15 279.47,-1.77635683940025E-15 298.54,-1.77635683940025E-15 313.21,14.67L776.8,478.26Q791.47,492.93 791.47,512 791.47,531.07 776.8,545.74L313.21,1009.33Q298.54,1024 279.47,1024 260.4,1024 246.46,1010.07 232.53,996.13 232.53,977.06 232.53,957.98 245.73,943.31L678.51,512z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ToRightHoverDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V1024 H1024 V0 H0 Z">
<DrawingGroup.Transform>
<TranslateTransform X="0" Y="1.7763568394002505E-15" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="#FF00A1D6" Geometry="F1 M1024,1024z M0,0z M678.51,512L245.73,80.69Q232.53,66.02 232.53,46.95 232.53,27.88 246.46,13.94 260.4,-1.77635683940025E-15 279.47,-1.77635683940025E-15 298.54,-1.77635683940025E-15 313.21,14.67L776.8,478.26Q791.47,492.93 791.47,512 791.47,531.07 776.8,545.74L313.21,1009.33Q298.54,1024 279.47,1024 260.4,1024 246.46,1010.07 232.53,996.13 232.53,977.06 232.53,957.98 245.73,943.31L678.51,512z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<Style x:Key="pagerBorder" TargetType="{x:Type Border}">
<Setter Property="Background" Value="#FFFFFFFF" />
<Setter Property="BorderBrush" Value="#FFD7DDE4" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="4" />
<Setter Property="Width" Value="30" />
<Setter Property="Height" Value="30" />
<Setter Property="Cursor" Value="Hand" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="#FF00A1D6" />
</Trigger>
<Trigger Property="IsMouseOver" Value="false">
<Setter Property="BorderBrush" Value="#FFD7DDE4" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="pagerButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="#FFFFFFFF" />
<Setter Property="BorderBrush" Value="#FFD7DDE4" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Width" Value="30" />
<Setter Property="Height" Value="30" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4">
<ContentPresenter
Name="content"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="#FF00A1D6" />
</Trigger>
<Trigger Property="IsMouseOver" Value="false">
<Setter Property="BorderBrush" Value="#FFD7DDE4" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Visibility="{Binding Visibility}">
<Button
x:Name="namePrevious"
Margin="0,0,8,0"
Command="{Binding PreviousCommand}"
Style="{StaticResource pagerButton}"
Visibility="{Binding PreviousVisibility}">
<Image
Width="16"
Height="16"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=namePrevious}" Value="True">
<Setter Property="Source" Value="{StaticResource ToLeftHoverDrawingImage}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=namePrevious}" Value="False">
<Setter Property="Source" Value="{StaticResource ToLeftDrawingImage}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
<Button
x:Name="nameFirst"
Margin="0,0,4,0"
Command="{Binding FirstCommand}"
Style="{StaticResource pagerButton}"
Visibility="{Binding FirstVisibility}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
Text="{Binding First, Mode=TwoWay}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=nameFirst}" Value="True">
<Setter Property="Foreground" Value="#FF00A1D6" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=nameFirst}" Value="False">
<Setter Property="Foreground" Value="#FF657180" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Button>
<Border
Width="20"
Height="40"
Margin="0,0,4,0"
Visibility="{Binding LeftJumpVisibility}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="#FF666666"
Text="&#x2022;&#x2022;&#x2022;" />
</Border>
<Button
x:Name="namePreviousSecond"
Margin="0,0,4,0"
Command="{Binding PreviousSecondCommand}"
Style="{StaticResource pagerButton}"
Visibility="{Binding PreviousSecondVisibility}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
Text="{Binding PreviousSecond, Mode=TwoWay}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=namePreviousSecond}" Value="True">
<Setter Property="Foreground" Value="#FF00A1D6" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=namePreviousSecond}" Value="False">
<Setter Property="Foreground" Value="#FF657180" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Button>
<Button
x:Name="namePreviousFirst"
Margin="0,0,4,0"
Command="{Binding PreviousFirstCommand}"
Style="{StaticResource pagerButton}"
Visibility="{Binding PreviousFirstVisibility}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
Text="{Binding PreviousFirst, Mode=TwoWay}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=namePreviousFirst}" Value="True">
<Setter Property="Foreground" Value="#FF00A1D6" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=namePreviousFirst}" Value="False">
<Setter Property="Foreground" Value="#FF657180" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Button>
<Border
Margin="0,0,4,0"
Background="#FF00A1D6"
BorderThickness="0"
Style="{StaticResource pagerBorder}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
Foreground="#FFFFFFFF"
Text="{Binding Current, Mode=TwoWay}" />
</Border>
<Button
x:Name="nameNextFirst"
Margin="0,0,4,0"
Command="{Binding NextFirstCommand}"
Style="{StaticResource pagerButton}"
Visibility="{Binding NextFirstVisibility}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
Text="{Binding NextFirst, Mode=TwoWay}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=nameNextFirst}" Value="True">
<Setter Property="Foreground" Value="#FF00A1D6" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=nameNextFirst}" Value="False">
<Setter Property="Foreground" Value="#FF657180" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Button>
<Button
x:Name="nameNextSecond"
Margin="0,0,4,0"
Command="{Binding NextSecondCommand}"
Style="{StaticResource pagerButton}"
Visibility="{Binding NextSecondVisibility}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
Text="{Binding NextSecond, Mode=TwoWay}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=nameNextSecond}" Value="True">
<Setter Property="Foreground" Value="#FF00A1D6" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=nameNextSecond}" Value="False">
<Setter Property="Foreground" Value="#FF657180" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Button>
<Border
Width="20"
Height="40"
Margin="0,0,4,0"
Visibility="{Binding RightJumpVisibility}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="#FF666666"
Text="&#x2022;&#x2022;&#x2022;" />
</Border>
<Button
x:Name="nameLast"
Margin="0,0,4,0"
Command="{Binding LastCommand}"
Style="{StaticResource pagerButton}"
Visibility="{Binding LastVisibility}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
Text="{Binding Count}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=nameLast}" Value="True">
<Setter Property="Foreground" Value="#FF00A1D6" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=nameLast}" Value="False">
<Setter Property="Foreground" Value="#FF657180" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Button>
<Button
x:Name="nameNext"
Margin="4,0,4,0"
Command="{Binding NextCommand}"
Style="{StaticResource pagerButton}"
Visibility="{Binding NextVisibility}">
<Image
Width="16"
Height="16"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=nameNext}" Value="True">
<Setter Property="Source" Value="{StaticResource ToRightHoverDrawingImage}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsMouseOver, ElementName=nameNext}" Value="False">
<Setter Property="Source" Value="{StaticResource ToRightDrawingImage}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
</StackPanel>
</UserControl>

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace DownKyi.CustomControl
{
/// <summary>
/// CustomPager.xaml 的交互逻辑
/// </summary>
public partial class CustomPager : UserControl
{
public CustomPager()
{
InitializeComponent();
}
}
}

@ -0,0 +1,460 @@
using System.ComponentModel;
using System.Windows;
namespace DownKyi.CustomControl
{
public class CustomPagerViewModel : INotifyPropertyChanged
{
public CustomPagerViewModel(int current, int count)
{
Current = current;
Count = count;
SetView();
}
public event PropertyChangedEventHandler PropertyChanged;
// Current修改的回调
public delegate bool CurrentChangedHandler(int old, int current);
public event CurrentChangedHandler CurrentChanged;
protected virtual bool OnCurrentChanged(int old, int current)
{
if (CurrentChanged == null)
{
return false;
}
else
{
return CurrentChanged.Invoke(old, current);
}
}
// Count修改的回调
public delegate void CountChangedHandler(int count);
public event CountChangedHandler CountChanged;
protected virtual void OnCountChanged(int count)
{
CountChanged?.Invoke(count);
}
#region 绑定属性
private Visibility visibility;
public Visibility Visibility
{
get { return visibility; }
set
{
visibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Visibility"));
}
}
private int count;
public int Count
{
get
{
return count;
}
set
{
if (value < Current || value < 1)
{
//throw new Exception("数值不在允许的范围内。");
System.Console.WriteLine(value.ToString());
}
else
{
count = value;
if (count == 1) { Visibility = Visibility.Hidden; }
else { Visibility = Visibility.Visible; }
OnCountChanged(count);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));
}
}
}
private int current;
public int Current
{
get
{
if (current < 1) { current = 1; }
return current;
}
set
{
if (Count > 0 && (value > Count || value < 1))
{
//throw new Exception("数值不在允许的范围内。");
}
else
{
bool isSuccess = OnCurrentChanged(current, value);
if (isSuccess)
{
current = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Current"));
}
}
}
}
private int first;
public int First
{
get { return first; }
set
{
first = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("First"));
}
}
private int previousSecond;
public int PreviousSecond
{
get { return previousSecond; }
set
{
previousSecond = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreviousSecond"));
}
}
private int previousFirst;
public int PreviousFirst
{
get { return previousFirst; }
set
{
previousFirst = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreviousFirst"));
}
}
private int nextFirst;
public int NextFirst
{
get { return nextFirst; }
set
{
nextFirst = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NextFirst"));
}
}
private int nextSecond;
public int NextSecond
{
get { return nextSecond; }
set
{
nextSecond = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NextSecond"));
}
}
// 控制Current左边的控件
private Visibility previousVisibility;
public Visibility PreviousVisibility
{
get { return previousVisibility; }
set
{
previousVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreviousVisibility"));
}
}
private Visibility firstVisibility;
public Visibility FirstVisibility
{
get { return firstVisibility; }
set
{
firstVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("FirstVisibility"));
}
}
private Visibility leftJumpVisibility;
public Visibility LeftJumpVisibility
{
get { return leftJumpVisibility; }
set
{
leftJumpVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("LeftJumpVisibility"));
}
}
private Visibility previousSecondVisibility;
public Visibility PreviousSecondVisibility
{
get { return previousSecondVisibility; }
set
{
previousSecondVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreviousSecondVisibility"));
}
}
private Visibility previousFirstVisibility;
public Visibility PreviousFirstVisibility
{
get { return previousFirstVisibility; }
set
{
previousFirstVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PreviousFirstVisibility"));
}
}
// 控制Current右边的控件
private Visibility nextFirstVisibility;
public Visibility NextFirstVisibility
{
get { return nextFirstVisibility; }
set
{
nextFirstVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NextFirstVisibility"));
}
}
private Visibility nextSecondVisibility;
public Visibility NextSecondVisibility
{
get { return nextSecondVisibility; }
set
{
nextSecondVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NextSecondVisibility"));
}
}
private Visibility rightJumpVisibility;
public Visibility RightJumpVisibility
{
get { return rightJumpVisibility; }
set
{
rightJumpVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("RightJumpVisibility"));
}
}
private Visibility lastVisibility;
public Visibility LastVisibility
{
get { return lastVisibility; }
set
{
lastVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("LastVisibility"));
}
}
private Visibility nextVisibility;
public Visibility NextVisibility
{
get { return nextVisibility; }
set
{
nextVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NextVisibility"));
}
}
#endregion
private MyDelegateCommand previousCommand;
public MyDelegateCommand PreviousCommand => previousCommand ?? (previousCommand = new MyDelegateCommand(PreviousExecuted));
public void PreviousExecuted(object obj)
{
Current -= 1;
SetView();
}
private MyDelegateCommand firstCommand;
public MyDelegateCommand FirstCommand => firstCommand ?? (firstCommand = new MyDelegateCommand(FirstExecuted));
public void FirstExecuted(object obj)
{
Current = 1;
SetView();
}
private MyDelegateCommand previousSecondCommand;
public MyDelegateCommand PreviousSecondCommand => previousSecondCommand ?? (previousSecondCommand = new MyDelegateCommand(PreviousSecondExecuted));
public void PreviousSecondExecuted(object obj)
{
Current -= 2;
SetView();
}
private MyDelegateCommand previousFirstCommand;
public MyDelegateCommand PreviousFirstCommand => previousFirstCommand ?? (previousFirstCommand = new MyDelegateCommand(PreviousFirstExecuted));
public void PreviousFirstExecuted(object obj)
{
Current -= 1;
SetView();
}
private MyDelegateCommand nextFirstCommand;
public MyDelegateCommand NextFirstCommand => nextFirstCommand ?? (nextFirstCommand = new MyDelegateCommand(NextFirstExecuted));
public void NextFirstExecuted(object obj)
{
Current += 1;
SetView();
}
private MyDelegateCommand nextSecondCommand;
public MyDelegateCommand NextSecondCommand => nextSecondCommand ?? (nextSecondCommand = new MyDelegateCommand(NextSecondExecuted));
public void NextSecondExecuted(object obj)
{
Current += 2;
SetView();
}
private MyDelegateCommand lastCommand;
public MyDelegateCommand LastCommand => lastCommand ?? (lastCommand = new MyDelegateCommand(LastExecuted));
public void LastExecuted(object obj)
{
Current = Count;
SetView();
}
private MyDelegateCommand nextCommand;
public MyDelegateCommand NextCommand => nextCommand ?? (nextCommand = new MyDelegateCommand(NextExecuted));
public void NextExecuted(object obj)
{
Current += 1;
SetView();
}
/// <summary>
/// 控制显示,暴力实现,以后重构
/// </summary>
private void SetView()
{
First = 1;
PreviousSecond = Current - 2;
PreviousFirst = Current - 1;
NextFirst = Current + 1;
NextSecond = Current + 2;
// 控制Current左边的控件
if (Current == 1)
{
PreviousVisibility = Visibility.Collapsed;
FirstVisibility = Visibility.Collapsed;
LeftJumpVisibility = Visibility.Collapsed;
PreviousSecondVisibility = Visibility.Collapsed;
PreviousFirstVisibility = Visibility.Collapsed;
}
else if (Current == 2)
{
PreviousVisibility = Visibility.Visible;
FirstVisibility = Visibility.Collapsed;
LeftJumpVisibility = Visibility.Collapsed;
PreviousSecondVisibility = Visibility.Collapsed;
PreviousFirstVisibility = Visibility.Visible;
}
else if (Current == 3)
{
PreviousVisibility = Visibility.Visible;
FirstVisibility = Visibility.Collapsed;
LeftJumpVisibility = Visibility.Collapsed;
PreviousSecondVisibility = Visibility.Visible;
PreviousFirstVisibility = Visibility.Visible;
}
else if (Current == 4)
{
PreviousVisibility = Visibility.Visible;
FirstVisibility = Visibility.Visible;
LeftJumpVisibility = Visibility.Collapsed;
PreviousSecondVisibility = Visibility.Visible;
PreviousFirstVisibility = Visibility.Visible;
}
else
{
PreviousVisibility = Visibility.Visible;
FirstVisibility = Visibility.Visible;
LeftJumpVisibility = Visibility.Visible;
PreviousSecondVisibility = Visibility.Visible;
PreviousFirstVisibility = Visibility.Visible;
}
// 控制Current右边的控件
if (Current == Count)
{
NextFirstVisibility = Visibility.Collapsed;
NextSecondVisibility = Visibility.Collapsed;
RightJumpVisibility = Visibility.Collapsed;
LastVisibility = Visibility.Collapsed;
NextVisibility = Visibility.Collapsed;
}
else if (Current == Count - 1)
{
NextFirstVisibility = Visibility.Visible;
NextSecondVisibility = Visibility.Collapsed;
RightJumpVisibility = Visibility.Collapsed;
LastVisibility = Visibility.Collapsed;
NextVisibility = Visibility.Visible;
}
else if (Current == Count - 2)
{
NextFirstVisibility = Visibility.Visible;
NextSecondVisibility = Visibility.Visible;
RightJumpVisibility = Visibility.Collapsed;
LastVisibility = Visibility.Collapsed;
NextVisibility = Visibility.Visible;
}
else if (Current == Count - 3)
{
NextFirstVisibility = Visibility.Visible;
NextSecondVisibility = Visibility.Visible;
RightJumpVisibility = Visibility.Collapsed;
LastVisibility = Visibility.Visible;
NextVisibility = Visibility.Visible;
}
else
{
NextFirstVisibility = Visibility.Visible;
NextSecondVisibility = Visibility.Visible;
RightJumpVisibility = Visibility.Visible;
LastVisibility = Visibility.Visible;
NextVisibility = Visibility.Visible;
}
}
}
}

@ -0,0 +1,85 @@
using System;
using System.Windows.Input;
namespace DownKyi.CustomControl
{
/// <summary>
/// 绑定命令的工具类
/// </summary>
public class MyDelegateCommand : ICommand
{
/// <summary>
/// 检查命令是否可以执行的事件在UI事件发生导致控件状态或数据发生变化时触发
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
{
CommandManager.RequerySuggested += value;
}
}
remove
{
if (_canExecute != null)
{
CommandManager.RequerySuggested -= value;
}
}
}
/// <summary>
/// 判断命令是否可以执行的方法
/// </summary>
private Func<object, bool> _canExecute;
/// <summary>
/// 命令需要执行的方法
/// </summary>
private Action<object> _execute;
/// <summary>
/// 创建一个命令
/// </summary>
/// <param name="execute">命令要执行的方法</param>
public MyDelegateCommand(Action<object> execute) : this(execute, null)
{
}
/// <summary>
/// 创建一个命令
/// </summary>
/// <param name="execute">命令要执行的方法</param>
/// <param name="canExecute">判断命令是否能够执行的方法</param>
public MyDelegateCommand(Action<object> execute, Func<object, bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
/// <summary>
/// 判断命令是否可以执行
/// </summary>
/// <param name="parameter">命令传入的参数</param>
/// <returns>是否可以执行</returns>
public bool CanExecute(object parameter)
{
if (_canExecute == null) return true;
return _canExecute(parameter);
}
/// <summary>
/// 执行命令
/// </summary>
/// <param name="parameter"></param>
public void Execute(object parameter)
{
if (_execute != null && CanExecute(parameter))
{
_execute(parameter);
}
}
}
}

@ -80,6 +80,11 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="Converter\CountConverter.cs" /> <Compile Include="Converter\CountConverter.cs" />
<Compile Include="CustomControl\CustomPager.xaml.cs">
<DependentUpon>CustomPager.xaml</DependentUpon>
</Compile>
<Compile Include="CustomControl\CustomPagerViewModel.cs" />
<Compile Include="CustomControl\MyDelegateCommand.cs" />
<Compile Include="CustomControl\GifImage.cs" /> <Compile Include="CustomControl\GifImage.cs" />
<Compile Include="Events\MessageEvent.cs" /> <Compile Include="Events\MessageEvent.cs" />
<Compile Include="Events\NavigationEvent.cs" /> <Compile Include="Events\NavigationEvent.cs" />
@ -97,6 +102,7 @@
<Compile Include="Services\SearchService.cs" /> <Compile Include="Services\SearchService.cs" />
<Compile Include="ViewModels\PageViewModels\Favorites.cs" /> <Compile Include="ViewModels\PageViewModels\Favorites.cs" />
<Compile Include="ViewModels\PageViewModels\FavoritesMedia.cs" /> <Compile Include="ViewModels\PageViewModels\FavoritesMedia.cs" />
<Compile Include="ViewModels\PageViewModels\PublicationMedia.cs" />
<Compile Include="ViewModels\PageViewModels\SpaceItem.cs" /> <Compile Include="ViewModels\PageViewModels\SpaceItem.cs" />
<Compile Include="ViewModels\Settings\DisplayFileNamePart.cs" /> <Compile Include="ViewModels\Settings\DisplayFileNamePart.cs" />
<Compile Include="Models\ParseScopeDisplay.cs" /> <Compile Include="Models\ParseScopeDisplay.cs" />
@ -145,6 +151,7 @@
<Compile Include="ViewModels\Settings\ViewNetworkViewModel.cs" /> <Compile Include="ViewModels\Settings\ViewNetworkViewModel.cs" />
<Compile Include="ViewModels\Dialogs\ViewParsingSelectorViewModel.cs" /> <Compile Include="ViewModels\Dialogs\ViewParsingSelectorViewModel.cs" />
<Compile Include="ViewModels\ViewMySpaceViewModel.cs" /> <Compile Include="ViewModels\ViewMySpaceViewModel.cs" />
<Compile Include="ViewModels\ViewPublicationViewModel.cs" />
<Compile Include="ViewModels\ViewPublicFavoritesViewModel.cs" /> <Compile Include="ViewModels\ViewPublicFavoritesViewModel.cs" />
<Compile Include="ViewModels\ViewSettingsViewModel.cs" /> <Compile Include="ViewModels\ViewSettingsViewModel.cs" />
<Compile Include="ViewModels\ViewToolboxViewModel.cs" /> <Compile Include="ViewModels\ViewToolboxViewModel.cs" />
@ -208,6 +215,9 @@
<Compile Include="Views\ViewMySpace.xaml.cs"> <Compile Include="Views\ViewMySpace.xaml.cs">
<DependentUpon>ViewMySpace.xaml</DependentUpon> <DependentUpon>ViewMySpace.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\ViewPublication.xaml.cs">
<DependentUpon>ViewPublication.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewPublicFavorites.xaml.cs"> <Compile Include="Views\ViewPublicFavorites.xaml.cs">
<DependentUpon>ViewPublicFavorites.xaml</DependentUpon> <DependentUpon>ViewPublicFavorites.xaml</DependentUpon>
</Compile> </Compile>
@ -223,6 +233,10 @@
<Compile Include="Views\ViewVideoDetail.xaml.cs"> <Compile Include="Views\ViewVideoDetail.xaml.cs">
<DependentUpon>ViewVideoDetail.xaml</DependentUpon> <DependentUpon>ViewVideoDetail.xaml</DependentUpon>
</Compile> </Compile>
<Page Include="CustomControl\CustomPager.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Languages\en_US.xaml"> <Page Include="Languages\en_US.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
@ -379,6 +393,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\ViewPublication.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewPublicFavorites.xaml"> <Page Include="Views\ViewPublicFavorites.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -497,6 +515,8 @@
<Resource Include="Resources\level\lv9.png" /> <Resource Include="Resources\level\lv9.png" />
<Resource Include="Resources\video-placeholder.png" /> <Resource Include="Resources\video-placeholder.png" />
<Resource Include="Resources\channel.png" /> <Resource Include="Resources\channel.png" />
<Resource Include="Resources\play.png" />
<Resource Include="Resources\time.png" />
<Content Include="打不开DownKyi请点我.txt"> <Content Include="打不开DownKyi请点我.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>

@ -63,6 +63,16 @@
<system:String x:Key="AllPublicationZones">全部</system:String> <system:String x:Key="AllPublicationZones">全部</system:String>
<system:String x:Key="Publication">投稿视频</system:String> <system:String x:Key="Publication">投稿视频</system:String>
<system:String x:Key="Channel">频道</system:String> <system:String x:Key="Channel">频道</system:String>
<system:String x:Key="UserSpaceWait">请稍等,马上就好~</system:String>
<!-- PublicFavorites -->
<system:String x:Key="PublicFavorites">收藏夹</system:String>
<system:String x:Key="FavoritesMediaCount">个内容</system:String>
<!-- Publication -->
<system:String x:Key="DownloadSelectedPublication">下载选中项</system:String>
<system:String x:Key="DownloadAllPublication">下载全部</system:String>
<system:String x:Key="PublicationWait">请稍等,马上就好~</system:String>
<!-- VideoDetail --> <!-- VideoDetail -->
<system:String x:Key="CopyCover">复制封面图片</system:String> <system:String x:Key="CopyCover">复制封面图片</system:String>
@ -252,10 +262,6 @@
<system:String x:Key="ExtractAudio">提取音频</system:String> <system:String x:Key="ExtractAudio">提取音频</system:String>
<system:String x:Key="ExtractVideo">提取视频</system:String> <system:String x:Key="ExtractVideo">提取视频</system:String>
<!-- PublicFavorites -->
<system:String x:Key="PublicFavorites">收藏夹</system:String>
<system:String x:Key="FavoritesMediaCount">个内容</system:String>
<!-- Dialog --> <!-- Dialog -->
<system:String x:Key="Cancel">取消</system:String> <system:String x:Key="Cancel">取消</system:String>
<system:String x:Key="SelectDirectory">请选择文件夹</system:String> <system:String x:Key="SelectDirectory">请选择文件夹</system:String>

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

@ -6,7 +6,13 @@
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}"> <ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid x:Name="panel" Height="60"> <Grid x:Name="panel" Height="60">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel <StackPanel
Grid.Column="0"
Margin="20,0,0,0" Margin="20,0,0,0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -34,12 +40,26 @@
Fill="{Binding Image.Fill}" Fill="{Binding Image.Fill}"
Stretch="UniformToFill" /> Stretch="UniformToFill" />
</ContentControl> </ContentControl>
<TextBlock <TextBlock
x:Name="text" x:Name="text"
HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
FontSize="12" FontSize="12"
Text="{Binding Title}" /> Foreground="{DynamicResource BrushTextDark}"
Text="{Binding Title}"
TextTrimming="CharacterEllipsis" />
</StackPanel> </StackPanel>
<TextBlock
x:Name="sub"
Grid.Column="1"
Margin="10,0,20,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource BrushTextGrey2}"
Text="{Binding SubTitle}" />
</Grid> </Grid>
<ControlTemplate.Triggers> <ControlTemplate.Triggers>

@ -0,0 +1,71 @@
using Prism.Commands;
using Prism.Mvvm;
using System.Windows.Media.Imaging;
namespace DownKyi.ViewModels.PageViewModels
{
public class PublicationMedia : BindableBase
{
public long Avid { get; set; }
public string Bvid { get; set; }
private bool isSelected;
public bool IsSelected
{
get => isSelected;
set => SetProperty(ref isSelected, value);
}
private BitmapImage cover;
public BitmapImage Cover
{
get => cover;
set => SetProperty(ref cover, value);
}
private string title;
public string Title
{
get => title;
set => SetProperty(ref title, value);
}
private string duration;
public string Duration
{
get => duration;
set => SetProperty(ref duration, value);
}
private string playNumber;
public string PlayNumber
{
get => playNumber;
set => SetProperty(ref playNumber, value);
}
private string createTime;
public string CreateTime
{
get => createTime;
set => SetProperty(ref createTime, value);
}
// 视频标题点击事件
private DelegateCommand<object> titleCommand;
public DelegateCommand<object> TitleCommand => titleCommand ?? (titleCommand = new DelegateCommand<object>(ExecuteTitleCommand));
/// <summary>
/// 视频标题点击事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteTitleCommand(object parameter)
{
if (!(parameter is string tag)) { return; }
string url = "https://www.bilibili.com/video/" + tag;
System.Diagnostics.Process.Start(url);
}
}
}

@ -1,10 +1,13 @@
using DownKyi.Core.BiliApi.Users.Models; using DownKyi.Core.BiliApi.Users.Models;
using DownKyi.Core.BiliApi.Zone; using DownKyi.Core.BiliApi.Zone;
using DownKyi.Events;
using DownKyi.Utils; using DownKyi.Utils;
using Prism.Commands;
using Prism.Events; using Prism.Events;
using Prism.Regions; using Prism.Regions;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
@ -12,7 +15,9 @@ namespace DownKyi.ViewModels.UserSpace
{ {
public class ViewArchiveViewModel : BaseViewModel public class ViewArchiveViewModel : BaseViewModel
{ {
public const string Tag = "ArchiveView"; public const string Tag = "PageUserSpaceArchiveView";
private long mid = -1;
#region 页面属性申明 #region 页面属性申明
@ -23,6 +28,13 @@ namespace DownKyi.ViewModels.UserSpace
set => SetProperty(ref publicationZones, value); set => SetProperty(ref publicationZones, value);
} }
private int selectedItem;
public int SelectedItem
{
get => selectedItem;
set => SetProperty(ref selectedItem, value);
}
#endregion #endregion
public ViewArchiveViewModel(IEventAggregator eventAggregator) : base(eventAggregator) public ViewArchiveViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
@ -35,6 +47,38 @@ namespace DownKyi.ViewModels.UserSpace
} }
#region 命令申明 #region 命令申明
// 视频选择事件
private DelegateCommand<object> publicationZonesCommand;
public DelegateCommand<object> PublicationZonesCommand => publicationZonesCommand ?? (publicationZonesCommand = new DelegateCommand<object>(ExecutePublicationZonesCommand));
/// <summary>
/// 视频选择事件
/// </summary>
/// <param name="parameter"></param>
private void ExecutePublicationZonesCommand(object parameter)
{
if (!(parameter is PublicationZone zone)) { return; }
Dictionary<string, object> data = new Dictionary<string, object>
{
{ "mid", mid },
{ "tid", zone.Tid },
{ "list", PublicationZones.ToList() }
};
// 进入视频页面
NavigationParam param = new NavigationParam
{
ViewName = ViewPublicationViewModel.Tag,
ParentViewName = ViewUserSpaceViewModel.Tag,
Parameter = data
};
eventAggregator.GetEvent<NavigationEvent>().Publish(param);
SelectedItem = -1;
}
#endregion #endregion
public override void OnNavigatedFrom(NavigationContext navigationContext) public override void OnNavigatedFrom(NavigationContext navigationContext)
@ -42,6 +86,7 @@ namespace DownKyi.ViewModels.UserSpace
base.OnNavigatedFrom(navigationContext); base.OnNavigatedFrom(navigationContext);
PublicationZones.Clear(); PublicationZones.Clear();
SelectedItem = -1;
} }
/// <summary> /// <summary>
@ -53,6 +98,7 @@ namespace DownKyi.ViewModels.UserSpace
base.OnNavigatedTo(navigationContext); base.OnNavigatedTo(navigationContext);
PublicationZones.Clear(); PublicationZones.Clear();
SelectedItem = -1;
// 根据传入参数不同执行不同任务 // 根据传入参数不同执行不同任务
var parameter = navigationContext.Parameters.GetValue<List<SpacePublicationListTypeVideoZone>>("object"); var parameter = navigationContext.Parameters.GetValue<List<SpacePublicationListTypeVideoZone>>("object");
@ -61,6 +107,9 @@ namespace DownKyi.ViewModels.UserSpace
return; return;
} }
// 传入mid
mid = navigationContext.Parameters.GetValue<long>("mid");
int VideoCount = 0; int VideoCount = 0;
foreach (var zone in parameter) foreach (var zone in parameter)
{ {

@ -12,7 +12,7 @@ namespace DownKyi.ViewModels.UserSpace
{ {
public class ViewChannelViewModel : BaseViewModel public class ViewChannelViewModel : BaseViewModel
{ {
public const string Tag = "Channel"; public const string Tag = "PageUserSpaceChannel";
#region 页面属性申明 #region 页面属性申明

@ -119,6 +119,8 @@ namespace DownKyi.ViewModels
//// 进入设置页面时显示的设置项 //// 进入设置页面时显示的设置项
SelectTabId = 0; SelectTabId = 0;
regionManager.RequestNavigate("DownloadManagerContentRegion", ViewDownloadingViewModel.Tag, new NavigationParameters()); regionManager.RequestNavigate("DownloadManagerContentRegion", ViewDownloadingViewModel.Tag, new NavigationParameters());
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
} }
} }

@ -63,7 +63,6 @@ namespace DownKyi.ViewModels
#endregion #endregion
} }
#region 命令申明 #region 命令申明
// 返回 // 返回
@ -92,7 +91,6 @@ namespace DownKyi.ViewModels
#endregion #endregion
#region 业务逻辑 #region 业务逻辑
/// <summary> /// <summary>
@ -224,6 +222,8 @@ namespace DownKyi.ViewModels
/// </summary> /// </summary>
private void InitStatus() private void InitStatus()
{ {
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
LoginQRCode = null; LoginQRCode = null;
LoginQRCodeOpacity = 1; LoginQRCodeOpacity = 1;
LoginQRCodeStatus = Visibility.Hidden; LoginQRCodeStatus = Visibility.Hidden;

@ -212,6 +212,11 @@ namespace DownKyi.ViewModels
} }
}); });
if (directory == null)
{
return;
}
// 通知用户添加到下载列表的结果 // 通知用户添加到下载列表的结果
if (i == 0) if (i == 0)
{ {
@ -230,6 +235,8 @@ namespace DownKyi.ViewModels
{ {
LogManager.Debug(Tag, "初始化页面元素"); LogManager.Debug(Tag, "初始化页面元素");
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
ContentVisibility = Visibility.Collapsed; ContentVisibility = Visibility.Collapsed;
NoDataVisibility = Visibility.Collapsed; NoDataVisibility = Visibility.Collapsed;

@ -0,0 +1,478 @@
using DownKyi.Core.BiliApi.VideoStream;
using DownKyi.Core.Storage;
using DownKyi.Core.Utils;
using DownKyi.CustomControl;
using DownKyi.Events;
using DownKyi.Images;
using DownKyi.Services;
using DownKyi.Services.Download;
using DownKyi.Utils;
using DownKyi.ViewModels.PageViewModels;
using DownKyi.ViewModels.UserSpace;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
namespace DownKyi.ViewModels
{
public class ViewPublicationViewModel : BaseViewModel
{
public const string Tag = "PagePublication";
private readonly IDialogService dialogService;
private CancellationTokenSource tokenSource;
private long mid = -1;
// 每页视频数量,暂时在此写死,以后在设置中增加选项
private readonly int VideoNumberInPage = 30;
#region 页面属性申明
private GifImage loading;
public GifImage Loading
{
get => loading;
set => SetProperty(ref loading, value);
}
private Visibility loadingVisibility;
public Visibility LoadingVisibility
{
get => loadingVisibility;
set => SetProperty(ref loadingVisibility, value);
}
private Visibility noDataVisibility;
public Visibility NoDataVisibility
{
get => noDataVisibility;
set => SetProperty(ref noDataVisibility, value);
}
private VectorImage arrowBack;
public VectorImage ArrowBack
{
get => arrowBack;
set => SetProperty(ref arrowBack, value);
}
private ObservableCollection<TabHeader> tabHeaders;
public ObservableCollection<TabHeader> TabHeaders
{
get => tabHeaders;
set => SetProperty(ref tabHeaders, value);
}
private int selectTabId;
public int SelectTabId
{
get => selectTabId;
set => SetProperty(ref selectTabId, value);
}
private bool isEnabled = true;
public bool IsEnabled
{
get => isEnabled;
set => SetProperty(ref isEnabled, value);
}
private CustomPagerViewModel pager;
public CustomPagerViewModel Pager
{
get => pager;
set => SetProperty(ref pager, value);
}
private ObservableCollection<PublicationMedia> medias;
public ObservableCollection<PublicationMedia> Medias
{
get => medias;
set => SetProperty(ref medias, value);
}
private bool isSelectAll;
public bool IsSelectAll
{
get => isSelectAll;
set => SetProperty(ref isSelectAll, value);
}
#endregion
public ViewPublicationViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base(eventAggregator)
{
this.dialogService = dialogService;
#region 属性初始化
// 初始化loading gif
Loading = new GifImage(Properties.Resources.loading);
Loading.StartAnimate();
LoadingVisibility = Visibility.Collapsed;
NoDataVisibility = Visibility.Collapsed;
ArrowBack = NavigationIcon.Instance().ArrowBack;
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
TabHeaders = new ObservableCollection<TabHeader>();
Medias = new ObservableCollection<PublicationMedia>();
#endregion
}
#region 命令申明
// 返回事件
private DelegateCommand backSpaceCommand;
public DelegateCommand BackSpaceCommand => backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace));
/// <summary>
/// 返回事件
/// </summary>
private void ExecuteBackSpace()
{
ArrowBack.Fill = DictionaryResource.GetColor("ColorText");
// 结束任务
tokenSource.Cancel();
NavigationParam parameter = new NavigationParam
{
ViewName = ParentView,
ParentViewName = null,
Parameter = null
};
eventAggregator.GetEvent<NavigationEvent>().Publish(parameter);
}
// 左侧tab点击事件
private DelegateCommand<object> leftTabHeadersCommand;
public DelegateCommand<object> LeftTabHeadersCommand => leftTabHeadersCommand ?? (leftTabHeadersCommand = new DelegateCommand<object>(ExecuteLeftTabHeadersCommand, CanExecuteLeftTabHeadersCommand));
/// <summary>
/// 左侧tab点击事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteLeftTabHeadersCommand(object parameter)
{
if (!(parameter is TabHeader tabHeader)) { return; }
// 页面选择
Pager = new CustomPagerViewModel(1, (int)Math.Ceiling(double.Parse(tabHeader.SubTitle) / VideoNumberInPage));
Pager.CurrentChanged += OnCurrentChanged_Pager;
Pager.CountChanged += OnCountChanged_Pager;
Pager.Current = 1;
}
/// <summary>
/// 左侧tab点击事件是否允许执行
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
private bool CanExecuteLeftTabHeadersCommand(object parameter)
{
return IsEnabled;
}
// 全选按钮点击事件
private DelegateCommand<object> selectAllCommand;
public DelegateCommand<object> SelectAllCommand => selectAllCommand ?? (selectAllCommand = new DelegateCommand<object>(ExecuteSelectAllCommand));
/// <summary>
/// 全选按钮点击事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteSelectAllCommand(object parameter)
{
if (IsSelectAll)
{
foreach (var item in Medias)
{
item.IsSelected = true;
}
}
else
{
foreach (var item in Medias)
{
item.IsSelected = false;
}
}
}
// 列表选择事件
private DelegateCommand<object> mediasCommand;
public DelegateCommand<object> MediasCommand => mediasCommand ?? (mediasCommand = new DelegateCommand<object>(ExecuteMediasCommand));
/// <summary>
/// 列表选择事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteMediasCommand(object parameter)
{
if (!(parameter is IList selectedMedia)) { return; }
if (selectedMedia.Count == Medias.Count)
{
IsSelectAll = true;
}
else
{
IsSelectAll = false;
}
}
// 添加选中项到下载列表事件
private DelegateCommand addToDownloadCommand;
public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? (addToDownloadCommand = new DelegateCommand(ExecuteAddToDownloadCommand));
/// <summary>
/// 添加选中项到下载列表事件
/// </summary>
private void ExecuteAddToDownloadCommand()
{
AddToDownload(true);
}
// 添加所有视频到下载列表事件
private DelegateCommand addAllToDownloadCommand;
public DelegateCommand AddAllToDownloadCommand => addAllToDownloadCommand ?? (addAllToDownloadCommand = new DelegateCommand(ExecuteAddAllToDownloadCommand));
/// <summary>
/// 添加所有视频到下载列表事件
/// </summary>
private void ExecuteAddAllToDownloadCommand()
{
AddToDownload(false);
}
#endregion
private async void AddToDownload(bool isOnlySelected)
{
// 收藏夹里只有视频
AddToDownloadService addToDownloadService = new AddToDownloadService(PlayStreamType.VIDEO);
// 选择文件夹
string directory = addToDownloadService.SetDirectory(dialogService);
// 视频计数
int i = 0;
await Task.Run(() =>
{
// 添加到下载
foreach (var media in Medias)
{
// 只下载选中项,跳过未选中项
if (isOnlySelected && !media.IsSelected) { continue; }
/// 有分P的就下载全部
// 开启服务
VideoInfoService videoInfoService = new VideoInfoService(media.Bvid);
addToDownloadService.SetVideoInfoService(videoInfoService);
addToDownloadService.GetVideo();
addToDownloadService.ParseVideo(videoInfoService);
// 下载
i += addToDownloadService.AddToDownload(eventAggregator, directory);
}
});
if (directory == null)
{
return;
}
// 通知用户添加到下载列表的结果
if (i == 0)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipAddDownloadingZero"));
}
else
{
eventAggregator.GetEvent<MessageEvent>().Publish($"{DictionaryResource.GetString("TipAddDownloadingFinished1")}{i}{DictionaryResource.GetString("TipAddDownloadingFinished2")}");
}
}
private void OnCountChanged_Pager(int count) { }
private bool OnCurrentChanged_Pager(int old, int current)
{
if (!IsEnabled)
{
//Pager.Current = old;
return false;
}
Medias.Clear();
LoadingVisibility = Visibility.Visible;
NoDataVisibility = Visibility.Collapsed;
UpdatePublication(current);
return true;
}
private async void UpdatePublication(int current)
{
// 是否正在获取数据
// 在所有的退出分支中都需要设为true
IsEnabled = false;
var tab = TabHeaders[SelectTabId];
await Task.Run(() =>
{
CancellationToken cancellationToken = tokenSource.Token;
var publications = Core.BiliApi.Users.UserSpace.GetPublication(mid, current, VideoNumberInPage, tab.Id);
if (publications == null)
{
// 没有数据UI提示
LoadingVisibility = Visibility.Collapsed;
NoDataVisibility = Visibility.Visible;
return;
}
var videos = publications.Vlist;
if (videos == null)
{
// 没有数据UI提示
LoadingVisibility = Visibility.Collapsed;
NoDataVisibility = Visibility.Visible;
return;
}
foreach (var video in videos)
{
// 查询、保存封面
string coverUrl = video.Pic;
BitmapImage cover;
if (coverUrl == null || coverUrl == "")
{
cover = new BitmapImage(new Uri($"pack://application:,,,/Resources/video-placeholder.png"));
}
else
{
if (!coverUrl.ToLower().StartsWith("http"))
{
coverUrl = $"https:{video.Pic}";
}
StorageCover storageCover = new StorageCover();
cover = storageCover.GetCoverThumbnail(video.Aid, video.Bvid, -1, coverUrl, 200, 125);
}
// 播放数
string play = string.Empty;
if (video.Play > 0)
{
play = Format.FormatNumber(video.Play);
}
else
{
play = "--";
}
DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区
DateTime dateCTime = startTime.AddSeconds(video.Created);
string ctime = dateCTime.ToString("yyyy-MM-dd");
App.PropertyChangeAsync(new Action(() =>
{
PublicationMedia media = new PublicationMedia
{
Avid = video.Aid,
Bvid = video.Bvid,
Cover = cover,
Duration = video.Length,
Title = video.Title,
PlayNumber = play,
CreateTime = ctime
};
medias.Add(media);
LoadingVisibility = Visibility.Collapsed;
NoDataVisibility = Visibility.Collapsed;
}));
// 判断是否该结束线程若为true跳出循环
if (cancellationToken.IsCancellationRequested)
{
break;
}
}
}, (tokenSource = new CancellationTokenSource()).Token);
IsEnabled = true;
}
/// <summary>
/// 初始化页面数据
/// </summary>
private void InitView()
{
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
TabHeaders.Clear();
SelectTabId = -1;
}
/// <summary>
/// 导航到VideoDetail页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
InitView();
// 根据传入参数不同执行不同任务
var parameter = navigationContext.Parameters.GetValue<Dictionary<string, object>>("Parameter");
if (parameter == null)
{
return;
}
mid = (long)parameter["mid"];
int tid = (int)parameter["tid"];
List<PublicationZone> zones = (List<PublicationZone>)parameter["list"];
foreach (var item in zones)
{
TabHeaders.Add(new TabHeader
{
Id = item.Tid,
Title = item.Name,
SubTitle = item.Count.ToString()
});
}
// 初始选中项
var selectTab = TabHeaders.FirstOrDefault(item => item.Id == tid);
SelectTabId = TabHeaders.IndexOf(selectTab);
// 页面选择
Pager = new CustomPagerViewModel(1, (int)Math.Ceiling(double.Parse(selectTab.SubTitle) / VideoNumberInPage));
Pager.CurrentChanged += OnCurrentChanged_Pager;
Pager.CountChanged += OnCountChanged_Pager;
Pager.Current = 1;
}
}
}

@ -131,6 +131,8 @@ namespace DownKyi.ViewModels
// 进入设置页面时显示的设置项 // 进入设置页面时显示的设置项
SelectTabId = 0; SelectTabId = 0;
regionManager.RequestNavigate("SettingsContentRegion", ViewBasicViewModel.Tag, new NavigationParameters()); regionManager.RequestNavigate("SettingsContentRegion", ViewBasicViewModel.Tag, new NavigationParameters());
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
} }
} }

@ -122,6 +122,8 @@ namespace DownKyi.ViewModels
// 进入设置页面时显示的设置项 // 进入设置页面时显示的设置项
SelectTabId = 0; SelectTabId = 0;
regionManager.RequestNavigate("ToolboxContentRegion", ViewBiliHelperViewModel.Tag, new NavigationParameters()); regionManager.RequestNavigate("ToolboxContentRegion", ViewBiliHelperViewModel.Tag, new NavigationParameters());
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
} }
} }

@ -216,6 +216,7 @@ namespace DownKyi.ViewModels
NavigationParameters param = new NavigationParameters() NavigationParameters param = new NavigationParameters()
{ {
{ "object", banner.Object }, { "object", banner.Object },
{ "mid", mid },
}; };
switch (banner.Id) switch (banner.Id)

@ -665,6 +665,8 @@ namespace DownKyi.ViewModels
{ {
base.OnNavigatedTo(navigationContext); base.OnNavigatedTo(navigationContext);
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
DownloadManage = ButtonIcon.Instance().DownloadManage; DownloadManage = ButtonIcon.Instance().DownloadManage;
DownloadManage.Height = 24; DownloadManage.Height = 24;
DownloadManage.Width = 24; DownloadManage.Width = 24;

@ -27,5 +27,15 @@
FontSize="30" FontSize="30"
Foreground="White" Foreground="White"
Text="Welcome to DownKyi!" /> Text="Welcome to DownKyi!" />
<TextBlock
x:Name="nameVersion"
Grid.Row="0"
Margin="10"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
FontSize="12"
Foreground="White" />
</Grid> </Grid>
</Window> </Window>

@ -1,16 +1,5 @@
using System; using DownKyi.Models;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows; 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 DownKyi.Views namespace DownKyi.Views
{ {
@ -22,6 +11,8 @@ namespace DownKyi.Views
public SplashWindow() public SplashWindow()
{ {
InitializeComponent(); InitializeComponent();
nameVersion.Text = new AppInfo().VersionName;
} }
} }
} }

@ -2,6 +2,7 @@
x:Class="DownKyi.Views.UserSpace.ViewArchive" x:Class="DownKyi.Views.UserSpace.ViewArchive"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:prism="http://prismlibrary.com/" xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"> prism:ViewModelLocator.AutoWireViewModel="True">
<Grid> <Grid>
@ -9,7 +10,17 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<ListBox ItemsSource="{Binding PublicationZones}"> <ListBox
Name="namePublicationZones"
Margin="30,0,0,0"
ItemsSource="{Binding PublicationZones}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectedIndex="{Binding SelectedItem}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding PublicationZonesCommand}" CommandParameter="{Binding ElementName=namePublicationZones, Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemsPanel> <ListBox.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" /> <WrapPanel IsItemsHost="True" />
@ -42,7 +53,7 @@
<ControlTemplate TargetType="{x:Type ListBoxItem}"> <ControlTemplate TargetType="{x:Type ListBoxItem}">
<StackPanel <StackPanel
Grid.Row="0" Grid.Row="0"
Margin="0,0,30,0" Margin="0,20,30,0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Cursor="Hand" Cursor="Hand"
Orientation="Vertical"> Orientation="Vertical">

@ -9,7 +9,7 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<ListBox ItemsSource="{Binding Channels}"> <ListBox ItemsSource="{Binding Channels}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel> <ListBox.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" /> <WrapPanel IsItemsHost="True" />
@ -42,7 +42,7 @@
<ControlTemplate TargetType="{x:Type ListBoxItem}"> <ControlTemplate TargetType="{x:Type ListBoxItem}">
<StackPanel <StackPanel
Grid.Row="0" Grid.Row="0"
Margin="40,0,0,10" Margin="30,0,30,10"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Orientation="Vertical"> Orientation="Vertical">
<Border <Border

@ -0,0 +1,312 @@
<UserControl
x:Class="DownKyi.Views.ViewPublication"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:DownKyi.CustomControl"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<UserControl.Resources>
<Style x:Key="MediaListStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<StackPanel
Name="nameItemPanel"
Margin="15,15,15,5"
Cursor="Hand"
Orientation="Vertical">
<Border
Name="nameCover"
Width="190"
Height="119"
HorizontalAlignment="Center"
CornerRadius="5">
<Border.Background>
<!-- 长宽比1.6 -->
<ImageBrush ImageSource="{Binding Cover}" />
</Border.Background>
<Grid Width="190" Height="119">
<Image
Name="nameChecked"
Width="24"
Height="24"
Margin="0,10,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Source="/DownKyi;component/Resources/checked.png" />
<Border
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Background="#7F000000"
CornerRadius="5 0 5 0">
<TextBlock
Name="nameDuration"
Padding="6,0"
Foreground="White"
Text="{Binding Duration}" />
</Border>
</Grid>
</Border>
<TextBlock
Name="nameTitle"
Height="35"
MaxWidth="190"
Margin="0,10,0,0"
Foreground="Black"
Tag="{Binding Bvid}"
Text="{Binding Title}"
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap"
ToolTip="{Binding Title}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding TitleCommand}" CommandParameter="{Binding Bvid}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
<Grid Margin="0,3,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<Image
Width="11"
Height="11"
Source="/DownKyi;component/Resources/play.png" />
<TextBlock
Margin="5,0,0,0"
Foreground="#FF999999"
Text="{Binding PlayNumber}" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Image
Width="12"
Height="11"
Source="/DownKyi;component/Resources/time.png" />
<TextBlock
Margin="5,0,0,0"
Foreground="#FF999999"
Text="{Binding CreateTime}" />
</StackPanel>
</Grid>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="nameChecked" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="nameChecked" Property="Visibility" Value="Hidden" />
</Trigger>
<Trigger SourceName="nameTitle" Property="IsMouseOver" Value="True">
<Setter TargetName="nameTitle" Property="Foreground" Value="{DynamicResource BrushPrimary}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="1" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="0"
Margin="10,5,0,5"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Command="{Binding BackSpaceCommand}"
Style="{StaticResource ImageBtnStyle}">
<StackPanel Orientation="Horizontal">
<ContentControl Width="24" Height="24">
<Path
Width="{Binding ArrowBack.Width}"
Height="{Binding ArrowBack.Height}"
Data="{Binding ArrowBack.Data}"
Fill="{Binding ArrowBack.Fill}"
Stretch="None" />
</ContentControl>
<TextBlock
VerticalAlignment="Center"
FontSize="16"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource Publication}" />
</StackPanel>
</Button>
</Grid>
<TextBlock Grid.Row="1" Background="{DynamicResource BrushBorder}" />
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- 左侧tab header -->
<ListBox
Name="nameLeftTabHeaders"
Grid.Column="0"
BorderThickness="0"
IsEnabled="{Binding IsEnabled}"
ItemContainerStyle="{StaticResource LeftTabHeaderItemStyle}"
ItemsSource="{Binding TabHeaders}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
SelectedIndex="{Binding SelectTabId, Mode=TwoWay}"
Style="{StaticResource LeftTabHeaderStyle}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding LeftTabHeadersCommand}" CommandParameter="{Binding ElementName=nameLeftTabHeaders, Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
<Grid Name="nameMediaPanel" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="1" />
<RowDefinition Height="49" />
</Grid.RowDefinitions>
<ListBox
x:Name="nameMedias"
Grid.Row="0"
BorderThickness="0"
ItemContainerStyle="{StaticResource MediaListStyle}"
ItemsSource="{Binding Medias}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectionMode="Extended">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding MediasCommand}" CommandParameter="{Binding ElementName=nameMedias, Path=SelectedItems}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border
x:Name="Bd"
Padding="0"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer Focusable="False">
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Style>
</ListBox>
<!-- 加载gif -->
<StackPanel
Grid.Row="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Vertical"
Visibility="{Binding LoadingVisibility}">
<ContentControl
Width="40"
Height="40"
Content="{Binding Loading}" />
<TextBlock
Margin="0,10,0,0"
FontSize="14"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource PublicationWait}" />
</StackPanel>
<!-- 没有数据提示 -->
<Image
Grid.Row="0"
Width="256"
Height="256"
Source="/DownKyi;component/Resources/no-data.png"
Visibility="{Binding NoDataVisibility}" />
<TextBlock Grid.Row="1" Background="{DynamicResource BrushBorder}" />
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<CheckBox
Grid.Column="0"
Margin="10,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Command="{Binding SelectAllCommand}"
CommandParameter="{Binding ElementName=nameMedias, Path=SelectedItem}"
Content="{DynamicResource SelectAll}"
Foreground="{DynamicResource BrushTextDark}"
IsChecked="{Binding IsSelectAll, Mode=TwoWay}"
Style="{StaticResource CheckBoxStyle}" />
<custom:CustomPager
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
DataContext="{Binding Pager}" />
<Button
Grid.Column="2"
Margin="0,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding AddToDownloadCommand}"
Content="{DynamicResource DownloadSelectedPublication}"
FontSize="12"
Foreground="{DynamicResource BrushText}"
Style="{StaticResource BtnStyle}" />
<Button
Grid.Column="3"
Margin="0,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding AddAllToDownloadCommand}"
Content="{DynamicResource DownloadAllPublication}"
FontSize="12"
Foreground="{DynamicResource BrushText}"
Style="{StaticResource BtnStyle}" />
</Grid>
</Grid>
</Grid>
</Grid>
</UserControl>

@ -0,0 +1,28 @@
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.Navigation;
using System.Windows.Shapes;
namespace DownKyi.Views
{
/// <summary>
/// ViewPublication.xaml 的交互逻辑
/// </summary>
public partial class ViewPublication : UserControl
{
public ViewPublication()
{
InitializeComponent();
}
}
}

@ -243,7 +243,7 @@
<!-- 内容 --> <!-- 内容 -->
<Grid Grid.Row="1" Visibility="{Binding ContentVisibility}"> <Grid Grid.Row="1" Visibility="{Binding ContentVisibility}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="70" /> <RowDefinition Height="65" />
<RowDefinition /> <RowDefinition />
</Grid.RowDefinitions> </Grid.RowDefinitions>
@ -294,10 +294,7 @@
</Grid> </Grid>
<!-- 内容区content --> <!-- 内容区content -->
<ContentControl <ContentControl Grid.Row="1" prism:RegionManager.RegionName="UserSpaceContentRegion" />
Grid.Row="1"
Margin="20,20,20,0"
prism:RegionManager.RegionName="UserSpaceContentRegion" />
</Grid> </Grid>
</Grid> </Grid>
@ -316,7 +313,7 @@
Margin="0,10,0,0" Margin="0,10,0,0"
FontSize="14" FontSize="14"
Foreground="{DynamicResource BrushTextDark}" Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource MySpaceWait}" /> Text="{DynamicResource UserSpaceWait}" />
</StackPanel> </StackPanel>
<!-- 没有数据提示 --> <!-- 没有数据提示 -->

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2021 FlySelfLog
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Loading…
Cancel
Save