|
13 | 13 | <link href="./css/bootstrap.min.css" rel="stylesheet">
|
14 | 14 | <link href="./css/font-awesome.min.css" rel="stylesheet">
|
15 | 15 | <link rel="stylesheet" href="./css/style.css">
|
16 |
| - <link ref="icon" href="./image/logo.png"> |
| 16 | + <link rel="icon" href="./image/logo.png"> |
17 | 17 | </head>
|
18 | 18 |
|
19 | 19 | <body>
|
|
31 | 31 | <player-list v-else-if="ui === 'playerList'" :cur="curPlayerIndex" @close="changeUI('main')" :init="init"
|
32 | 32 | :players="players" :aoa="addOfflineAccount"
|
33 | 33 | :account="account"></player-list>
|
| 34 | + <version-list v-else-if="ui === 'versionList'" :cur-ver="curVer" |
| 35 | + @install="installVersion" |
| 36 | + @close="changeUI('main')" |
| 37 | + :init="init"></version-list> |
34 | 38 | <text-input v-else-if="ui === 'input'" @finish="input.resolveFunc" @close="goBack" :title="input.title"
|
35 | 39 | :desc="input.desc" :placeholder="input.placeholder"></text-input>
|
36 | 40 | <div v-else-if="ui === 'main'">
|
|
59 | 63 |
|
60 | 64 | <transition>
|
61 | 65 | <div class="main-menu" v-if="ui === 'main'">
|
62 |
| - <button class="ctrl button"> |
| 66 | + <button class="ctrl button" @click="changeUI('versionList')"> |
63 | 67 | <i class="fa fa-bars"></i>
|
64 | 68 | {{ $t('versionList') }}
|
65 | 69 | </button>
|
|
256 | 260 | </template>
|
257 | 261 | </ui-container>
|
258 | 262 | </template>
|
| 263 | + |
| 264 | + |
| 265 | + <!-- TODO: Version List template --> |
| 266 | + <template id="version-list"> |
| 267 | + <transition mode="out-in"> |
| 268 | + <ui-container v-if="mode === 'list'"> |
| 269 | + <template #title> |
| 270 | + <i class="fa fa-list"></i> |
| 271 | + {{ $t('versionList') }} |
| 272 | + </template> |
| 273 | + <template #content> |
| 274 | + <div class="mx-3"> |
| 275 | + <transition mode="out-in"> |
| 276 | + <div v-if="loading.version" class="text-muted"> |
| 277 | + <span class="spinner-border spinner-border-sm"></span> |
| 278 | + {{ $t('loading') }} |
| 279 | + </div> |
| 280 | + <div v-else-if="versions.length === 0" class="text-muted"> |
| 281 | + <i class="fa fa-minus-circle"></i> |
| 282 | + {{ $t('noVersions') }} |
| 283 | + </div> |
| 284 | + <div v-else> |
| 285 | + <transition-group name="list"> |
| 286 | + <div v-for="ver in versions" class="clearfix mt-2" :key="ver"> |
| 287 | + <div class="float-left"> |
| 288 | + <input type="radio" name="version" :value="ver" v-model="selectedVersion" :id="'ver-' + ver"> <label |
| 289 | + :for="'ver-' + ver"> |
| 290 | + {{ ver }} |
| 291 | + </div> |
| 292 | + <div class="float-right"> |
| 293 | + <button class="btn btn-sm btn-danger" @click="deleteVersion(ver)"> |
| 294 | + <i class="fa fa-trash"></i> |
| 295 | + </button> |
| 296 | + </div> |
| 297 | + </div> |
| 298 | + </transition-group> |
| 299 | + </div> |
| 300 | + </transition> |
| 301 | + |
| 302 | + </div> |
| 303 | + <button class="btn btn-info btn-block mt-2" @click="mode = 'install'"> |
| 304 | + <i class="fa fa-download"></i> |
| 305 | + {{ $t('install') }} |
| 306 | + </button> |
| 307 | + <button class="btn btn-success btn-block mt-2" @click="$emit('close')"> |
| 308 | + <i class="fa fa-check"></i> {{ $t('finish') }} |
| 309 | + </button> |
| 310 | + </template> |
| 311 | + </ui-container> |
| 312 | + <ui-container v-else-if="mode === 'install'"> |
| 313 | + <template #title> |
| 314 | + <i class="fa fa-download"></i> |
| 315 | + {{ $t('versionSelect') }} |
| 316 | + </template> |
| 317 | + <template #content> |
| 318 | + <button class="btn btn-secondary mb-2" @click="mode = 'list'"> |
| 319 | + <i class="fa fa-times"></i> |
| 320 | + {{ $t('cancel') }} |
| 321 | + </button> |
| 322 | + <select class="btn btn-info mb-2" v-model="versionType"> |
| 323 | + <option v-for="item in types" :value="item">{{ $t(item) }}</option> |
| 324 | + </select> |
| 325 | + <transition mode="out-in"> |
| 326 | + <div v-if="loading.allVersions" class="text-muted"> |
| 327 | + <span class="spinner-border spinner-border-sm"></span> |
| 328 | + {{ $t('loadingAll') }} |
| 329 | + </div> |
| 330 | + <div v-else class="mx-3"> |
| 331 | + <template v-for="ver in allVersions"> |
| 332 | + <button class="btn btn-success mt-2" @click="$emit('install', ver)"> |
| 333 | + <i class="fa fa-download"></i> |
| 334 | + {{ ver }} |
| 335 | + </button> |
| 336 | + </template> |
| 337 | + </div> |
| 338 | + </transition> |
| 339 | + </template> |
| 340 | + </ui-container> |
| 341 | + |
| 342 | + </transition> |
| 343 | + </template> |
| 344 | + |
| 345 | + |
259 | 346 | <!-- TODO: Component templates -->
|
260 | 347 |
|
261 | 348 | <script src="./vue.global.prod.js"></script>
|
|
293 | 380 | addOfflineAccountFailed: "Failed to add offline account",
|
294 | 381 | nameInvalid: "The name you entered is invalid, please try again",
|
295 | 382 | accountNamePlaceholder: "Enter account name",
|
296 |
| - |
| 383 | + install: "Install Game", |
| 384 | + installing: "Installing {ver}...", |
| 385 | + downloadingResource: "Downloading resources...", |
| 386 | + versionNotFound: "Version not found, please reinstall" |
297 | 387 | // TODO: i18n en
|
298 | 388 | },
|
299 | 389 | zh: {
|
|
318 | 408 | accountNameTips: "请输入账号名称,只能包含字母和数字,长度为 3-16 位",
|
319 | 409 | accountNamePlaceholder: "输入账号名称",
|
320 | 410 | addOfflineAccountFailed: "添加离线账户失败",
|
321 |
| - nameInvalid: "您输入的名称不符合要求,请重新添加" |
| 411 | + nameInvalid: "您输入的名称不符合要求,请重新添加", |
| 412 | + install: "安装游戏", |
| 413 | + installing: "正在安装 {ver}...", |
| 414 | + downloadingResource: "正在下载资源文件...", |
| 415 | + versionNotFound: "未找到此版本,请重新安装" |
322 | 416 | // TODO: i18n zh
|
323 | 417 | }
|
324 | 418 | }
|
|
564 | 658 | }
|
565 | 659 | };
|
566 | 660 |
|
| 661 | + // TODO: VersionList |
| 662 | + const VersionList = { |
| 663 | + emits: ["close", "install"], |
| 664 | + props: { |
| 665 | + curVer: { |
| 666 | + type: String |
| 667 | + }, |
| 668 | + init: { |
| 669 | + type: Function |
| 670 | + } |
| 671 | + }, |
| 672 | + components: { |
| 673 | + UiContainer |
| 674 | + }, |
| 675 | + template: "#version-list", |
| 676 | + data() { |
| 677 | + return { |
| 678 | + versions: [], |
| 679 | + loading: { |
| 680 | + version: true, |
| 681 | + allVersions: true |
| 682 | + }, |
| 683 | + allVersions: [], |
| 684 | + mode: "list", |
| 685 | + versionType: "release", |
| 686 | + types: [ |
| 687 | + "release", |
| 688 | + "all", |
| 689 | + "snapshot", |
| 690 | + "oldAlpha", |
| 691 | + "oldBeta" |
| 692 | + ], |
| 693 | + selectedVersion: this.curVer |
| 694 | + }; |
| 695 | + }, |
| 696 | + watch: { |
| 697 | + async mode(val) { |
| 698 | + if (val === "list") { |
| 699 | + await this.getVersions(); |
| 700 | + } else { |
| 701 | + await this.getAllVersions(); |
| 702 | + } |
| 703 | + }, |
| 704 | + async versionType(val) { |
| 705 | + await this.getAllVersions(); |
| 706 | + }, |
| 707 | + async selectedVersion(val) { |
| 708 | + if (val) { |
| 709 | + await api.cmcl(["--select", val]); |
| 710 | + } else { |
| 711 | + await api.cmcl(["config", "--delete", "selectedVersion"]); |
| 712 | + } |
| 713 | + |
| 714 | + await this.init(); |
| 715 | + } |
| 716 | + }, |
| 717 | + methods: { |
| 718 | + async selectVersion(ver) { |
| 719 | + await api.cmcl(["--select", ver]); |
| 720 | + await this.init(); |
| 721 | + }, |
| 722 | + async getAllVersions() { |
| 723 | + this.loading.allVersions = true; |
| 724 | + const allVersionsStr = await api.cmcl(["install", "--show", this.versionType]); |
| 725 | + this.allVersions = allVersionsStr.split(/\s+/).slice(0, -1); |
| 726 | + this.allVersions.reverse(); |
| 727 | + this.loading.allVersions = false; |
| 728 | + }, |
| 729 | + async getVersions() { |
| 730 | + this.loading.version = true; |
| 731 | + const versionStr = await api.cmcl(["--list"]); |
| 732 | + this.versions = versionStr.split("\n").slice(1).join("\n").split(/\s+/).slice(0, -1); |
| 733 | + if (this.versions.length === 1 && this.versions[0] === "") { |
| 734 | + this.versions = []; |
| 735 | + } |
| 736 | + |
| 737 | + this.loading.version = false; |
| 738 | + }, |
| 739 | + async deleteVersion(ver) { |
| 740 | + if (await api.confirm_dialog(this.$t("deleteConfirm"), this.$t("deleteVersion"))) { |
| 741 | + await api.cmcl(["version", ver, "--delete"]); |
| 742 | + if (this.selectedVersion === ver) { |
| 743 | + this.selectedVersion = ""; |
| 744 | + } |
| 745 | + await this.getVersions(); |
| 746 | + } |
| 747 | + } |
| 748 | + }, |
| 749 | + async mounted() { |
| 750 | + await this.getVersions(); |
| 751 | + }, |
| 752 | + i18n: { |
| 753 | + messages: { |
| 754 | + en: { |
| 755 | + loading: "Getting installed versions...", |
| 756 | + loadingAll: "Getting all versions...", |
| 757 | + noVersions: "No versions installed, please click the button below to install", |
| 758 | + install: "Install a game version", |
| 759 | + versionSelect: "Select a game version", |
| 760 | + release: "Release", |
| 761 | + all: "All Versions", |
| 762 | + snapshot: "Snapshot", |
| 763 | + oldAlpha: "Old Alpha", |
| 764 | + oldBeta: "Old Beta", |
| 765 | + deleteConfirm: "Are you sure to delete this version?", |
| 766 | + deleteVersion: "Delete Version" |
| 767 | + }, |
| 768 | + zh: { |
| 769 | + loading: "正在获取已安装的版本...", |
| 770 | + loadingAll: "正在获取可安装的版本...", |
| 771 | + noVersions: "当前未安装任何版本,请点击下方按钮安装", |
| 772 | + install: "安装一个游戏版本", |
| 773 | + versionSelect: "选择要安装的游戏版本", |
| 774 | + release: "正式版", |
| 775 | + all: "所有版本", |
| 776 | + snapshot: "快照版", |
| 777 | + oldAlpha: "远古 Alpha 版", |
| 778 | + oldBeta: "远古 Beta 版", |
| 779 | + deleteConfirm: "确定要删除这个版本吗?", |
| 780 | + deleteVersion: "删除版本" |
| 781 | + } |
| 782 | + } |
| 783 | + } |
| 784 | + }; |
| 785 | + |
567 | 786 | // TODO: Components
|
568 | 787 | const app = createApp({
|
569 | 788 | components: {
|
570 | 789 | Loading,
|
571 | 790 | Warning,
|
572 | 791 | Settings,
|
573 | 792 | PlayerList,
|
| 793 | + VersionList, |
574 | 794 | TextInput
|
575 | 795 | },
|
576 | 796 | data() {
|
|
612 | 832 | await this.init();
|
613 | 833 | return res;
|
614 | 834 | },
|
| 835 | + |
| 836 | + // TODO: installVersion |
| 837 | + async installVersion(ver) { |
| 838 | + this.startLoading(this.$t("install"), this.$t("installing", { ver }), (result, loading) => { |
| 839 | + const msg = result.replace(/\u0008/g, "").replace(/\(\d+%\)/g, ""); |
| 840 | + console.log(msg); |
| 841 | + const reg = /\[(\d+)\/(\d+)\]/; |
| 842 | + if (reg.test(msg)) { |
| 843 | + const match = reg.exec(msg); |
| 844 | + loading.progress = parseInt(match[1]) / parseInt(match[2]) * 100; |
| 845 | + loading.log = this.$t("downloadingResource") + ` (${match[1]}/${match[2]})`; |
| 846 | + } else { |
| 847 | + loading.log = msg; |
| 848 | + loading.progress += 1; |
| 849 | + } |
| 850 | + }); |
| 851 | + const res = await api.cmcl_waiting(["install", ver]); |
| 852 | + this.finishLoading(); |
| 853 | + }, |
| 854 | + |
615 | 855 | async addOfflineAccount() {
|
616 | 856 | const name = await this.requestInput(
|
617 | 857 | this.$t("addOfflineAccount"),
|
|
671 | 911 | async launchGame() {
|
672 | 912 | // TODO: launch game
|
673 | 913 | if (!this.curVer) {
|
| 914 | + this.changeUI("versionList"); |
674 | 915 | return;
|
675 | 916 | }
|
676 | 917 |
|
|
703 | 944 | const reg = /^(游戏崩溃可能的错误:|Game crash possible error: ).*$/m;
|
704 | 945 | const match = reg.exec(res);
|
705 | 946 | this.showWarning(this.$t("launchFail"), match[0]);
|
| 947 | + } else if (res.includes("install <")) { |
| 948 | + this.finishLoading(); |
| 949 | + this.showWarning(this.$t("launchFail"), this.$t("versionNotFound")); |
706 | 950 | }
|
707 | 951 | },
|
708 | 952 | async init() {
|
|
0 commit comments