MyCompItem.xaml.vb 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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 Else 'CompType.ResourcePack
  186. 'FUTURE: Res
  187. TargetVersion = "" 'If(PageDownloadResource.Loader.Input.GameVersion, "")
  188. End Select
  189. End If
  190. If CType(sender.Tag, CompProject).Type <> CompType.Mod Then TargetLoader = CompModLoaderType.Any
  191. FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail,
  192. .Additional = {sender.Tag, New List(Of String), TargetVersion, TargetLoader}})
  193. End Sub
  194. '鼠标点击判定
  195. Private IsMouseDown As Boolean = False
  196. Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
  197. If IsMouseOver AndAlso CanInteraction Then IsMouseDown = True
  198. End Sub
  199. Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.PreviewMouseLeftButtonUp
  200. IsMouseDown = False
  201. End Sub
  202. #End Region
  203. #Region "后加载指向背景"
  204. Private _RectBack As Border = Nothing
  205. Public ReadOnly Property RectBack As Border
  206. Get
  207. If _RectBack Is Nothing Then
  208. Dim Rect As New Border With {
  209. .Name = "RectBack",
  210. .CornerRadius = New CornerRadius(3),
  211. .RenderTransform = New ScaleTransform(0.8, 0.8),
  212. .RenderTransformOrigin = New Point(0.5, 0.5),
  213. .BorderThickness = New Thickness(GetWPFSize(1)),
  214. .SnapsToDevicePixels = True,
  215. .IsHitTestVisible = False,
  216. .Opacity = 0
  217. }
  218. Rect.SetResourceReference(Border.BackgroundProperty, "ColorBrush7")
  219. Rect.SetResourceReference(Border.BorderBrushProperty, "ColorBrush6")
  220. SetColumnSpan(Rect, 999)
  221. SetRowSpan(Rect, 999)
  222. Children.Insert(0, Rect)
  223. _RectBack = Rect
  224. '<!--<Border x:Name = "RectBack" CornerRadius="3" RenderTransformOrigin="0.5,0.5" SnapsToDevicePixels="True"
  225. 'IsHitTestVisible = "False" Opacity="0" BorderThickness="1"
  226. 'Grid.ColumnSpan = "4" Background="{DynamicResource ColorBrush7}" BorderBrush="{DynamicResource ColorBrush6}"/>-->
  227. End If
  228. Return _RectBack
  229. End Get
  230. End Property
  231. #End Region
  232. Private StateLast As String
  233. ''' <summary>
  234. ''' 是否允许交互。目前仅用于 PageDownloadCompDetail 的顶部栏展示:若关闭碰撞检测,则无法展开 Tooltip。
  235. ''' </summary>
  236. Public CanInteraction As Boolean = True
  237. Public Sub RefreshColor(sender As Object, e As EventArgs) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonDown, Me.MouseLeftButtonUp
  238. If Not CanInteraction Then Exit Sub
  239. '判断当前颜色
  240. Dim StateNew As String, Time As Integer
  241. If IsMouseOver Then
  242. If IsMouseDown Then
  243. StateNew = "MouseDown"
  244. Time = 120
  245. Else
  246. StateNew = "MouseOver"
  247. Time = 120
  248. End If
  249. Else
  250. StateNew = "Idle"
  251. Time = 180
  252. End If
  253. If StateLast = StateNew Then Exit Sub
  254. StateLast = StateNew
  255. '触发颜色动画
  256. If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
  257. '有动画
  258. Dim Ani As New List(Of AniData)
  259. If IsMouseOver Then
  260. Ani.AddRange({
  261. AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
  262. AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
  263. })
  264. If IsMouseDown Then
  265. Ani.Add(AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
  266. Else
  267. Ani.Add(AaScaleTransform(RectBack, 1 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
  268. End If
  269. Else
  270. Ani.AddRange({
  271. AaOpacity(RectBack, -RectBack.Opacity, Time),
  272. AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
  273. AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
  274. AaScaleTransform(RectBack, -0.196, 1,,, True)
  275. })
  276. End If
  277. AniStart(Ani, "CompItem Color " & Uuid)
  278. Else
  279. '无动画
  280. AniStop("CompItem Color " & Uuid)
  281. If _RectBack IsNot Nothing Then RectBack.Opacity = 0
  282. End If
  283. End Sub
  284. End Class