Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 74 additions & 61 deletions Plain Craft Launcher 2/Controls/MyImage.vb
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Public Class MyImage
GetType(CornerRadius),
GetType(MyImage),
New FrameworkPropertyMetadata(
New CornerRadius(0),
New CornerRadius(-1),
AddressOf OnCornerRadiusChanged)
)

Expand All @@ -98,7 +98,8 @@ Public Class MyImage
End Sub

Private Sub UpdateClip() Handles Me.SizeChanged
If (ActualWidth > 0 AndAlso ActualHeight > 0) Then
If (ActualWidth > 0 AndAlso ActualHeight > 0) AndAlso
(CornerRadius.TopLeft >= 0 AndAlso CornerRadius.TopRight >= 0) Then
Clip = New RectangleGeometry(
New Rect(0, 0, ActualWidth, ActualHeight),
CornerRadius.TopLeft,
Expand Down Expand Up @@ -135,7 +136,7 @@ Public Class MyImage
End Property
Private _ActualSource As String = Nothing

Private Async Sub Load() Handles Me.Initialized '属性读取顺序修正:在完成 XAML 属性读取后再触发图片加载(#4868)
Private Sub Load() Handles Me.Initialized '属性读取顺序修正:在完成 XAML 属性读取后再触发图片加载(#4868)
'空
If Source Is Nothing Then
ActualSource = Nothing
Expand All @@ -156,71 +157,83 @@ Public Class MyImage
If (Date.Now - TempFile.LastWriteTime) < FileCacheExpiredTime Then Return '无需刷新缓存
End If

Dim TempDownloadingPath As String = Nothing
Dispatcher.BeginInvoke(
Async Function() As Task
Try
'下载
ActualSource = LoadingSource '显示加载中图片

Dim resp = Await DownloadImageAsync(Url)
If Not String.IsNullOrEmpty(resp) Then
ActualSource = resp
Return
End If

resp = Await DownloadImageAsync(FallbackSource)
If Not String.IsNullOrEmpty(resp) Then
ActualSource = resp
Return
End If

Catch ex As Exception
'更换备用地址
Log(ex, $"Online image get fail(source = {Url}, fallback = {FallbackSource})", LogLevel.Developer)
'从缓存加载网络图片
TempPath = GetTempPath(Url)
TempFile = New FileInfo(TempPath)
If EnableCache AndAlso TempFile.Exists() Then
ActualSource = TempPath
If (Date.Now - TempFile.LastWriteTime) < FileCacheExpiredTime Then Return '无需刷新缓存
End If
End Try
End Function)
End Sub
Public Shared Function DownloadImageAsync(url As String) As Task(Of String)
Return _downloadTasks.GetOrAdd(
url,
Function(key)
Dim t = DownloadImageInternelAsync(key)
t.ContinueWith(
Sub()
_downloadTasks.Remove(url, Nothing)
End Sub)
Return t
End Function)
End Function
Public Shared Function GetTempPath(Url As String) As String
Return IO.Path.Combine(PathTemp, "Cache", "Images", $"{GetStringMD5(Url)}.png")
End Function

Private Shared ReadOnly _downloadTasks As New Concurrent.ConcurrentDictionary(Of String, Task(Of String))
Private Shared Async Function DownloadImageInternelAsync(url As String) As Task(Of String)
Dim tempPath = GetTempPath(url)
Dim TempDownloadingPath = tempPath & RandomUtils.NextInt(0, 1000000)

Try
'下载
ActualSource = LoadingSource '显示加载中图片
TempDownloadingPath = TempPath & RandomUtils.NextInt(0, 1000000)
Directory.CreateDirectory(GetPathFromFullPath(TempPath)) '重新实现下载,以避免携带 Header(#5072)
Directory.CreateDirectory(GetPathFromFullPath(tempPath)) '重新实现下载,以避免携带 Header(#5072)
Using fs As New FileStream(TempDownloadingPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)
Using response = Await HttpRequest.Create(Url).
Using response = Await HttpRequest.Create(url).
WithHttpVersionOption(HttpVersion.Version30).
SendAsync(addMetedata:=False).
ConfigureAwait(False)
If response.IsSuccessStatusCode Then
Using nfs = Await response.AsStreamAsync()
fs.SetLength(0)
Await nfs.CopyToAsync(fs)
End Using
ElseIf Not FallbackSource.IsNullOrWhiteSpace() Then
Using fallbackResponse = Await HttpRequest.
Create(FallbackSource).
WithHttpVersionOption(HttpVersion.Version30).
SendAsync(addMetedata:=False).
ConfigureAwait(False)
If fallbackResponse.IsSuccessStatusCode Then
Using fallbackNfs = Await fallbackResponse.AsStreamAsync()
fs.SetLength(0)
Await fallbackNfs.CopyToAsync(fs)
End Using
End If
End Using
Else
Return
End If
SendAsync(addMetedata:=False)
response.EnsureSuccessStatusCode()

Using nfs = Await response.AsStreamAsync()
fs.SetLength(0)
Await nfs.CopyToAsync(fs)
End Using
End Using
End Using
If Url <> Source AndAlso Url <> FallbackSource Then
'已经更换了地址
File.Delete(TempDownloadingPath)
ElseIf EnableCache Then
'保存缓存并显示
If File.Exists(TempPath) Then File.Delete(TempPath)
File.Move(TempDownloadingPath, TempPath, True)
ActualSource = TempPath
Else
'直接显示
ActualSource = TempDownloadingPath
End If

File.Move(TempDownloadingPath, tempPath, True)
Return tempPath
Catch ex As Exception
Try
If TempPath IsNot Nothing AndAlso File.Exists(TempPath) Then File.Delete(TempPath)
If TempDownloadingPath IsNot Nothing AndAlso File.Exists(TempDownloadingPath) Then File.Delete(TempDownloadingPath)
Catch
End Try
'更换备用地址
Log(ex, $"下载图片失败(Base = {Url}, Fallback = {FallbackSource})", LogLevel.Developer)
'从缓存加载网络图片
TempPath = GetTempPath(Url)
TempFile = New FileInfo(TempPath)
If EnableCache AndAlso TempFile.Exists() Then
ActualSource = TempPath
If (Date.Now - TempFile.LastWriteTime) < FileCacheExpiredTime Then Return '无需刷新缓存
End If
If File.Exists(tempPath) Then File.Delete(tempPath)
If File.Exists(TempDownloadingPath) Then File.Delete(TempDownloadingPath)

Log(ex, $"Try to get online image fail (url = {url}, dest = {tempPath})")
Return String.Empty
End Try
End Sub
Public Shared Function GetTempPath(Url As String) As String
Return IO.Path.Combine(PathTemp, "Cache", "Images", $"{GetStringMD5(Url)}.png")
End Function


End Class
2 changes: 1 addition & 1 deletion Plain Craft Launcher 2/Controls/MyListItem.xaml.vb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Imports System.Windows.Markup
Imports System.Windows.Markup

<ContentProperty("Inlines")>
Public Class MyListItem
Expand Down
4 changes: 2 additions & 2 deletions Plain Craft Launcher 2/Modules/Base/MyBitmap.vb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'一个万能的自动图片类型转换工具类
'一个万能的自动图片类型转换工具类

Imports System.Drawing.Imaging
Imports PCL.Core.UI.Media
Expand Down Expand Up @@ -72,7 +72,7 @@ Public Class MyBitmap
End If
Else
'使用这种自己接管 FileStream 的方法加载才能解除文件占用
Using picStream As New FileStream(FilePathOrResourceName, FileMode.Open)
Using picStream As New FileStream(FilePathOrResourceName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
If picStream.Length > 2 AndAlso picStream.ReadByte() = 82 AndAlso picStream.ReadByte() = 73 Then
picStream.Seek(0, SeekOrigin.Begin)
'调用 WIC 转换,需要系统内置 WebP 组件,专治各种精简系统
Expand Down
19 changes: 12 additions & 7 deletions Plain Craft Launcher 2/Modules/Minecraft/ModComp.vb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Imports System.Collections.Concurrent
Imports System.Collections.Concurrent
Imports System.Net.Http
Imports System.Text.Json
Imports System.Text.Json.Serialization
Expand Down Expand Up @@ -836,12 +836,17 @@ Public Module ModComp
End Function) With {.Height = 64}
End Function
Public Function ToListItem() As MyListItem
Dim result As New MyListItem()
result.Title = TranslatedName
result.Info = Description.Replace(vbCr, "").Replace(vbLf, "")
result.Logo = LogoUrl
result.Tags = Tags
result.Tag = Me
Dim result As New MyListItem With {
.Title = TranslatedName,
.Info = Description.Replace(vbCr, "").Replace(vbLf, ""),
.Logo = LogoUrl,
.Tags = Tags,
.Tag = Me
}

Dim img = DirectCast(result.PathLogo, MyImage)
img.CornerRadius = New CornerRadius(6)
img.SnapsToDevicePixels = True
Return result
End Function
Public Sub ApplyLogoToMyImage(img As MyImage)
Expand Down
120 changes: 88 additions & 32 deletions Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
<Grid x:Class="MyLocalCompItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL;assembly="
x:Name="PanBack" Height="44"
RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True">
<Grid
x:Class="MyLocalCompItem"
x:Name="PanBack"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL;assembly="
Height="44"
Background="{StaticResource ColorBrushSemiTransparent}"
RenderTransformOrigin="0.5,0.5"
SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6" />
<ColumnDefinition Width="34" />
<ColumnDefinition Width="7" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="4" x:Name="ColumnPaddingRight" />
<ColumnDefinition x:Name="ColumnPaddingRight" Width="4" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
Expand All @@ -19,39 +23,91 @@
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<!-- Logo -->
<Border Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" IsHitTestVisible="False" SnapsToDevicePixels="True" UseLayoutRounding="True"
HorizontalAlignment="Right" VerticalAlignment="Center" Width="34" Height="34">
<Border.Clip>
<RectangleGeometry Rect="0,0,34,34" RadiusX="6" RadiusY="6" />
</Border.Clip>
<local:MyImage x:Name="PathLogo" RenderOptions.BitmapScalingMode="HighQuality" FallbackSource="pack://application:,,,/images/Icons/NoIcon.png" />
</Border>
<local:MyImage
x:Name="PathLogo"
Grid.Row="1"
Grid.RowSpan="2"
Grid.Column="1"
Width="34"
Height="34"
HorizontalAlignment="Right"
VerticalAlignment="Center"
CornerRadius="6"
FallbackSource="pack://application:,,,/images/Icons/NoIcon.png"
IsHitTestVisible="False"
RenderOptions.BitmapScalingMode="HighQuality"
SnapsToDevicePixels="True" />
<!-- 标题 -->
<Grid Grid.Column="3" Grid.ColumnSpan="2" Grid.Row="1" VerticalAlignment="Center" Margin="0,1,0,0"
SnapsToDevicePixels="False" UseLayoutRounding="False" x:Name="PanTitle">
<Grid
x:Name="PanTitle"
Grid.Row="1"
Grid.Column="3"
Grid.ColumnSpan="2"
Margin="0,1,0,0"
VerticalAlignment="Center"
SnapsToDevicePixels="False"
UseLayoutRounding="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" x:Name="ColumnTitle" />
<ColumnDefinition Width="Auto" x:Name="ColumnSubtitle" />
<ColumnDefinition x:Name="ColumnTitle" Width="Auto" />
<ColumnDefinition x:Name="ColumnSubtitle" Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" x:Name="ColumnExtend" />
<ColumnDefinition x:Name="ColumnExtend" Width="1*" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="LabTitle" TextTrimming="CharacterEllipsis" FontSize="14" IsHitTestVisible="False" />
<TextBlock x:Name="LabSubtitle" Grid.Column="1" HorizontalAlignment="Left"
TextTrimming="CharacterEllipsis" FontSize="12" IsHitTestVisible="False"
Foreground="{DynamicResource ColorBrushGray1}" Opacity="0.4" VerticalAlignment="Center" Visibility="Collapsed" />
<TextBlock
x:Name="LabTitle"
FontSize="14"
IsHitTestVisible="False"
TextTrimming="CharacterEllipsis" />
<TextBlock
x:Name="LabSubtitle"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource ColorBrushGray1}"
IsHitTestVisible="False"
Opacity="0.4"
TextTrimming="CharacterEllipsis"
Visibility="Collapsed" />
<!-- 更新按钮 -->
<local:MyIconButton Grid.Column="2"
Width="21" Height="21" Margin="-2,-1.6,0,0" x:Name="BtnUpdate" Theme="Black" Opacity="0.4" Visibility="Collapsed"
ToolTipService.Placement="Right" ToolTipService.InitialShowDelay="100" ToolTipService.VerticalOffset="-9"
Logo="M640 768H384l-32-32V509H213L190 454l298-298h45l298 298L810 509h-138v226z m-224-64h192V477l32-32h93L512 223 290 445H384l32 32zM352 831h320v64h-320z" />
<local:MyIconButton
x:Name="BtnUpdate"
Grid.Column="2"
Width="21"
Height="21"
Margin="-2,-1.6,0,0"
Logo="M640 768H384l-32-32V509H213L190 454l298-298h45l298 298L810 509h-138v226z m-224-64h192V477l32-32h93L512 223 290 445H384l32 32zM352 831h320v64h-320z"
Opacity="0.4"
Theme="Black"
ToolTipService.InitialShowDelay="100"
ToolTipService.Placement="Right"
ToolTipService.VerticalOffset="-9"
Visibility="Collapsed" />
</Grid>
<!-- Tag 与 详情 -->
<StackPanel x:Name="PanTags" Grid.Row="2" Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Center" Margin="-1,0,1,0" Visibility="Collapsed" IsHitTestVisible="False">
<StackPanel
x:Name="PanTags"
Grid.Row="2"
Grid.Column="3"
Margin="-1,0,1,0"
VerticalAlignment="Center"
IsHitTestVisible="False"
Orientation="Horizontal"
Visibility="Collapsed">
<!--<corelocal:BlurBorder Background="{DynamicResource ColorBrush6}" Padding="3,1" CornerRadius="3" Margin="0,0,4,0" SnapsToDevicePixels="True" UseLayoutRounding="False">
<TextBlock Text="科技" Foreground="{DynamicResource ColorBrush2}" FontSize="11" />
</corelocal:BlurBorder>-->
</StackPanel>
<TextBlock x:Name="LabInfo" Grid.Row="2" Grid.Column="4" VerticalAlignment="Center" Margin="0,0,3,1"
TextTrimming="CharacterEllipsis" FontSize="12" Foreground="{DynamicResource ColorBrushGray4}"
IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False" />
</Grid>
<TextBlock
x:Name="LabInfo"
Grid.Row="2"
Grid.Column="4"
Margin="0,0,3,1"
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource ColorBrushGray4}"
IsHitTestVisible="False"
SnapsToDevicePixels="False"
TextTrimming="CharacterEllipsis"
UseLayoutRounding="False" />
</Grid>
Loading
Loading