MyCompItem.xaml.vb 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. Public Class MyCompItem
  2. #Region "基础属性"
  3. Public Uuid As Integer = GetUuid()
  4. 'Logo
  5. Private _Logo As String = ""
  6. Public Property Logo As String
  7. Get
  8. Return _Logo
  9. End Get
  10. Set(value As String)
  11. If _Logo = value OrElse value Is Nothing Then Exit Property
  12. _Logo = value
  13. Dim FileAddress = PathTemp & "CompLogo\" & GetHash(_Logo) & ".png"
  14. Try
  15. If _Logo.StartsWithF("http", True) Then
  16. '网络图片
  17. If File.Exists(FileAddress) Then
  18. PathLogo.Source = New MyBitmap(FileAddress)
  19. ElseIf _Logo.EndsWithF(".webp", True) Then 'Modrinth 林业 Mod 使用了不支持的 WebP 格式 Logo
  20. Log($"[Comp] 发现不支持的 WebP 格式图标,已更改为默认图标:{_Logo}")
  21. PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")
  22. Else
  23. PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png")
  24. RunInNewThread(Sub() LogoLoader(FileAddress), "Comp Logo Loader " & Uuid & "#", ThreadPriority.BelowNormal)
  25. End If
  26. Else
  27. '位图
  28. PathLogo.Source = New MyBitmap(_Logo)
  29. End If
  30. Catch ex As IOException
  31. Log(ex, "加载资源工程图标时读取失败(" & FileAddress & ")")
  32. Catch ex As ArgumentException
  33. '考虑缓存的图片本身可能有误
  34. Log(ex, "可视化资源工程图标失败(" & FileAddress & ")")
  35. Try
  36. File.Delete(FileAddress)
  37. Log("[Comp] 已清理损坏的资源工程图标:" & FileAddress)
  38. Catch exx As Exception
  39. Log(exx, "清理损坏的资源工程图标缓存失败(" & FileAddress & ")", LogLevel.Hint)
  40. End Try
  41. Catch ex As Exception
  42. Log(ex, "加载资源工程图标失败(" & value & ")")
  43. End Try
  44. End Set
  45. End Property
  46. '后台加载 Logo
  47. Private Sub LogoLoader(LocalFileAddress As String)
  48. Dim Retried As Boolean = False
  49. Dim DownloadEnd As String = GetUuid()
  50. RetryStart:
  51. Try
  52. 'CurseForge 图片使用缩略图
  53. Dim Url As String = _Logo
  54. If Url.Contains("/256/256/") AndAlso GetPixelSize(1) <= 1.25 AndAlso Not Retried Then
  55. Url = Url.Replace("/256/256/", "/64/64/") '#3075:部分 Mod 不存在 64x64 图标,所以重试时不再缩小
  56. End If
  57. '下载图片
  58. NetDownload(Url, LocalFileAddress & DownloadEnd, True)
  59. Dim LoadError As Exception = Nothing
  60. RunInUiWait(
  61. Sub()
  62. Try
  63. '在地址更换时取消加载
  64. If LocalFileAddress <> $"{PathTemp}CompLogo\{GetHash(_Logo)}.png" Then Exit Sub
  65. '在完成正常加载后才保存缓存图片
  66. PathLogo.Source = New MyBitmap(LocalFileAddress & DownloadEnd)
  67. Catch ex As Exception
  68. Log(ex, $"读取资源工程图标失败({LocalFileAddress})")
  69. File.Delete(LocalFileAddress & DownloadEnd)
  70. LoadError = ex
  71. End Try
  72. End Sub)
  73. If LoadError IsNot Nothing Then Throw LoadError
  74. If File.Exists(LocalFileAddress) Then
  75. File.Delete(LocalFileAddress & DownloadEnd)
  76. Else
  77. FileIO.FileSystem.MoveFile(LocalFileAddress & DownloadEnd, LocalFileAddress)
  78. End If
  79. Catch ex As Exception
  80. If Not Retried Then
  81. Retried = True
  82. GoTo RetryStart
  83. Else
  84. Log(ex, $"下载资源工程图标失败({_Logo})")
  85. RunInUi(Sub() PathLogo.Source = New MyBitmap(PathImage & "Icons/NoIcon.png"))
  86. End If
  87. End Try
  88. End Sub
  89. '标题
  90. Public Property Title As String
  91. Get
  92. Return LabTitle.Text
  93. End Get
  94. Set(value As String)
  95. If LabTitle.Text = value Then Exit Property
  96. LabTitle.Text = value
  97. End Set
  98. End Property
  99. '副标题
  100. Public Property SubTitle As String
  101. Get
  102. Return If(LabTitleRaw?.Text, "")
  103. End Get
  104. Set(value As String)
  105. If LabTitleRaw.Text = value Then Exit Property
  106. LabTitleRaw.Text = value
  107. LabTitleRaw.Visibility = If(value = "", Visibility.Collapsed, Visibility.Visible)
  108. End Set
  109. End Property
  110. '描述
  111. Public Property Description As String
  112. Get
  113. Return LabInfo.Text
  114. End Get
  115. Set(value As String)
  116. If LabInfo.Text = value Then Exit Property
  117. LabInfo.Text = value
  118. End Set
  119. End Property
  120. '指向时扩展描述
  121. Private Sub LabInfo_MouseEnter(sender As Object, e As MouseEventArgs) Handles LabInfo.MouseEnter
  122. If IsTextTrimmed(LabInfo) Then
  123. ToolTipInfo.Content = LabInfo.Text
  124. ToolTipInfo.Width = LabInfo.ActualWidth + 25
  125. LabInfo.ToolTip = ToolTipInfo
  126. Else
  127. LabInfo.ToolTip = Nothing
  128. End If
  129. End Sub
  130. Private Function IsTextTrimmed(textBlock As TextBlock) As Boolean
  131. Dim typeface As New Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch)
  132. Dim formattedText As New FormattedText(textBlock.Text, Thread.CurrentThread.CurrentCulture, textBlock.FlowDirection, typeface, textBlock.FontSize, textBlock.Foreground, DPI)
  133. Return formattedText.Width > textBlock.ActualWidth
  134. End Function
  135. 'Tag
  136. Public WriteOnly Property Tags As List(Of String)
  137. Set(value As List(Of String))
  138. PanTags.Children.Clear()
  139. PanTags.Visibility = If(value.Any(), Visibility.Visible, Visibility.Collapsed)
  140. For Each TagText In value
  141. Dim NewTag = GetObjectFromXML(
  142. "<Border xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
  143. Background=""#11000000"" Padding=""3,1"" CornerRadius=""3"" Margin=""0,0,3,0""
  144. SnapsToDevicePixels=""True"" UseLayoutRounding=""False"">
  145. <TextBlock Text=""" & TagText & """ Foreground=""#868686"" FontSize=""11"" />
  146. </Border>")
  147. PanTags.Children.Add(NewTag)
  148. Next
  149. End Set
  150. End Property
  151. #End Region
  152. #Region "点击"
  153. '触发点击事件
  154. Public Event Click(sender As Object, e As MouseButtonEventArgs)
  155. Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp
  156. If IsMouseDown Then
  157. RaiseEvent Click(sender, e)
  158. If e.Handled Then Exit Sub
  159. Log("[Control] 按下资源工程列表项:" & LabTitle.Text)
  160. End If
  161. End Sub
  162. Private Sub ProjectClick(sender As MyCompItem, e As EventArgs) Handles Me.Click
  163. '记录当前展开的卡片标题(#2712)
  164. Dim Titles As New List(Of String)
  165. If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then
  166. For Each Card As MyCard In FrmDownloadCompDetail.PanMain.Children
  167. If Card.Title <> "" AndAlso Not Card.IsSwaped Then Titles.Add(Card.Title)
  168. Next
  169. Log("[Comp] 记录当前已展开的卡片:" & String.Join("、", Titles))
  170. FrmMain.PageCurrent.Additional(1) = Titles
  171. End If
  172. '打开详情页
  173. Dim TargetVersion As String
  174. Dim TargetLoader As CompModLoaderType
  175. If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then
  176. TargetVersion = FrmMain.PageCurrent.Additional(2)
  177. TargetLoader = FrmMain.PageCurrent.Additional(3)
  178. Else
  179. Select Case CType(sender.Tag, CompProject).Type
  180. Case CompType.Mod
  181. TargetVersion = If(PageDownloadMod.Loader.Input.GameVersion, "")
  182. TargetLoader = PageDownloadMod.Loader.Input.ModLoader
  183. Case CompType.ModPack
  184. TargetVersion = If(PageDownloadPack.Loader.Input.GameVersion, "")
  185. Case CompType.DataPack
  186. TargetVersion = If(PageDownloadDataPack.Loader.Input.GameVersion, "")
  187. Case Else 'CompType.ResourcePack
  188. 'FUTURE: Res
  189. TargetVersion = "" 'If(PageDownloadResource.Loader.Input.GameVersion, "")
  190. End Select
  191. End If
  192. If CType(sender.Tag, CompProject).Type <> CompType.Mod Then TargetLoader = CompModLoaderType.Any
  193. FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail,
  194. .Additional = {sender.Tag, New List(Of String), TargetVersion, TargetLoader}})
  195. End Sub
  196. '鼠标点击判定
  197. Private IsMouseDown As Boolean = False
  198. Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
  199. If IsMouseOver AndAlso CanInteraction Then IsMouseDown = True
  200. End Sub
  201. Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.PreviewMouseLeftButtonUp
  202. IsMouseDown = False
  203. End Sub
  204. #End Region
  205. #Region "后加载指向背景"
  206. Private _RectBack As Border = Nothing
  207. Public ReadOnly Property RectBack As Border
  208. Get
  209. If _RectBack Is Nothing Then
  210. Dim Rect As New Border With {
  211. .Name = "RectBack",
  212. .CornerRadius = New CornerRadius(3),
  213. .RenderTransform = New ScaleTransform(0.8, 0.8),
  214. .RenderTransformOrigin = New Point(0.5, 0.5),
  215. .BorderThickness = New Thickness(GetWPFSize(1)),
  216. .SnapsToDevicePixels = True,
  217. .IsHitTestVisible = False,
  218. .Opacity = 0
  219. }
  220. Rect.SetResourceReference(Border.BackgroundProperty, "ColorBrush7")
  221. Rect.SetResourceReference(Border.BorderBrushProperty, "ColorBrush6")
  222. SetColumnSpan(Rect, 999)
  223. SetRowSpan(Rect, 999)
  224. Children.Insert(0, Rect)
  225. _RectBack = Rect
  226. '<!--<Border x:Name = "RectBack" CornerRadius="3" RenderTransformOrigin="0.5,0.5" SnapsToDevicePixels="True"
  227. 'IsHitTestVisible = "False" Opacity="0" BorderThickness="1"
  228. 'Grid.ColumnSpan = "4" Background="{DynamicResource ColorBrush7}" BorderBrush="{DynamicResource ColorBrush6}"/>-->
  229. End If
  230. Return _RectBack
  231. End Get
  232. End Property
  233. #End Region
  234. Private StateLast As String
  235. ''' <summary>
  236. ''' 是否允许交互。目前仅用于 PageDownloadCompDetail 的顶部栏展示:若关闭碰撞检测,则无法展开 Tooltip。
  237. ''' </summary>
  238. Public CanInteraction As Boolean = True
  239. Public Sub RefreshColor(sender As Object, e As EventArgs) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonDown, Me.MouseLeftButtonUp
  240. If Not CanInteraction Then Exit Sub
  241. '判断当前颜色
  242. Dim StateNew As String, Time As Integer
  243. If IsMouseOver Then
  244. If IsMouseDown Then
  245. StateNew = "MouseDown"
  246. Time = 120
  247. Else
  248. StateNew = "MouseOver"
  249. Time = 120
  250. End If
  251. Else
  252. StateNew = "Idle"
  253. Time = 180
  254. End If
  255. If StateLast = StateNew Then Exit Sub
  256. StateLast = StateNew
  257. '触发颜色动画
  258. If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
  259. '有动画
  260. Dim Ani As New List(Of AniData)
  261. If IsMouseOver Then
  262. Ani.AddRange({
  263. AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
  264. AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
  265. })
  266. If IsMouseDown Then
  267. Ani.Add(AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
  268. Else
  269. Ani.Add(AaScaleTransform(RectBack, 1 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
  270. End If
  271. Else
  272. Ani.AddRange({
  273. AaOpacity(RectBack, -RectBack.Opacity, Time),
  274. AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
  275. AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
  276. AaScaleTransform(RectBack, -0.196, 1,,, True)
  277. })
  278. End If
  279. AniStart(Ani, "CompItem Color " & Uuid)
  280. Else
  281. '无动画
  282. AniStop("CompItem Color " & Uuid)
  283. If _RectBack IsNot Nothing Then RectBack.Opacity = 0
  284. End If
  285. End Sub
  286. End Class