PageDownloadMod.xaml.vb 9.3 KB

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