MyCompItem.xaml.vb 13 KB

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