├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug.yml │ └── documentation.yml └── workflows │ ├── AutoBuild.yml │ ├── close-invalid-issues.yml │ └── label-resolved-issues.yml ├── .gitignore ├── Build.cmd ├── ControlX ├── .gitignore ├── Additional │ ├── Animations │ │ ├── BeginAnimation.cs │ │ ├── ControllableAnimationBase.cs │ │ └── ReverseAfterEndAnimation.cs │ └── RelativePointAnimator.cs ├── App.axaml ├── App.axaml.cs ├── Class1.cs ├── ControlX.csproj ├── Controls │ ├── Arc.cs │ ├── ContentExpandControl.cs │ ├── Rotator.cs │ ├── Scroller.cs │ └── ScrollerControlPresenter.cs ├── Converters │ ├── AutoCorrectPositionConverter.cs │ ├── BrushRoundConverter.cs │ ├── DatePickerTextConverter.cs │ ├── DateTimeToOffsetConverter.cs │ ├── InverseBooleanValueConverter.cs │ ├── MarginCreator.cs │ ├── RangeToSweepConverter.cs │ ├── RectangleHollowGeometryConverter.cs │ └── WrapContentIntoContentPresenterConverter.cs ├── Expander.axaml ├── ExpanderToggleButton.axaml ├── OptionsDisplayItem.cs ├── OptionsDisplayItemStyles.axaml ├── Program.cs ├── ProgressBar.xaml ├── Window1.axaml └── Window1.axaml.cs ├── ExamplePlugin ├── CustomValue.cs └── CustomValue.csproj ├── GithubLib ├── .editorconfig ├── GithubLib.cs └── GithubLib.csproj ├── LICENSE ├── PluginLoader ├── Cancellable.cs ├── Config.cs ├── ConfigManager.cs ├── EmptyEvent.cs ├── EmptyPlugin.cs ├── Error.cs ├── Event.cs ├── EventHandler.cs ├── Listener.cs ├── ListenerHandler.cs ├── PathLib.cs ├── Plugin.cs ├── PluginHandler.cs ├── PluginInfo.cs ├── PluginLoadEvent.cs ├── PluginLoader.cs ├── PluginLoader.csproj ├── PluginUnLoadEvent.cs ├── Runnable.cs ├── RunnableHandler.cs └── util.cs ├── README.md ├── WonderLab.Desktop ├── Program.cs └── WonderLab.Desktop.csproj ├── WonderLab ├── .github │ └── ISSUE_TEMPLATE │ │ └── bug.yml ├── App.axaml ├── App.axaml.cs ├── Directory.Build.props ├── FodyWeavers.xml ├── MainWindow.axaml ├── MainWindow.axaml.cs ├── Modules │ ├── Base │ │ ├── TaskBase.cs │ │ └── ViewModelBase.cs │ ├── Const │ │ ├── InfoConst.cs │ │ └── PathConst.cs │ ├── Controls │ │ ├── Arc.cs │ │ ├── Cards │ │ │ ├── OptionsDisplayItem.cs │ │ │ └── UserCard.cs │ │ ├── Frame.cs │ │ ├── FrontalSkinX.cs │ │ ├── Page.cs │ │ ├── Rotator.cs │ │ ├── ScrollContentPresenter.cs │ │ ├── Styles │ │ │ ├── CaptionButtonsStyle.axaml │ │ │ ├── ContentDialog.axaml │ │ │ ├── FrameXStyle.axaml │ │ │ ├── FrontalSkinXStyle.axaml │ │ │ ├── ListBoxStyle.axaml │ │ │ ├── OptionsDisplayItemStyles.axaml │ │ │ ├── ScrollViewerStyle.axaml │ │ │ ├── TextBoxStyle.axaml │ │ │ ├── TitleBarStyle.axaml │ │ │ ├── ToolTipStyle.axaml │ │ │ ├── UserCardStyle.axaml │ │ │ └── UserListBoxItemStyle.axaml │ │ ├── TextCommandBarFlyoutX.cs │ │ └── TitleBar.cs │ ├── Enum │ │ ├── DownType.cs │ │ ├── LaunchFailedType.cs │ │ └── LogTyoe.cs │ ├── Interface │ │ ├── IPackToolkit.cs │ │ └── ITask.cs │ ├── Media │ │ ├── DrillInNavigationTransitionInfoX.cs │ │ ├── EntranceNavigationTransitionInfoX.cs │ │ ├── TeachingTipAnimation.cs │ │ └── ZoomOutAnimation.cs │ ├── Models │ │ ├── CurseForgeModel.cs │ │ ├── DataModels.cs │ │ ├── GameCoreItem.cs │ │ ├── GameCoreViewData.cs │ │ ├── GameDataModels.cs │ │ ├── GameLogType.cs │ │ ├── InfoBarModel.cs │ │ ├── LogModels.cs │ │ ├── LogType.cs │ │ ├── LogViewData.cs │ │ ├── ModDataModel.cs │ │ ├── ModInfoModels.cs │ │ ├── ModLangDataModel.cs │ │ ├── NewsModels.cs │ │ ├── OtherDataModels.cs │ │ ├── ResourcePackViewData.cs │ │ ├── SaveUserDataModels.cs │ │ ├── TransformationModel.cs │ │ ├── UserDataModels.cs │ │ └── UserViewDataModels.cs │ └── Toolkits │ │ ├── BitmapToolkit.cs │ │ ├── ClipboardToolkt.cs │ │ ├── CryptoToolkit.cs │ │ ├── ExtendToolkit.cs │ │ ├── FileToolkit.cs │ │ ├── GameLogToolkit.cs │ │ ├── JavaToolkit.cs │ │ ├── JsonToolkit.cs │ │ ├── LanguageToolkit.cs │ │ ├── LogToolkit.cs │ │ ├── McVersionLib.cs │ │ ├── OptionsToolkit.cs │ │ ├── ScriptToolkit.cs │ │ ├── StringToolkit.cs │ │ ├── TasksTooklit.cs │ │ └── WebToolkit.cs ├── PluginAPI │ ├── DownloadAsyncEvent.cs │ ├── GameDeleteEvent.cs │ ├── GameLaunchAsyncEvent.cs │ ├── PluginSetting.cs │ ├── UpdataCheckEvent.cs │ └── WonderLabPlugin.cs ├── Plugins │ └── Plugins.json ├── Program.cs ├── Properties │ ├── Resources.Designer.cs │ └── Resources.resx ├── Resources │ ├── Icon.ico │ ├── ModData.json │ ├── Strings │ │ ├── en-us.axaml │ │ ├── zh-cn.axaml │ │ └── zh-stem.axaml │ ├── WonderLab.Desktop │ ├── WonderLab.Desktop-Linux │ ├── WonderLab.Desktop.exe │ ├── fabric.png │ ├── forge.png │ ├── normal.png │ ├── sdf.png │ └── xcmy.jpg ├── ViewLocator.cs ├── ViewModels │ ├── ConsoleWindowViewModel.cs │ ├── DownGameViewModel.cs │ ├── DownItemViewModel.cs │ ├── DownModViewModel.cs │ ├── DownSettingViewModel.cs │ ├── DownViewModel.cs │ ├── ExplosionRadioViewModel.cs │ ├── GameItemViewModel.cs │ ├── GameSettingViewModel.cs │ ├── GameViewModels.cs │ ├── HomeViewModel.cs │ ├── IndependencyCoreSettingViewModel.cs │ ├── LaunchItemViewModel.cs │ ├── MainPropertyViewModel.cs │ ├── MainViewModel.cs │ ├── MainWindowViewModel.cs │ ├── ModPropertyViewModel.cs │ ├── OtherViewModel.cs │ ├── PropertyViewModel.cs │ ├── ResourceViewModel.cs │ ├── StructureViewModel.cs │ └── UsersViewModel.cs ├── Views │ ├── BlessingView.axaml │ ├── BlessingView.axaml.cs │ ├── ColorSettingView.axaml │ ├── ColorSettingView.axaml.cs │ ├── ConsoleView.axaml │ ├── ConsoleView.axaml.cs │ ├── ConsoleWindow.axaml │ ├── ConsoleWindow.axaml.cs │ ├── Converters │ │ ├── BitmapConverter.cs │ │ ├── BoolConverter.cs │ │ ├── ErrorLogConverter.cs │ │ ├── GameCoreNameConverter.cs │ │ ├── HeightConverter.cs │ │ ├── LoaderConverter.cs │ │ ├── LoaderEnabledConverter.cs │ │ ├── LoaderListConverter.cs │ │ ├── LogBrushConverter.cs │ │ ├── ModDescriptionConverter.cs │ │ ├── ModIconConverter.cs │ │ ├── ModLoaderConverter.cs │ │ ├── PrefixConverter.cs │ │ ├── UserNameConverter.cs │ │ └── UserTypeConverter.cs │ ├── DebugWindow.axaml │ ├── DebugWindow.axaml.cs │ ├── DownCustomView.axaml │ ├── DownCustomView.axaml.cs │ ├── DownGameView.axaml │ ├── DownGameView.axaml.cs │ ├── DownItemView.axaml │ ├── DownItemView.axaml.cs │ ├── DownModView.axaml │ ├── DownModView.axaml.cs │ ├── DownSettingView.axaml │ ├── DownSettingView.axaml.cs │ ├── DownView.axaml │ ├── DownView.axaml.cs │ ├── ExplosionRadioView.axaml │ ├── ExplosionRadioView.axaml.cs │ ├── GameItemView.axaml │ ├── GameItemView.axaml.cs │ ├── GameSettingView.axaml │ ├── GameSettingView.axaml.cs │ ├── GameView.axaml │ ├── GameView.axaml.cs │ ├── HomeView.axaml │ ├── HomeView.axaml.cs │ ├── IndependencyCoreSettingView.axaml │ ├── IndependencyCoreSettingView.axaml.cs │ ├── LaunchItemView.axaml │ ├── LaunchItemView.axaml.cs │ ├── MainPropertyView.axaml │ ├── MainPropertyView.axaml.cs │ ├── MainView.axaml │ ├── MainView.axaml.cs │ ├── ModPropertyView.axaml │ ├── ModPropertyView.axaml.cs │ ├── NewItemView.axaml │ ├── NewItemView.axaml.cs │ ├── NewsView.axaml │ ├── NewsView.axaml.cs │ ├── OtherView.axaml │ ├── OtherView.axaml.cs │ ├── PropertyView.axaml │ ├── PropertyView.axaml.cs │ ├── ResourceView.axaml │ ├── ResourceView.axaml.cs │ ├── SettingView.axaml │ ├── SettingView.axaml.cs │ ├── StructureView.axaml │ ├── StructureView.axaml.cs │ ├── TaskView.axaml │ ├── TaskView.axaml.cs │ ├── UsersView.axaml │ └── UsersView.axaml.cs ├── WonderLabX.csproj ├── icon.ico ├── wonderlab.desktop └── wonderlab.png ├── WonderLabAur ├── PKGBUILD └── WonderLab.tar.gz ├── WonderLabX.sln ├── autoMake └── javaInfo ├── LICENSE ├── README.md ├── javaInfo.sln └── javaInfo ├── Java.cs └── javaInfo.csproj /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # SYSLIB0014: 类型或成员已过时 4 | dotnet_diagnostic.SYSLIB0014.severity = none 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug 反馈 2 | description: 反馈 WonderLab 使用中遇到的问题和 Bug 3 | labels: 4 | - "bug" 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | 感谢你使用 WonderLab 问题反馈系统! 11 | 12 | 如果此问题反馈不符合模板,将会被管理员无条件关闭。 13 | - type: checkboxes 14 | attributes: 15 | label: '❗ 检查表' 16 | description: 在反馈前, 请确认你已经做了下面这些事情 17 | options: 18 | - label: 搜索了已有的 [issues](https://github.com/Blessing-Studio/WonderLab/issues) 列表中是否有相似问题 19 | required: true 20 | - label: 查看 [Releases](https://github.com/Blessing-Studio/WonderLab/releases) 中最新版是否已修复你所遇到的问题 21 | required: true 22 | - label: 查看 [Actions](https://github.com/Blessing-Studio/WonderLab/Actions) 中最新Dev版是否已修复你所遇到的问题 23 | required: true 24 | 25 | - type: textarea 26 | id: issue-description 27 | attributes: 28 | label: 问题描述 29 | description: 在此详细描述你遇到的问题(日志和此处二选一 都提交可以让我们更快修复) 30 | validations: 31 | required: true 32 | - type: textarea 33 | id: issue-log 34 | attributes: 35 | label: 日志 36 | description: 在此提交崩溃日志 37 | validations: 38 | required: false 39 | - type: dropdown 40 | id: reproducibility 41 | attributes: 42 | label: 问题复现率 43 | description: 选择问题发生的概率 44 | options: 45 | - 无法复现 46 | - 低偶发 47 | - 高偶发 48 | - 必现 49 | validations: 50 | required: true 51 | 52 | - type: textarea 53 | id: reproduce 54 | attributes: 55 | label: 复现步骤 56 | description: 在这里简略说明如何让这个问题再次发生 57 | placeholder: | 58 | 在这里简略说明如何让这个问题再次发生 59 | 可使用 1. 2. 3. 的列表格式,或其他任意恰当的格式 60 | 如果你不确定如何复现, 请尽量描述发生当时的情景 61 | validations: 62 | required: true 63 | 64 | - type: dropdown 65 | id: server-platform-type 66 | attributes: 67 | label: 操作系统版本 68 | description: | 69 | 选择你正在使用的操作系统 70 | options: 71 | - '全平台' 72 | - Windows 73 | - Linux 74 | - Mac 75 | validations: 76 | required: true 77 | 78 | - type: textarea 79 | id: slimefun-version 80 | validations: 81 | required: true 82 | attributes: 83 | label: WonderLab版本 84 | description: | 85 | **"最新版" 不是版本号,请填写一个确切的版本号!** 86 | #如果你不太确定,可以截图 "" 的输出内容并截图,记得截全。 87 | placeholder: '1.0.1.x' 88 | 89 | - type: textarea 90 | id: other-plugin 91 | attributes: 92 | label: 插件信息 93 | description: 如果这个问题与你的其他插件有关,请提供你的WonderLab插件列表。 94 | placeholder: | 95 | 插件: 版本 96 | 97 | - type: textarea 98 | id: additional 99 | attributes: 100 | label: 补充信息 101 | description: 如有必要,你可以在下文继续添加其他信息 102 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.yml: -------------------------------------------------------------------------------- 1 | name: 建议反馈 2 | description: 反馈你的想法 3 | labels: 4 | - "建议" 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | 感谢你使用 WonderLab 问题反馈系统! 11 | 12 | 如果此建议反馈不符合模板,将会被管理员无条件关闭。 13 | - type: textarea 14 | id: issue-description 15 | attributes: 16 | label: 建议描述 17 | description: 在此详细描述你的想法 18 | validations: 19 | required: true 20 | 21 | validations: 22 | required: true 23 | 24 | - type: dropdown 25 | id: server-platform-type 26 | attributes: 27 | label: 操作系统版本 28 | description: | 29 | 选择你正在使用的操作系统 30 | options: 31 | - Windows 32 | - Linux 33 | - Mac 34 | validations: 35 | required: true 36 | 37 | - type: textarea 38 | id: slimefun-version 39 | validations: 40 | required: true 41 | attributes: 42 | label: WonderLab版本 43 | description: | 44 | **"最新版" 不是版本号,请填写一个确切的版本号!** 45 | #如果你不太确定,可以截图 "" 的输出内容并截图,记得截全。 46 | placeholder: '1.0.1.0' 47 | 48 | - type: textarea 49 | id: additional 50 | attributes: 51 | label: 补充信息 52 | description: 如有必要,你可以在下文继续添加其他信息 53 | -------------------------------------------------------------------------------- /.github/workflows/close-invalid-issues.yml: -------------------------------------------------------------------------------- 1 | name: Close invalid Issue 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | 7 | jobs: 8 | comment: 9 | 10 | name: Invalid Issues 11 | runs-on: ubuntu-latest 12 | 13 | if: contains(github.event.issue.labels.*.name, 'bug') == false && contains(github.event.issue.labels.*.name, '建议') == false 14 | steps: 15 | - name: Close Issue 16 | uses: maxkomarychev/octions/octions/issues/update@master 17 | with: 18 | token: ${{ secrets.ACCESS_TOKEN }} 19 | issue_number: ${{ github.event.issue.number }} 20 | state: closed 21 | - name: Add invalid label 22 | uses: maxkomarychev/octions/octions/issues/add-labels@master 23 | with: 24 | token: ${{ secrets.ACCESS_TOKEN }} 25 | issue_number: ${{ github.event.issue.number }} 26 | labels: '无效' 27 | - name: Create a comment 28 | uses: maxkomarychev/octions/octions/issues/create-comment@master 29 | with: 30 | token: ${{ secrets.ACCESS_TOKEN }} 31 | issue_number: ${{ github.event.issue.number }} 32 | body: |- 33 | 你的议题必须使用我们的模版 34 | [点击这里选择一个模版并创建新议题](https://github.com/Blessing-Studio/WonderLab/issues/new/choose) 35 | -------------------------------------------------------------------------------- /.github/workflows/label-resolved-issues.yml: -------------------------------------------------------------------------------- 1 | name: Label resolved issues 2 | 3 | on: 4 | issues: 5 | types: [closed] 6 | 7 | permissions: 8 | contents: read 9 | issues: write 10 | 11 | jobs: 12 | label: 13 | 14 | name: Label Issue 15 | runs-on: ubuntu-latest 16 | if: (contains(github.event.issue.labels.*.name, 'bug') || contains(github.event.issue.labels.*.name, '建议')) && contains(github.event.issue.labels.*.name, '无效') == false 17 | 18 | steps: 19 | - name: Query recent commits 20 | uses: TheBusyBiscuit/recently-closed-issues@1.1.0 21 | id: resolved 22 | with: 23 | token: ${{ secrets.ACCESS_TOKEN }} 24 | max_commits: 20 25 | 26 | - name: Add label 27 | uses: maxkomarychev/octions/octions/issues/add-labels@master 28 | with: 29 | token: ${{ secrets.ACCESS_TOKEN }} 30 | issue_number: ${{ github.event.issue.number }} 31 | labels: '已解决' 32 | - name: Create a comment 33 | uses: maxkomarychev/octions/octions/issues/create-comment@master 34 | with: 35 | token: ${{ secrets.ACCESS_TOKEN }} 36 | issue_number: ${{ github.event.issue.number }} 37 | body: |- 38 | 你的议题已解决 39 | 感谢反馈 40 | [点击这里反馈新问题](https://github.com/Blessing-Studio/WonderLab/issues/new/choose) 41 | -------------------------------------------------------------------------------- /Build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | ver|findstr /r /i " [版本 10.0.*]" > NUL && goto Windows10+ 3 | goto UnknownVersion 4 | 5 | :Windows10+ 6 | winget install Microsoft.Dotnet.SDK.6 7 | goto Build 8 | 9 | :UnknownVersion 10 | echo 请确认你已经安装了.net6 sdk 11 | pause 12 | goto Build 13 | 14 | :Build 15 | dotnet build --configuration Release 16 | 17 | echo 编译完成 请到WonderLab\WonderLab\bin查看结果 18 | pause 19 | -------------------------------------------------------------------------------- /ControlX/Additional/Animations/BeginAnimation.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Subjects; 2 | 3 | namespace ControlX.Styles.Additional.Animations { 4 | /// 5 | /// Tracks the progress of an animation. Will always continue to end or until restart. 6 | /// Perhaps this has already been implemented without such crutches. Issue: 7 | /// https://github.com/AvaloniaUI/Avalonia/issues/4673 8 | /// 9 | public class BeginAnimation : ControllableAnimationBase { 10 | internal override void OnNext(Subject match, bool previous, bool obj) { 11 | if (!obj) return; 12 | // "Turning" off 13 | match.OnNext(false); 14 | 15 | // Then "turning" on 16 | match.OnNext(true); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /ControlX/Additional/Animations/ControllableAnimationBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Subjects; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Avalonia; 6 | using Avalonia.Animation; 7 | using Avalonia.Metadata; 8 | 9 | namespace ControlX.Styles.Additional.Animations { 10 | /// 11 | /// Tracks the progress of an animation. This class should act the same as 12 | /// 13 | public class ControllableAnimationBase : AvaloniaObject, IAnimation { 14 | public static readonly DirectProperty AnimationProperty = 15 | AvaloniaProperty.RegisterDirect( 16 | nameof(_animation), 17 | o => o._animation, 18 | (o, v) => o._animation = v); 19 | 20 | #pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 21 | private Animation _animation; 22 | #pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 23 | 24 | [Content] 25 | public Animation Animation { 26 | get => _animation; 27 | set => SetAndRaise(AnimationProperty, ref _animation, value); 28 | } 29 | 30 | public virtual IDisposable Apply(Animatable control, IClock clock, IObservable match, Action onComplete = null) { 31 | var previous = false; 32 | var observable = new Subject(); 33 | match.Subscribe(b => { 34 | OnNext(observable, previous, b); 35 | previous = b; 36 | }); 37 | return Animation.Apply(control, clock, observable, onComplete); 38 | } 39 | 40 | public virtual Task RunAsync(Animatable control, IClock clock, CancellationToken cancellationToken = new CancellationToken()) { 41 | return Animation.RunAsync(control, clock, cancellationToken); 42 | } 43 | 44 | internal virtual void OnNext(Subject match, bool previous, bool obj) { 45 | match.OnNext(obj); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /ControlX/Additional/Animations/ReverseAfterEndAnimation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Subjects; 3 | using System.Threading.Tasks; 4 | using Avalonia.Animation; 5 | 6 | namespace ControlX.Styles.Additional.Animations { 7 | public class ReverseAfterEndAnimation : ControllableAnimationBase { 8 | public bool WaitTillEnd { get; set; } = false; 9 | 10 | // Required WaitTillEnd == true 11 | public TimeSpan DelayBetweenReverse { get; set; } = TimeSpan.Zero; 12 | 13 | public override IDisposable Apply(Animatable control, IClock clock, IObservable match, Action onComplete = null) { 14 | var reversedAnimation = new Animation { 15 | Delay = Animation.Delay, Duration = Animation.Duration, Easing = Animation.Easing, FillMode = Animation.FillMode, 16 | IterationCount = new IterationCount(1), SpeedRatio = Animation.SpeedRatio 17 | }; 18 | reversedAnimation.Children.AddRange(Animation.Children); 19 | reversedAnimation.PlaybackDirection = Animation.PlaybackDirection switch { 20 | PlaybackDirection.Normal => PlaybackDirection.Reverse, 21 | PlaybackDirection.Reverse => PlaybackDirection.Normal, 22 | PlaybackDirection.Alternate => PlaybackDirection.AlternateReverse, 23 | PlaybackDirection.AlternateReverse => PlaybackDirection.Alternate, 24 | _ => PlaybackDirection.Reverse 25 | }; 26 | 27 | var lastValue = false; 28 | // Applying reversed animation 29 | var reversedObserver = new Subject(); 30 | var timeOut = Task.CompletedTask; 31 | 32 | match.Subscribe(async b => { 33 | if (lastValue == b) return; 34 | lastValue = b; 35 | if (b) { 36 | reversedObserver.OnNext(false); 37 | timeOut = Task.Delay(reversedAnimation.Duration + DelayBetweenReverse); 38 | } 39 | else { 40 | await timeOut; 41 | reversedObserver.OnNext(true); 42 | } 43 | }); 44 | reversedAnimation.Apply(control, clock, reversedObserver, () => { }); 45 | 46 | return base.Apply(control, clock, match, onComplete); 47 | } 48 | 49 | internal override void OnNext(Subject match, bool previous, bool obj) { 50 | if (WaitTillEnd) { 51 | if (obj) return; 52 | // "Turning" off 53 | match.OnNext(false); 54 | 55 | // Then "turning" on 56 | match.OnNext(true); 57 | } 58 | else { 59 | base.OnNext(match, previous, obj); 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /ControlX/Additional/RelativePointAnimator.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Animation.Animators; 3 | 4 | namespace ControlX.Styles.Additional { 5 | public class RelativePointAnimator : Animator { 6 | public override RelativePoint Interpolate(double progress, RelativePoint oldValue, RelativePoint newValue) { 7 | return new RelativePoint( 8 | (newValue.Point.X - oldValue.Point.X) * progress + oldValue.Point.X, 9 | (newValue.Point.Y - oldValue.Point.Y) * progress + oldValue.Point.Y, 10 | newValue.Unit); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /ControlX/App.axaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ControlX/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Markup.Xaml; 4 | 5 | namespace ControlX 6 | { 7 | public partial class App : Application 8 | { 9 | public override void Initialize() 10 | { 11 | AvaloniaXamlLoader.Load(this); 12 | } 13 | 14 | public override void OnFrameworkInitializationCompleted() 15 | { 16 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 17 | { 18 | desktop.MainWindow = new Window1(); 19 | } 20 | 21 | base.OnFrameworkInitializationCompleted(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ControlX/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ControlX 8 | { 9 | public class Class1 10 | { 11 | 12 | public static double NaN = 0D / 0D; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ControlX/ControlX.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Library 4 | net6.0 5 | osx-x64;linux-x64;win-x64 6 | enable 7 | 8 | copyused 9 | true 10 | 11 | 12 | 13 | CS0693;CS8602;CS8670;CS8618;CS8762 14 | 15 | 16 | CS0693;CS8602;CS8670;CS8618;CS8762 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Designer 25 | MSBuild:Compile 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ControlX/Controls/ContentExpandControl.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Layout; 3 | using Avalonia; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace ControlX.Controls 11 | { 12 | public class ContentExpandControl : ContentControl 13 | { 14 | public static readonly StyledProperty MultiplierProperty = 15 | AvaloniaProperty.Register(nameof(Multiplier)); 16 | 17 | public double Multiplier 18 | { 19 | get => GetValue(MultiplierProperty); 20 | set => SetValue(MultiplierProperty, value); 21 | } 22 | 23 | public static readonly StyledProperty OrientationProperty = 24 | AvaloniaProperty.Register(nameof(Orientation)); 25 | 26 | public Orientation Orientation 27 | { 28 | get => GetValue(OrientationProperty); 29 | set => SetValue(OrientationProperty, value); 30 | } 31 | 32 | static ContentExpandControl() 33 | { 34 | AffectsArrange(MultiplierProperty, 35 | OrientationProperty); 36 | 37 | AffectsMeasure(MultiplierProperty, 38 | OrientationProperty); 39 | } 40 | 41 | protected override void ArrangeCore(Rect finalRect) 42 | { 43 | base.ArrangeCore(finalRect); 44 | } 45 | 46 | protected override Size MeasureCore(Size availableSize) 47 | { 48 | var result = base.MeasureCore(availableSize); 49 | return result; 50 | } 51 | 52 | protected override Size ArrangeOverride(Size finalSize) 53 | { 54 | var result = base.ArrangeOverride(finalSize); 55 | return result; 56 | } 57 | 58 | protected override Size MeasureOverride(Size availableSize) 59 | { 60 | var result = base.MeasureOverride(availableSize); 61 | 62 | var w = result.Width; 63 | var h = result.Height; 64 | 65 | switch (Orientation) 66 | { 67 | case Orientation.Horizontal: 68 | w *= Multiplier; 69 | break; 70 | 71 | case Orientation.Vertical: 72 | h *= Multiplier; 73 | break; 74 | default: 75 | throw new ArgumentOutOfRangeException(); 76 | } 77 | 78 | return new Size(w, h); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /ControlX/Controls/ScrollerControlPresenter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reactive.Disposables; 5 | using System.Reactive.Linq; 6 | using Avalonia; 7 | using Avalonia.Controls; 8 | using Avalonia.Controls.Presenters; 9 | using Avalonia.Controls.Primitives; 10 | using Avalonia.Input; 11 | using Avalonia.VisualTree; 12 | 13 | #nullable enable 14 | 15 | namespace ControlX.Styles.Controls 16 | { 17 | /// 18 | /// Presents a scrolling view of content inside a . 19 | /// 20 | public class ScrollerContentPresenter : ScrollContentPresenter 21 | { 22 | protected override void OnPointerWheelChanged(PointerWheelEventArgs e) 23 | { 24 | // Scroll Horizontally default when content width greater than viewport width 25 | // and the height of content is less equal than viewport height 26 | if (Extent.Width > Viewport.Width) 27 | { 28 | var scrollable = Child as ILogicalScrollable; 29 | bool isLogical = scrollable?.IsLogicalScrollEnabled == true; 30 | 31 | double x = Offset.X; 32 | double y = Offset.Y; 33 | 34 | double width = isLogical ? scrollable!.ScrollSize.Width : 50; 35 | x += -e.Delta.Y * width; 36 | x = Math.Max(x, 0); 37 | x = Math.Min(x, Extent.Width - Viewport.Width); 38 | 39 | Offset = new Vector(x, y); 40 | e.Handled = true; 41 | } 42 | 43 | /*if (Extent.Height > Viewport.Height || Extent.Width > Viewport.Width) 44 | { 45 | var scrollable = Child as ILogicalScrollable; 46 | bool isLogical = scrollable?.IsLogicalScrollEnabled == true; 47 | 48 | double x = Offset.X; 49 | double y = Offset.Y; 50 | 51 | if (Extent.Height > Viewport.Height) 52 | { 53 | double height = isLogical ? scrollable!.ScrollSize.Height : 50; 54 | y += -e.Delta.Y * height; 55 | y = Math.Max(y, 0); 56 | y = Math.Min(y, Extent.Height - Viewport.Height); 57 | } 58 | 59 | if (Extent.Width > Viewport.Width) 60 | { 61 | double width = isLogical ? scrollable!.ScrollSize.Width : 50; 62 | x += -e.Delta.X * width; 63 | x = Math.Max(x, 0); 64 | x = Math.Min(x, Extent.Width - Viewport.Width); 65 | } 66 | 67 | Offset = new Vector(x, y); 68 | e.Handled = true; 69 | }*/ 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ControlX/Converters/AutoCorrectPositionConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using Avalonia; 5 | using Avalonia.Controls; 6 | using Avalonia.Data.Converters; 7 | using Avalonia.Media; 8 | using Avalonia.Media.Transformation; 9 | using Avalonia.VisualTree; 10 | 11 | namespace Material.Styles.Converters 12 | { 13 | public class AutoCorrectPositionConverter : IValueConverter 14 | { 15 | public static double DefaultOffsetY = 0; 16 | 17 | private static double GetOffLeft(Rect bounds, double offsetX) => offsetX; 18 | 19 | private static double GetOffRight(Rect bounds, double windowW, double offsetX) => offsetX + (bounds.Width) - windowW; 20 | 21 | private static Vector GetTranslate(TransformedBounds bounds) 22 | { 23 | return new Vector(bounds.Transform.M31, bounds.Transform.M32); 24 | } 25 | 26 | private Vector _prevCorrect = Vector.One; 27 | 28 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 29 | { 30 | var transformedBounds = value as TransformedBounds?; 31 | 32 | double offsetX = 0; 33 | if (transformedBounds.HasValue) 34 | { 35 | var bounds = transformedBounds.Value; 36 | 37 | var translate = GetTranslate(bounds); 38 | 39 | var left = GetOffLeft(bounds.Bounds, translate.X - _prevCorrect.X); 40 | var right = GetOffRight(bounds.Bounds, bounds.Clip.Width, translate.X- _prevCorrect.X); 41 | 42 | if (left < 0) 43 | { 44 | offsetX = -left; 45 | //_prevCorrect = new Vector(offsetX, DefaultOffsetY); 46 | } 47 | else if (right > 0) 48 | { 49 | offsetX = -right; 50 | // _prevCorrect = new Vector(offsetX, DefaultOffsetY); 51 | } 52 | } 53 | return new TranslateTransform(offsetX, DefaultOffsetY); 54 | } 55 | 56 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 57 | { 58 | throw new NotImplementedException(); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /ControlX/Converters/BrushRoundConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | using Avalonia.Media; 5 | 6 | namespace Material.Styles.Converters { 7 | public class BrushRoundConverter : IValueConverter { 8 | public static readonly IValueConverter Instance = new BrushRoundConverter(); 9 | public Brush HighValue { get; set; } = new SolidColorBrush(Brushes.White.Color); 10 | 11 | public Brush LowValue { get; set; } = new SolidColorBrush(Brushes.Black.Color); 12 | 13 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { 14 | if (!(value is SolidColorBrush solidColorBrush)) return null; 15 | 16 | var color = solidColorBrush.Color; 17 | 18 | var brightness = 0.3 * color.R + 0.59 * color.G + 0.11 * color.B; 19 | 20 | return brightness < 123 ? LowValue : HighValue; 21 | } 22 | 23 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { 24 | throw new NotImplementedException(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /ControlX/Converters/DatePickerTextConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using Avalonia; 5 | using Avalonia.Data; 6 | using Avalonia.Data.Converters; 7 | 8 | namespace Material.Styles.Converters { 9 | public class DatePickerTextConverter : IMultiValueConverter { 10 | public static DatePickerTextConverter Instance { get; } = new DatePickerTextConverter(); 11 | public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) { 12 | // ReSharper disable once ConditionIsAlwaysTrueOrFalse 13 | // ReSharper disable once HeuristicUnreachableCode 14 | try { 15 | return values[0] is UnsetValueType || values[0] == null ? "Not selected" : ((DateTimeOffset)values[0]).ToString((string)values[1]); 16 | } 17 | catch (Exception) { 18 | return BindingOperations.DoNothing; 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /ControlX/Converters/DateTimeToOffsetConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | 5 | namespace Material.Styles.Converters { 6 | public class DateTimeToOffsetConverter : IValueConverter { 7 | public static DateTimeToOffsetConverter Instance { get; } = new DateTimeToOffsetConverter(); 8 | 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { 10 | if (value is DateTimeOffset offset) { 11 | return offset.Date; 12 | } 13 | 14 | return value; 15 | } 16 | 17 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { 18 | if (value is DateTime dateTime) { 19 | return new DateTimeOffset(dateTime); 20 | } 21 | 22 | return value; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /ControlX/Converters/InverseBooleanValueConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | 5 | namespace Material.Styles { 6 | internal class InverseBooleanValueConverter : IValueConverter { 7 | public bool Default { get; set; } 8 | 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { 10 | return value is bool b ? !b : Default; 11 | } 12 | 13 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { 14 | return value is bool b ? !b : !Default; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /ControlX/Converters/MarginCreator.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Data.Converters; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Globalization; 6 | using System.Text; 7 | 8 | namespace Material.Styles.Converters 9 | { 10 | /// 11 | /// Converter for NavigationDrawer use. 12 | /// 13 | public class MarginCreator : IMultiValueConverter 14 | { 15 | public const double Offset = -8; 16 | 17 | public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | if ((values[0] is double left)) 20 | return createMargin(left: -left + Offset); 21 | if ((values[1] is double up)) 22 | return createMargin(up: -up + Offset); 23 | if ((values[2] is double right)) 24 | return createMargin(right: -right + Offset); 25 | if ((values[3] is double down)) 26 | return createMargin(down: -down + Offset); 27 | return createMargin(); 28 | } 29 | 30 | public static Thickness createMargin(double left = 0, double up = 0, double right = 0, double down = 0) => new Thickness(left, up, right, down); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ControlX/Converters/RangeToSweepConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using Avalonia.Data.Converters; 5 | 6 | // ReSharper disable HeapView.BoxingAllocation 7 | 8 | namespace Material.Styles.Converters 9 | { 10 | public class RangeToSweepConverter : IMultiValueConverter 11 | { 12 | public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) 13 | { 14 | double min = 0, max = 100, val = 0; 15 | 16 | if (values[0] is double value) 17 | { 18 | val = value; 19 | } 20 | 21 | if (values.Count >= 2 && values[1] is double minimum) 22 | { 23 | min = minimum; 24 | } 25 | 26 | if (values.Count >= 3 && values[2] is double maximum) 27 | { 28 | max = maximum; 29 | } 30 | 31 | double m = max - min; 32 | var result = val / m; 33 | return result * 360; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /ControlX/Converters/WrapContentIntoContentPresenterConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Controls; 4 | using Avalonia.Controls.Presenters; 5 | using Avalonia.Data.Converters; 6 | 7 | namespace Material.Styles.Converters { 8 | internal class WrapContentIntoContentPresenterConverter : IValueConverter { 9 | public static WrapContentIntoContentPresenterConverter Instance { get; } = new WrapContentIntoContentPresenterConverter(); 10 | 11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { 12 | return value is IControl ? value : new ContentPresenter() { Content = value }; 13 | 14 | } 15 | 16 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { 17 | throw new NotSupportedException(); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /ControlX/Program.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Controls.ApplicationLifetimes; 4 | using System; 5 | 6 | namespace ControlX 7 | { 8 | internal class Program 9 | { 10 | // Initialization code. Don't use any Avalonia, third-party APIs or any 11 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 12 | // yet and stuff might break. 13 | [STAThread] 14 | public static void Main(string[] args) => BuildAvaloniaApp() 15 | .StartWithClassicDesktopLifetime(args); 16 | 17 | // Avalonia configuration, don't remove; also used by visual designer. 18 | public static AppBuilder BuildAvaloniaApp() 19 | => AppBuilder.Configure() 20 | .UsePlatformDetect() 21 | .LogToTrace(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ControlX/Window1.axaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /WonderLab/Views/GameItemView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | using WonderLab.Modules.Base; 5 | using WonderLab.Modules.Controls; 6 | using WonderLab.ViewModels; 7 | 8 | namespace WonderLab.Views 9 | { 10 | public partial class GameItemView : Page 11 | { 12 | public GameItemView(GameItemViewModel model) => InitializeComponent(model); 13 | public GameItemView() => InitializeComponent(); 14 | 15 | private void InitializeComponent(GameItemViewModel model) 16 | { 17 | InitializeComponent(true); 18 | this.DataContext = model; 19 | PointerEnter += model.MoveInAction; 20 | PointerLeave += model.MoveOutAction; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /WonderLab/Views/GameSettingView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | using Avalonia.Threading; 5 | using Microsoft.VisualBasic; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Diagnostics; 9 | using System.Linq; 10 | using System.Runtime.InteropServices; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using WonderLab.Modules.Controls; 14 | using WonderLab.ViewModels; 15 | 16 | namespace WonderLab.Views 17 | { 18 | public partial class GameSettingView : Page 19 | { 20 | public GameSettingViewModel ViewModel = new(); 21 | public GameSettingView() 22 | { 23 | InitializeComponent(); 24 | DataContext = ViewModel; 25 | } 26 | 27 | public override void OnNavigatedTo() 28 | { 29 | try { 30 | if (App.Data.GameFooterList is not null && App.Data.GameFooterList.Count != 0) { 31 | ViewModel.CurrentGameFolder = App.Data.FooterPath; 32 | } 33 | 34 | ViewModel.IsOlate = App.Data.Isolate; 35 | } catch (Exception ex) { 36 | Trace.WriteLine("[Error] " + ex.ToString()); 37 | } 38 | } 39 | 40 | private void InitializeComponent() => InitializeComponent(true); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /WonderLab/Views/HomeView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | using Avalonia.Media; 5 | using Avalonia.Threading; 6 | using FluentAvalonia.UI.Controls; 7 | using MinecraftLaunch.Modules.Toolkits; 8 | using System; 9 | using System.ComponentModel; 10 | using System.Diagnostics; 11 | using System.Linq; 12 | using System.Threading.Tasks; 13 | using WonderLab.Modules.Base; 14 | using WonderLab.Modules.Controls; 15 | using WonderLab.Modules.Toolkits; 16 | using WonderLab.ViewModels; 17 | 18 | namespace WonderLab.Views 19 | { 20 | public partial class HomeView : Page 21 | { 22 | public HomeView() 23 | { 24 | InitializeComponent(true); 25 | DataContext = HomeViewModel; 26 | SettingButton.PointerEnter += Launchbutton_PointerEnter; 27 | SettingButton.PointerLeave += Launchbutton_PointerLeave; 28 | SettingButton.Click += SettingButton_Click; 29 | } 30 | 31 | private void SettingButton_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) 32 | { 33 | MainPropertyView.SelectGameCore = HomeViewModel.SelectedGameCore; 34 | var view = new MainPropertyView(); 35 | MainView.mv.FrameView.Navigate(view.GetType()); 36 | } 37 | 38 | private async void Launchbutton_PointerLeave(object? sender, Avalonia.Input.PointerEventArgs e) 39 | { 40 | await Task.Delay(200); 41 | if (SettingButton.Width is 25) 42 | { 43 | SettingButton.Width = 0; 44 | } 45 | } 46 | 47 | private void Launchbutton_PointerEnter(object? sender, Avalonia.Input.PointerEventArgs e) 48 | { 49 | SettingButton.Width = 25; 50 | } 51 | 52 | public override void OnNavigatedTo() 53 | { 54 | BackgroundWorker worker = new(); 55 | worker.DoWork += (_, _) => 56 | { 57 | HomeViewModel.GameSearchAsync(); 58 | HomeViewModel.RefreshUserAsync(); 59 | }; 60 | worker.RunWorkerAsync(); 61 | } 62 | } 63 | 64 | partial class HomeView 65 | { 66 | public static HomeViewModel HomeViewModel = new(); 67 | public static HomeView home; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /WonderLab/Views/IndependencyCoreSettingView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using MinecraftLaunch.Modules.Models.Launch; 3 | using WonderLab.Modules.Controls; 4 | using WonderLab.Modules.Toolkits; 5 | using WonderLab.ViewModels; 6 | 7 | namespace WonderLab.Views 8 | { 9 | public partial class IndependencyCoreSettingView : Page 10 | { 11 | public static GameCore GameCore { get; set; } 12 | public static IndependencyCoreSettingViewModel ViewModel { get; set; } = new(); 13 | public IndependencyCoreSettingView() 14 | { 15 | InitializeComponent(); 16 | DataContext = ViewModel; 17 | } 18 | 19 | public override void OnNavigatedTo() 20 | { 21 | GameCore = MainPropertyView.SelectGameCore; 22 | var res = JsonToolkit.GetEnableIndependencyCoreData(App.Data.FooterPath, GameCore.ToNatsurainkoGameCore()); 23 | if (res is not null) 24 | { 25 | ViewModel.IsEnableIndependencyCore = res.IsEnableIndependencyCore; 26 | ViewModel.IsFullWindow = res.IsFullWindows; 27 | ViewModel.IsOlate = res.Isolate; 28 | ViewModel.WindowHeight = res.WindowHeight.ToString(); 29 | ViewModel.WindowWidth = res.WindowWidth.ToString(); 30 | } 31 | else 32 | { 33 | var res1 = JsonToolkit.CreaftEnableIndependencyCoreInfoJson(App.Data.FooterPath, GameCore.ToNatsurainkoGameCore(), false); 34 | ViewModel.IsEnableIndependencyCore = res1.IsEnableIndependencyCore; 35 | ViewModel.IsFullWindow = res1.IsFullWindows; 36 | ViewModel.IsOlate = res1.Isolate; 37 | ViewModel.WindowHeight = res1.WindowHeight.ToString(); 38 | ViewModel.WindowWidth = res1.WindowWidth.ToString(); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /WonderLab/Views/LaunchItemView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | using Avalonia.Media; 5 | using Avalonia.OpenGL; 6 | using Avalonia.Threading; 7 | using FluentAvalonia.UI.Controls; 8 | using FluentAvalonia.UI.Media.Animation; 9 | using MinecraftLaunch.Events; 10 | using MinecraftLaunch.Launch; 11 | using MinecraftLaunch.Modules.Analyzers; 12 | using MinecraftLaunch.Modules.Interface; 13 | using MinecraftLaunch.Modules.Models.Auth; 14 | using MinecraftLaunch.Modules.Models.Launch; 15 | using MinecraftLaunch.Modules.Toolkits; 16 | using System; 17 | using System.Collections.Generic; 18 | using System.ComponentModel; 19 | using System.Diagnostics; 20 | using System.IO; 21 | using System.Linq; 22 | using System.Runtime.InteropServices; 23 | using System.Threading; 24 | using System.Threading.Tasks; 25 | using WonderLab.Modules.Base; 26 | using WonderLab.Modules.Const; 27 | using WonderLab.Modules.Controls; 28 | using WonderLab.Modules.Interface; 29 | using WonderLab.Modules.Models; 30 | using WonderLab.Modules.Toolkits; 31 | using WonderLab.ViewModels; 32 | using Button = Avalonia.Controls.Button; 33 | 34 | namespace WonderLab.Views 35 | { 36 | public partial class LaunchItemView : Page, ITask 37 | { 38 | public static LaunchItemViewModel ViewModel { get; set; } 39 | Process GameProcess = null; 40 | 41 | ConsoleWindow Window = null; 42 | 43 | string Path = ""; 44 | 45 | public LaunchItemView() => InitializeComponent(); 46 | 47 | public LaunchItemView(string version, UserDataModels userData, string javapath) 48 | { 49 | MainView.ViewModel.AllTaskCount++; 50 | InitializeComponent(version, userData, javapath); 51 | } 52 | 53 | private void InitializeComponent(string version, UserDataModels userData,string javapath) 54 | { 55 | InitializeComponent(true); 56 | ViewModel = new(GameCoreToolkit.GetGameCore(App.Data.FooterPath, version), userData.ToAccount(), javapath); 57 | DataContext = ViewModel; 58 | ViewModel.GameLaunchAction(); 59 | } 60 | 61 | public void Button_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) 62 | { 63 | TaskView.Remove(this); 64 | MainView.ViewModel.AllTaskCount--; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /WonderLab/Views/MainView.axaml.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blessing-Studio/WonderLab/953f62b11e0bd6d8a7782884ccb288ecc2924f07/WonderLab/Views/MainView.axaml.cs -------------------------------------------------------------------------------- /WonderLab/Views/ModPropertyView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using MinecraftLaunch.Modules.Toolkits; 3 | using System.Threading.Tasks; 4 | using WonderLab.Modules.Const; 5 | using WonderLab.Modules.Controls; 6 | using WonderLab.Modules.Models; 7 | using WonderLab.Modules.Toolkits; 8 | using WonderLab.ViewModels; 9 | 10 | namespace WonderLab.Views 11 | { 12 | public partial class ModPropertyView : Page 13 | { 14 | public static ModPropertyViewModel ViewModel { get; protected set; } = new(); 15 | public ModPropertyView() 16 | { 17 | InitializeComponent(true); 18 | DataContext = ViewModel; 19 | } 20 | 21 | private void Hyperlink_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) 22 | { 23 | NavigatedToDownView(); 24 | } 25 | 26 | public override async void OnNavigatedTo() 27 | { 28 | await Task.Run(() => 29 | { 30 | var res = JsonToolkit.GetEnableIndependencyCoreData(App.Data.FooterPath, ModPropertyViewModel.SelectedGameCore.ToNatsurainkoGameCore()); 31 | bool isolate = App.Data.Isolate; 32 | if (res != null && res.IsEnableIndependencyCore) { 33 | isolate = res.Isolate; 34 | } 35 | 36 | if (!isolate) { 37 | ViewModel.Isolate = true; 38 | } 39 | else ViewModel.Isolate = false; 40 | 41 | ViewModel.Toolkit = new(ModPropertyViewModel.SelectedGameCore, false, isolate, App.Data.FooterPath); 42 | ModDataModel.SetToolkit(ViewModel.Toolkit); 43 | ViewModel.LoadModList(); 44 | }); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /WonderLab/Views/NewItemView.axaml: -------------------------------------------------------------------------------- 1 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /WonderLab/Views/NewItemView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | using Avalonia.Media.Imaging; 5 | using System; 6 | using System.IO; 7 | using System.Net.Http; 8 | using System.Threading.Tasks; 9 | using WonderLab.Modules.Controls; 10 | 11 | namespace WonderLab.Views 12 | { 13 | public partial class NewItemView : Page 14 | { 15 | public NewItemView() 16 | { 17 | InitializeComponent(); 18 | } 19 | 20 | public NewItemView(string uri,string title,string message,string data,string uri1) 21 | { 22 | InitializeComponent(); 23 | LoadImage(uri); 24 | mTitle.Text = title; 25 | Message.Text= message; 26 | link.Content = uri1; 27 | IsOk.Header = title; 28 | link.NavigateUri = new(uri1); 29 | Date.Text= string.Format("{0}{1}","发布日期:",data); 30 | } 31 | 32 | async void LoadImage(string uri) 33 | { 34 | try 35 | { 36 | using HttpClient hc = new(); 37 | var newsimage = await Task.Run(async () => 38 | { 39 | var stream1 = await hc.GetByteArrayAsync("https://launchercontent.mojang.com/" + uri); 40 | MemoryStream stream = new(stream1); 41 | return stream; 42 | }); 43 | Bitmap bitmap = new(newsimage); 44 | image.Source = bitmap; 45 | } 46 | catch (Exception) 47 | { 48 | 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /WonderLab/Views/NewsView.axaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /WonderLab/Views/NewsView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | using Avalonia.Media.Imaging; 5 | using Avalonia.Threading; 6 | using Newtonsoft.Json; 7 | using System.Collections.Generic; 8 | using System.Diagnostics; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Net.Http; 12 | using System.Threading.Tasks; 13 | using WonderLab.Modules.Controls; 14 | using WonderLab.Modules.Models; 15 | 16 | namespace WonderLab.Views 17 | { 18 | public partial class NewsView : Page 19 | { 20 | public NewsView() 21 | { 22 | InitializeComponent(); 23 | LoadNews(); 24 | } 25 | 26 | private void InitializeComponent() 27 | { 28 | AvaloniaXamlLoader.Load(this); 29 | newslist = this.Find("newslist"); 30 | Isok = this.Find("Isok"); 31 | } 32 | List newItemViews = new List(); 33 | public async void LoadNews() 34 | { 35 | using HttpClient hc = new(); 36 | try 37 | { 38 | var json = await hc.GetStringAsync("https://launchercontent.mojang.com/news.json"); 39 | var v = JsonConvert.DeserializeObject(json); 40 | foreach (var i in v.entries) 41 | { 42 | NewItemView newItem = new(i.newsPageImage.url, i.title, i.text, i.date, i.readMoreLink); 43 | newItem.IsOk.Description = i.tag + " 快讯"; 44 | newItemViews.Add(newItem); 45 | 46 | if (newItemViews.Count is 20) 47 | break; 48 | } 49 | } 50 | catch (System.Exception) 51 | { 52 | 53 | } 54 | finally 55 | { 56 | Isok.IsVisible = false; 57 | hc.Dispose(); 58 | foreach (var i in newItemViews) 59 | await Dispatcher.UIThread.InvokeAsync(() => { newslist.Children.Add(i); }, DispatcherPriority.Background); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WonderLab/Views/OtherView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | using WonderLab.Modules.Controls; 5 | using WonderLab.ViewModels; 6 | 7 | namespace WonderLab.Views 8 | { 9 | public partial class OtherView : Page 10 | { 11 | public OtherView() 12 | { 13 | InitializeComponent(true); 14 | DataContext = new OtherViewModel(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /WonderLab/Views/PropertyView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using MinecraftLaunch.Modules.Models.Launch; 3 | using Natsurainko.FluentCore.Module.Launcher; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using WonderLab.Modules.Controls; 8 | using WonderLab.ViewModels; 9 | 10 | namespace WonderLab.Views 11 | { 12 | public partial class PropertyView : Page 13 | { 14 | public static GameCore GameCore { get; set; } 15 | public static PropertyView Instance { get; set; } 16 | public static PropertyViewModel PropertyViewModel = new PropertyViewModel(); 17 | public PropertyView() 18 | { 19 | InitializeComponent(true); 20 | DataContext = PropertyViewModel; 21 | Instance = this; 22 | } 23 | 24 | public override void OnNavigatedTo() 25 | { 26 | try 27 | { 28 | if (GameCore is null) 29 | { 30 | Debug.WriteLine("Null"); 31 | return; 32 | } 33 | 34 | var app = App.Data; 35 | var core = new GameCoreLocator(app.FooterPath).GetGameCore(GameCore.Id); 36 | PropertyViewModel.GamePath = app.FooterPath; 37 | var time = PropertyViewModel.GetLastLaunchTime(core); 38 | PropertyViewModel.IsLaunched = time.Item2; 39 | PropertyViewModel.LastLaunchTime = time.Item1; 40 | PropertyViewModel.AssetCount = PropertyViewModel.GetAssetCount(core); 41 | PropertyViewModel.LibraryCount = PropertyViewModel.GetLibraryCount(core); 42 | PropertyViewModel.TotalSize = PropertyViewModel.GetTotalSize(core); 43 | PropertyViewModel.ModLoaders = PropertyViewModel.GetModLoader(core) 44 | .Any() ? string.Join(": ", PropertyViewModel.GetModLoader(core) 45 | .Select(x => $"{x.LoaderType}: {x.Version}")) : null; 46 | } 47 | catch (NullReferenceException ex) 48 | { 49 | Debug.WriteLine("Chao"); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /WonderLab/Views/ResourceView.axaml.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blessing-Studio/WonderLab/953f62b11e0bd6d8a7782884ccb288ecc2924f07/WonderLab/Views/ResourceView.axaml.cs -------------------------------------------------------------------------------- /WonderLab/Views/SettingView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | using Avalonia.Threading; 5 | using FluentAvalonia.UI.Controls; 6 | using FluentAvalonia.UI.Media.Animation; 7 | using System; 8 | using WonderLab.Modules.Controls; 9 | 10 | namespace WonderLab.Views 11 | { 12 | public partial class SettingView : Page 13 | { 14 | public static SettingView sv { get; set; } 15 | public SettingView() 16 | { 17 | InitializeComponent(); 18 | } 19 | 20 | private void InitializeComponent() 21 | { 22 | InitializeComponent(true); 23 | sv = this; 24 | FrameView.Navigated += FrameView_Navigated; 25 | //home.IsSelected = true; 26 | //FrameView.Navigate(typeof(GameSettingView), null, new SlideNavigationTransitionInfo()); 27 | RootNavigationView.ItemInvoked += RootNavigationView_ItemInvoked; 28 | } 29 | 30 | private void FrameView_Navigated(object sender, FluentAvalonia.UI.Navigation.NavigationEventArgs e) 31 | { 32 | foreach (NavigationViewItem item in RootNavigationView.MenuItems) 33 | { 34 | if ((string)item.Tag == e.SourcePageType.Name) 35 | { 36 | RootNavigationView.SelectedItem = item; 37 | item.IsSelected = true; 38 | } 39 | } 40 | FrameView.NavigateTo((Page)e.Content); 41 | } 42 | 43 | public override void OnNavigatedTo() 44 | { 45 | NavigatedToGameSettingView(); 46 | } 47 | 48 | private void RootNavigationView_BackRequested(object? sender, NavigationViewBackRequestedEventArgs e) 49 | { 50 | FrameView.GoBack(null); 51 | } 52 | 53 | private void RootNavigationView_ItemInvoked(object? sender, NavigationViewItemInvokedEventArgs e) 54 | { 55 | FrameView.Navigate((Page)FrameView.Content, e.IsSettingsInvoked ? typeof(GameSettingView) : (Type.GetType($"WonderLab.Views.{((NavigationViewItem)e.InvokedItemContainer).Tag ??= string.Empty}")) ?? typeof(GameSettingView), null, null); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /WonderLab/Views/StructureView.axaml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 13 | 14 | 15 |