PageDownloadMod.xaml.vb 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. Public Class PageDownloadMod
  2. Public Const PageSize = 40
  3. ''' <summary>
  4. ''' 在切换到该页面时自动设置的目标版本。
  5. ''' </summary>
  6. Public Shared TargetVersion As McVersion = Nothing
  7. ''' <summary>
  8. ''' 在切换到该页面时自动设置的搜索框内的内容。
  9. ''' </summary>
  10. Public Shared TargetName As String = Nothing
  11. '加载器信息
  12. Public Shared Loader As New LoaderTask(Of CompProjectRequest, Integer)("CompProject Mod", AddressOf CompProjectsGet, AddressOf LoaderInput) With {.ReloadTimeout = 60 * 1000}
  13. Public Shared Storage As New CompProjectStorage
  14. Public Shared Page As Integer = 0
  15. Private IsLoaderInited As Boolean = False
  16. Private Sub PageDownloadMod_Inited(sender As Object, e As EventArgs) Handles Me.Loaded
  17. '不知道从 Initialized 改成 Loaded 会不会有问题,但用 Initialized 会导致初始的筛选器修改被覆盖回默认值
  18. If TargetVersion IsNot Nothing Then
  19. '设置目标
  20. ResetFilter() '重置筛选器
  21. TextSearchVersion.Text = TargetVersion.Version.McName
  22. Dim GetTargetItemByName =
  23. Function(Name As String) As MyComboBoxItem
  24. For Each Item As MyComboBoxItem In ComboSearchLoader.Items
  25. If Item.Content = Name Then Return Item
  26. Next
  27. Return ComboSearchLoader.Items(0)
  28. End Function
  29. If TargetVersion.Version.HasForge Then
  30. ComboSearchLoader.SelectedItem = GetTargetItemByName("Forge")
  31. ElseIf TargetVersion.Version.HasFabric Then
  32. ComboSearchLoader.SelectedItem = GetTargetItemByName("Fabric")
  33. ElseIf TargetVersion.Version.HasNeoForge Then
  34. ComboSearchLoader.SelectedItem = GetTargetItemByName("NeoForge")
  35. End If
  36. TargetVersion = Nothing
  37. '如果已经完成请求,则重新开始
  38. If IsLoaderInited Then StartNewSearch()
  39. PanScroll.ScrollToHome()
  40. End If
  41. '加载器初始化
  42. If IsLoaderInited Then Return
  43. IsLoaderInited = True
  44. PageLoaderInit(Load, PanLoad, PanContent, PanAlways, Loader, AddressOf Load_OnFinish, AddressOf LoaderInput)
  45. If McVersionHighest = -1 Then McVersionHighest = Math.Max(McVersionHighest, Integer.Parse(CType(TextSearchVersion.Items(1), MyComboBoxItem).Content.ToString.Split(".")(1)))
  46. End Sub
  47. Private Shared Function LoaderInput() As CompProjectRequest
  48. Dim Request As New CompProjectRequest(CompType.Mod, Storage, (Page + 1) * PageSize)
  49. If FrmDownloadMod IsNot Nothing Then
  50. Dim ModLoader As CompModLoaderType = Val(FrmDownloadMod.ComboSearchLoader.SelectedItem.Tag)
  51. Dim GameVersion As String = If(FrmDownloadMod.TextSearchVersion.Text = "全部 (也可自行输入)", Nothing,
  52. If(FrmDownloadMod.TextSearchVersion.Text.Contains(".") OrElse FrmDownloadMod.TextSearchVersion.Text.Contains("w"), FrmDownloadMod.TextSearchVersion.Text, Nothing))
  53. If GameVersion IsNot Nothing AndAlso GameVersion.Contains(".") AndAlso Val(GameVersion.Split(".")(1)) < 14 AndAlso '1.14-
  54. ModLoader = CompModLoaderType.Forge Then '选择了 Forge
  55. ModLoader = CompModLoaderType.Any '此时,视作没有筛选 Mod Loader(因为部分老 Mod 没有设置自己支持的加载器)
  56. End If
  57. If TargetName IsNot Nothing Then
  58. FrmDownloadMod.TextSearchName.Text = TargetName
  59. End If
  60. With Request
  61. .SearchText = FrmDownloadMod.TextSearchName.Text
  62. .GameVersion = GameVersion
  63. .Tag = FrmDownloadMod.ComboSearchTag.SelectedItem.Tag
  64. .ModLoader = ModLoader
  65. .Source = CType(Val(FrmDownloadMod.ComboSearchSource.SelectedItem.Tag), CompSourceType)
  66. End With
  67. End If
  68. Return Request
  69. End Function
  70. '结果 UI 化
  71. Private Sub Load_OnFinish()
  72. Try
  73. Log($"[Comp] 开始可视化 Mod 列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页")
  74. '列表项
  75. PanProjects.Children.Clear()
  76. For i = Math.Min(Page * PageSize, Storage.Results.Count - 1) To Math.Min((Page + 1) * PageSize - 1, Storage.Results.Count - 1)
  77. PanProjects.Children.Add(Storage.Results(i).ToCompItem(Loader.Input.GameVersion Is Nothing, Loader.Input.ModLoader = CompModLoaderType.Any))
  78. Next
  79. '页码
  80. CardPages.Visibility = If(Storage.Results.Count > 40 OrElse
  81. Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal,
  82. Visibility.Visible, Visibility.Collapsed)
  83. LabPage.Text = Page + 1
  84. BtnPageFirst.IsEnabled = Page > 1
  85. BtnPageFirst.Opacity = If(Page > 1, 1, 0.2)
  86. BtnPageLeft.IsEnabled = Page > 0
  87. BtnPageLeft.Opacity = If(Page > 0, 1, 0.2)
  88. Dim IsRightEnabled As Boolean = '由于 WPF 的未知 bug,读取到的 IsEnabled 可能是错误的值(#3319)
  89. Storage.Results.Count > PageSize * (Page + 1) OrElse
  90. Storage.CurseForgeOffset < Storage.CurseForgeTotal OrElse Storage.ModrinthOffset < Storage.ModrinthTotal
  91. BtnPageRight.IsEnabled = IsRightEnabled
  92. BtnPageRight.Opacity = If(IsRightEnabled, 1, 0.2)
  93. '错误信息
  94. If Storage.ErrorMessage Is Nothing Then
  95. HintError.Visibility = Visibility.Collapsed
  96. Else
  97. HintError.Visibility = Visibility.Visible
  98. HintError.Text = Storage.ErrorMessage
  99. End If
  100. '强制返回顶部
  101. PanBack.ScrollToTop()
  102. Catch ex As Exception
  103. Log(ex, "可视化 Mod 列表出错", LogLevel.Feedback)
  104. End Try
  105. End Sub
  106. '自动重试
  107. Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged
  108. Select Case Loader.State
  109. Case LoadState.Failed
  110. Dim ErrorMessage As String = ""
  111. If Loader.Error IsNot Nothing Then ErrorMessage = Loader.Error.Message
  112. If ErrorMessage.Contains("不是有效的 json 文件") Then
  113. Log("[Download] 下载的 Mod 列表 json 文件损坏,已自动重试", LogLevel.Debug)
  114. PageLoaderRestart()
  115. End If
  116. End Select
  117. End Sub
  118. '切换页码
  119. Private Sub BtnPageFirst_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageFirst.Click
  120. ChangePage(0)
  121. End Sub
  122. Private Sub BtnPageLeft_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageLeft.Click
  123. ChangePage(Page - 1)
  124. End Sub
  125. Private Sub BtnPageRight_Click(sender As Object, e As RoutedEventArgs) Handles BtnPageRight.Click
  126. ChangePage(Page + 1)
  127. End Sub
  128. Private Sub ChangePage(NewPage As Integer)
  129. CardPages.IsEnabled = False
  130. Page = NewPage
  131. FrmMain.BackToTop()
  132. Log($"[Download] Mod 切换到第 {Page + 1} 页")
  133. RunInThread(
  134. Sub()
  135. Thread.Sleep(100) '等待向上滚的动画结束
  136. RunInUi(Sub() CardPages.IsEnabled = True)
  137. Loader.Start()
  138. End Sub)
  139. End Sub
  140. #Region "搜索"
  141. '搜索按钮
  142. Private Sub StartNewSearch() Handles BtnSearchRun.Click
  143. Page = 0
  144. If Loader.ShouldStart(LoaderInput()) Then Storage = New CompProjectStorage '避免连续搜索两次使得 CompProjectStorage 引用丢失(#1311)
  145. Loader.Start()
  146. End Sub
  147. Private Sub EnterTrigger(sender As Object, e As KeyEventArgs) Handles TextSearchName.KeyDown, TextSearchVersion.KeyDown
  148. If e.Key = Key.Enter Then StartNewSearch()
  149. End Sub
  150. '重置按钮
  151. Private Sub ResetFilter() Handles BtnSearchReset.Click
  152. TextSearchName.Text = ""
  153. TextSearchVersion.Text = "全部 (也可自行输入)"
  154. TextSearchVersion.SelectedIndex = 0
  155. ComboSearchSource.SelectedIndex = 0
  156. ComboSearchTag.SelectedIndex = 0
  157. ComboSearchLoader.SelectedIndex = 0
  158. Loader.LastFinishedTime = 0 '要求强制重新开始
  159. End Sub
  160. '版本选择
  161. '#3067:当下拉菜单展开时,程序会被 WPF 挂起,因而无法更新 Grid 布局,所以必须延迟到下拉菜单收起后才能更新
  162. Private Sub TextSearchVersion_TextChanged() Handles TextSearchVersion.TextChanged
  163. If Not TextSearchVersion.IsDropDownOpen Then UpdateSearchLoaderVisibility()
  164. End Sub
  165. Private Sub UpdateSearchLoaderVisibility() Handles TextSearchVersion.DropDownClosed
  166. If TextSearchVersion.Text.Contains(".") OrElse TextSearchVersion.Text.Contains("w") Then
  167. ComboSearchLoader.Visibility = Visibility.Visible
  168. Grid.SetColumnSpan(TextSearchVersion, 1)
  169. Else
  170. ComboSearchLoader.Visibility = Visibility.Collapsed
  171. Grid.SetColumnSpan(TextSearchVersion, 2)
  172. ComboSearchLoader.SelectedIndex = 0
  173. End If
  174. End Sub
  175. #End Region
  176. End Class