Implemented better authentication system, completed more localization, implemented cached JWT login, implemented locking costumes and title plates for FreeProfileEditing
This commit is contained in:
parent
19db91fc59
commit
650552e403
491
GameDatabase/Migrations/20240203182355_AddUnlockedUraSongIdListToUserDatum.Designer.cs
generated
Normal file
491
GameDatabase/Migrations/20240203182355_AddUnlockedUraSongIdListToUserDatum.Designer.cs
generated
Normal file
@ -0,0 +1,491 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using GameDatabase.Context;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GameDatabase.Migrations
|
||||
{
|
||||
[DbContext(typeof(TaikoDbContext))]
|
||||
[Migration("20240203182355_AddUnlockedUraSongIdListToUserDatum")]
|
||||
partial class AddUnlockedUraSongIdListToUserDatum
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "8.0.0-rc.2.23480.1");
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
|
||||
{
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("SongId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("Difficulty")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsWin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Baid", "SongId", "Difficulty");
|
||||
|
||||
b.ToTable("AiScoreData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
|
||||
{
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("SongId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("Difficulty")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SectionIndex")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Crown")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("DrumrollCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("GoodCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsWin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("MissCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("OkCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("Score")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex");
|
||||
|
||||
b.ToTable("AiSectionScoreData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.Card", b =>
|
||||
{
|
||||
b.Property<string>("AccessCode")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("AccessCode");
|
||||
|
||||
b.HasIndex("Baid");
|
||||
|
||||
b.ToTable("Card", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
|
||||
{
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Salt")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Baid");
|
||||
|
||||
b.ToTable("Credential", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
|
||||
{
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("DanId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DanType")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(1);
|
||||
|
||||
b.Property<uint>("ArrivalSongCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ClearState")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(0u);
|
||||
|
||||
b.Property<uint>("ComboCountTotal")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("SoulGaugeTotal")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Baid", "DanId", "DanType");
|
||||
|
||||
b.ToTable("DanScoreData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
|
||||
{
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("DanId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DanType")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(1);
|
||||
|
||||
b.Property<uint>("SongNumber")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("BadCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ComboCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("DrumrollCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("GoodCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("HighScore")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("OkCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("PlayScore")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("TotalHitCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Baid", "DanId", "DanType", "SongNumber");
|
||||
|
||||
b.ToTable("DanStageScoreData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
|
||||
{
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("SongId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("Difficulty")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("BestCrown")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("BestRate")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("BestScore")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("BestScoreRank")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Baid", "SongId", "Difficulty");
|
||||
|
||||
b.ToTable("SongBestData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ComboCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("Crown")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("Difficulty")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("DrumrollCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("GoodCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("HitCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("MissCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("OkCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("PlayTime")
|
||||
.HasColumnType("datetime");
|
||||
|
||||
b.Property<uint>("Score")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ScoreRank")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ScoreRate")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Skipped")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("SongId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("SongNumber")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Baid");
|
||||
|
||||
b.ToTable("SongPlayData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
|
||||
{
|
||||
b.Property<ulong>("Baid")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("AchievementDisplayDifficulty")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AiWinCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ColorBody")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ColorFace")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ColorLimb")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("CostumeData")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CostumeFlgArray")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DifficultyPlayedArray")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DifficultySettingArray")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("DisplayAchievement")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("DisplayDan")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("FavoriteSongsArray")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("GenericInfoFlgArray")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsAdmin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsSkipOn")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsVoiceOn")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("LastPlayDatetime")
|
||||
.HasColumnType("datetime");
|
||||
|
||||
b.Property<uint>("LastPlayMode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("MyDonName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("MyDonNameLanguage")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("NotesPosition")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<short>("OptionSetting")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("SelectedToneId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("TitleFlgArray")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("TitlePlateId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("TokenCountDict")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ToneFlgArray")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("UnlockedSongIdList")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Baid");
|
||||
|
||||
b.ToTable("UserData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.AiScoreDatum", "Parent")
|
||||
.WithMany("AiSectionScoreData")
|
||||
.HasForeignKey("Baid", "SongId", "Difficulty")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Parent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.Card", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.DanScoreDatum", "Parent")
|
||||
.WithMany("DanStageScoreData")
|
||||
.HasForeignKey("Baid", "DanId", "DanType")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Parent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
|
||||
{
|
||||
b.Navigation("AiSectionScoreData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
|
||||
{
|
||||
b.Navigation("DanStageScoreData");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GameDatabase.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddUnlockedUraSongIdListToUserDatum : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
10
SharedProject/Models/Requests/ChangePasswordRequest.cs
Normal file
10
SharedProject/Models/Requests/ChangePasswordRequest.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace SharedProject.Models.Requests;
|
||||
|
||||
public class ChangePasswordRequest
|
||||
{
|
||||
public string AccessCode { get; set; } = string.Empty;
|
||||
|
||||
public string OldPassword { get; set; } = string.Empty;
|
||||
|
||||
public string NewPassword { get; set; } = string.Empty;
|
||||
}
|
6
SharedProject/Models/Requests/GenerateOtpRequest.cs
Normal file
6
SharedProject/Models/Requests/GenerateOtpRequest.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace SharedProject.Models.Requests;
|
||||
|
||||
public class GenerateOtpRequest
|
||||
{
|
||||
public uint Baid { get; set; }
|
||||
}
|
7
SharedProject/Models/Requests/LoginRequest.cs
Normal file
7
SharedProject/Models/Requests/LoginRequest.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace SharedProject.Models.Requests;
|
||||
|
||||
public class LoginRequest
|
||||
{
|
||||
public string AccessCode { get; set; } = string.Empty;
|
||||
public string Password { get; set; } = string.Empty;
|
||||
}
|
10
SharedProject/Models/Requests/RegisterRequest.cs
Normal file
10
SharedProject/Models/Requests/RegisterRequest.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace SharedProject.Models.Requests;
|
||||
|
||||
public class RegisterRequest
|
||||
{
|
||||
public string AccessCode { get; set; } = string.Empty;
|
||||
public string Password { get; set; } = string.Empty;
|
||||
public bool RegisterWithLastPlayTime { get; set; }
|
||||
public DateTime LastPlayDateTime { get; set; }
|
||||
public string InviteCode { get; set; } = string.Empty;
|
||||
}
|
6
SharedProject/Models/Requests/ResetPasswordRequest.cs
Normal file
6
SharedProject/Models/Requests/ResetPasswordRequest.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace SharedProject.Models.Requests;
|
||||
|
||||
public class ResetPasswordRequest
|
||||
{
|
||||
public uint Baid { get; set; }
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace SharedProject.Models.Requests;
|
||||
|
||||
public class SetPasswordRequest
|
||||
{
|
||||
public uint Baid { get; set; }
|
||||
public string Password { get; set; } = default!;
|
||||
public string Salt { get; set; } = default!;
|
||||
}
|
8
SharedProject/Models/Requests/VerifyOtpRequest.cs
Normal file
8
SharedProject/Models/Requests/VerifyOtpRequest.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace SharedProject.Models.Requests;
|
||||
|
||||
public class VerifyOtpRequest
|
||||
{
|
||||
public string Otp { get; set; } = "";
|
||||
|
||||
public uint Baid { get; set; }
|
||||
}
|
@ -3,6 +3,4 @@
|
||||
public class DashboardResponse
|
||||
{
|
||||
public List<User> Users { get; set; } = new();
|
||||
|
||||
public List<UserCredential> UserCredentials { get; set; } = new();
|
||||
}
|
6
SharedProject/Models/Responses/SongHistoryResponse.cs
Normal file
6
SharedProject/Models/Responses/SongHistoryResponse.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace SharedProject.Models.Responses;
|
||||
|
||||
public class SongHistoryResponse
|
||||
{
|
||||
public List<SongHistoryData> SongHistoryData { get; set; } = new();
|
||||
}
|
48
SharedProject/Models/SongHistoryData.cs
Normal file
48
SharedProject/Models/SongHistoryData.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using SharedProject.Enums;
|
||||
|
||||
namespace SharedProject.Models;
|
||||
|
||||
public class SongHistoryData
|
||||
{
|
||||
public uint SongId { get; set; }
|
||||
|
||||
public SongGenre Genre { get; set; }
|
||||
|
||||
public string MusicName { get; set; } = string.Empty;
|
||||
|
||||
public string MusicArtist { get; set; } = string.Empty;
|
||||
|
||||
public Difficulty Difficulty { get; set; }
|
||||
|
||||
public int Stars { get; set; }
|
||||
|
||||
public bool ShowDetails { get; set; }
|
||||
|
||||
public uint Score { get; set; }
|
||||
|
||||
public CrownType Crown { get; set; }
|
||||
|
||||
public ScoreRank ScoreRank { get; set; }
|
||||
|
||||
public DateTime PlayTime { get; set; }
|
||||
|
||||
public bool IsFavorite { get; set; }
|
||||
|
||||
public uint GoodCount { get; set; }
|
||||
|
||||
public uint OkCount { get; set; }
|
||||
|
||||
public uint MissCount { get; set; }
|
||||
|
||||
public uint ComboCount { get; set; }
|
||||
|
||||
public uint HitCount { get; set; }
|
||||
|
||||
public uint DrumrollCount { get; set; }
|
||||
|
||||
public uint SongNumber { get; set; }
|
||||
|
||||
//public List<AiSectionBestData> AiSectionBestData { get; set; } = new();
|
||||
|
||||
//public bool ShowAiData { get; set; }
|
||||
}
|
7
TaikoLocalServer/Configurations/AuthSettings.json
Normal file
7
TaikoLocalServer/Configurations/AuthSettings.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"AuthSettings": {
|
||||
"JwtKey": "SuperSecretKeyAndHeresItsPadding",
|
||||
"JwtIssuer": "http://localhost:5000",
|
||||
"JwtAudience": "http://localhost:5000"
|
||||
}
|
||||
}
|
221
TaikoLocalServer/Controllers/Api/AuthController.cs
Normal file
221
TaikoLocalServer/Controllers/Api/AuthController.cs
Normal file
@ -0,0 +1,221 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using TaikoLocalServer.Settings;
|
||||
using OtpNet;
|
||||
using SharedProject.Models.Requests;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Api;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class AuthController(ICredentialService credentialService, ICardService cardService,
|
||||
IUserDatumService userDatumService, IOptions<AuthSettings> settings) : BaseController<AuthController>
|
||||
{
|
||||
private readonly AuthSettings authSettings = settings.Value;
|
||||
|
||||
private string GenerateJwtToken(uint baid, bool isAdmin)
|
||||
{
|
||||
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authSettings.JwtKey));
|
||||
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new(ClaimTypes.Name, baid.ToString()),
|
||||
new(ClaimTypes.Role, isAdmin ? "Admin" : "User")
|
||||
};
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: authSettings.JwtIssuer,
|
||||
audience: authSettings.JwtAudience,
|
||||
expires: DateTime.UtcNow.AddHours(24),
|
||||
signingCredentials: credentials,
|
||||
claims: claims
|
||||
);
|
||||
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
|
||||
private static string ComputeHash(string inputPassword, string salt)
|
||||
{
|
||||
var encDataByte = Encoding.UTF8.GetBytes(inputPassword + salt);
|
||||
var encodedData = Convert.ToBase64String(encDataByte);
|
||||
encDataByte = Encoding.UTF8.GetBytes(encodedData);
|
||||
encodedData = Convert.ToBase64String(encDataByte);
|
||||
encDataByte = Encoding.UTF8.GetBytes(encodedData);
|
||||
encodedData = Convert.ToBase64String(encDataByte);
|
||||
encDataByte = Encoding.UTF8.GetBytes(encodedData);
|
||||
encodedData = Convert.ToBase64String(encDataByte);
|
||||
return encodedData;
|
||||
}
|
||||
|
||||
private static Totp MakeTotp(uint baid)
|
||||
{
|
||||
var secretKey = (baid * 765 + 2023).ToString();
|
||||
var base32String = Base32Encoding.ToString(Encoding.UTF8.GetBytes(secretKey));
|
||||
var base32Bytes = Base32Encoding.ToBytes(base32String);
|
||||
return new Totp(base32Bytes, step: 999999999);
|
||||
}
|
||||
|
||||
private static string CreateSalt()
|
||||
{
|
||||
//Generate a cryptographic random number.
|
||||
var randomNumber = new byte[32];
|
||||
var rng = RandomNumberGenerator.Create();
|
||||
rng.GetBytes(randomNumber);
|
||||
var salt = Convert.ToBase64String(randomNumber);
|
||||
|
||||
// Return a Base64 string representation of the random number.
|
||||
return salt;
|
||||
}
|
||||
|
||||
private static bool VerifyOtp(string otp, uint baid)
|
||||
{
|
||||
var totp = MakeTotp(baid);
|
||||
return totp.VerifyTotp(otp, out _);
|
||||
}
|
||||
|
||||
[HttpPost("Login")]
|
||||
public async Task<IActionResult> Login(LoginRequest loginRequest)
|
||||
{
|
||||
var accessCode = loginRequest.AccessCode;
|
||||
var password = loginRequest.Password;
|
||||
|
||||
var card = await cardService.GetCardByAccessCode(accessCode);
|
||||
if (card == null)
|
||||
return Unauthorized(new { message = "Access Code Not Found" });
|
||||
|
||||
var credential = await credentialService.GetCredentialByBaid(card.Baid);
|
||||
if (credential == null)
|
||||
return Unauthorized(new { message = "Credential Not Found" });
|
||||
|
||||
if (credential.Password == "")
|
||||
return Unauthorized(new { message = "User Not Registered" });
|
||||
|
||||
// Hash the password with the salt
|
||||
var hashedPassword = ComputeHash(password, credential.Salt);
|
||||
|
||||
if (credential.Password != hashedPassword)
|
||||
return Unauthorized(new { message = "Invalid Password" });
|
||||
|
||||
// Get User information
|
||||
var user = await userDatumService.GetFirstUserDatumOrNull(card.Baid);
|
||||
if (user == null)
|
||||
return Unauthorized(new { message = "User Does Not Exist" });
|
||||
|
||||
var authToken = GenerateJwtToken(card.Baid, user.IsAdmin);
|
||||
|
||||
// Return the token with key authToken
|
||||
return Ok(new { authToken });
|
||||
}
|
||||
|
||||
[HttpPost("Register")]
|
||||
public async Task<IActionResult> Register(RegisterRequest registerRequest)
|
||||
{
|
||||
var accessCode = registerRequest.AccessCode;
|
||||
var password = registerRequest.Password;
|
||||
var lastPlayDateTime = registerRequest.LastPlayDateTime;
|
||||
var registerWithLastPlayTime = registerRequest.RegisterWithLastPlayTime;
|
||||
var inviteCode = registerRequest.InviteCode;
|
||||
|
||||
var card = await cardService.GetCardByAccessCode(accessCode);
|
||||
if (card == null)
|
||||
return Unauthorized(new { message = "Access Code Not Found" });
|
||||
|
||||
var credential = await credentialService.GetCredentialByBaid(card.Baid);
|
||||
if (credential == null)
|
||||
return Unauthorized(new { message = "Credential Not Found" });
|
||||
|
||||
if (credential.Password != "")
|
||||
return Unauthorized(new { message = "User Already Registered" });
|
||||
|
||||
if (registerWithLastPlayTime)
|
||||
{
|
||||
var invited = false;
|
||||
if (inviteCode != "")
|
||||
{
|
||||
invited = VerifyOtp(inviteCode, card.Baid);
|
||||
}
|
||||
|
||||
if (!invited)
|
||||
{
|
||||
var user = await userDatumService.GetFirstUserDatumOrNull(card.Baid);
|
||||
if (user == null)
|
||||
return Unauthorized(new { message = "User Does Not Exist" });
|
||||
|
||||
var diffMinutes = (lastPlayDateTime - user.LastPlayDatetime).Duration().TotalMinutes;
|
||||
if (diffMinutes > 5)
|
||||
return Unauthorized(new { message = "Wrong Last Play Time" });
|
||||
}
|
||||
}
|
||||
|
||||
// Hash the password with the salt
|
||||
var salt = CreateSalt();
|
||||
var hashedPassword = ComputeHash(password, salt);
|
||||
|
||||
var result = await credentialService.UpdatePassword(card.Baid, hashedPassword, salt);
|
||||
return result ? Ok() : Unauthorized( new { message = "Failed to Update Password" });
|
||||
}
|
||||
|
||||
[HttpPost("ChangePassword")]
|
||||
public async Task<IActionResult> ChangePassword(ChangePasswordRequest changePasswordRequest)
|
||||
{
|
||||
var accessCode = changePasswordRequest.AccessCode;
|
||||
var oldPassword = changePasswordRequest.OldPassword;
|
||||
var newPassword = changePasswordRequest.NewPassword;
|
||||
|
||||
var card = await cardService.GetCardByAccessCode(accessCode);
|
||||
if (card == null)
|
||||
return Unauthorized(new { message = "Access Code Not Found" });
|
||||
|
||||
var credential = await credentialService.GetCredentialByBaid(card.Baid);
|
||||
if (credential == null)
|
||||
return Unauthorized(new { message = "Credential Not Found" });
|
||||
|
||||
if (credential.Password == "")
|
||||
return Unauthorized(new { message = "User Not Registered" });
|
||||
|
||||
// Hash the password with the salt
|
||||
var hashedOldPassword = ComputeHash(oldPassword, credential.Salt);
|
||||
if (credential.Password != hashedOldPassword)
|
||||
return Unauthorized(new { message = "Wrong Old Password" });
|
||||
|
||||
// Hash the new password with the salt
|
||||
var salt = CreateSalt();
|
||||
var hashedNewPassword = ComputeHash(newPassword, salt);
|
||||
|
||||
var result = await credentialService.UpdatePassword(card.Baid, hashedNewPassword, salt);
|
||||
return result ? Ok() : Unauthorized( new { message = "Failed to Update Password" });
|
||||
}
|
||||
|
||||
[HttpPost("ResetPassword")]
|
||||
public async Task<IActionResult> ResetPassword(ResetPasswordRequest resetPasswordRequest)
|
||||
{
|
||||
var baid = resetPasswordRequest.Baid;
|
||||
|
||||
var credential = await credentialService.GetCredentialByBaid(baid);
|
||||
if (credential == null)
|
||||
return Unauthorized(new { message = "Credential Not Found" });
|
||||
|
||||
var result = await credentialService.UpdatePassword(baid, "", "");
|
||||
return result ? Ok() : Unauthorized( new { message = "Failed to Reset Password" });
|
||||
}
|
||||
|
||||
[HttpPost("GenerateOtp")]
|
||||
public IActionResult GenerateOtp(GenerateOtpRequest generateOtpRequest)
|
||||
{
|
||||
var totp = MakeTotp(generateOtpRequest.Baid);
|
||||
return Ok(new { otp = totp.ComputeTotp() });
|
||||
}
|
||||
|
||||
[HttpPost("VerifyOtp")]
|
||||
public IActionResult VerifyOtpHandler(VerifyOtpRequest verifyOtpRequest)
|
||||
{
|
||||
if (VerifyOtp(verifyOtpRequest.Otp, verifyOtpRequest.Baid))
|
||||
return Ok();
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using SharedProject.Models.Requests;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Api;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class CredentialsController : BaseController<CredentialsController>
|
||||
{
|
||||
private readonly ICredentialService credentialService;
|
||||
|
||||
public CredentialsController(ICredentialService credentialService)
|
||||
{
|
||||
this.credentialService = credentialService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> UpdatePassword(SetPasswordRequest request)
|
||||
{
|
||||
var baid = request.Baid;
|
||||
var password = request.Password;
|
||||
var salt = request.Salt;
|
||||
var result = await credentialService.UpdatePassword(baid, password, salt);
|
||||
return result ? NoContent() : NotFound();
|
||||
}
|
||||
}
|
@ -7,23 +7,19 @@ namespace TaikoLocalServer.Controllers.Api;
|
||||
public class DashboardController : BaseController<DashboardController>
|
||||
{
|
||||
private readonly ICardService cardService;
|
||||
private readonly ICredentialService credentialService;
|
||||
|
||||
public DashboardController(ICardService cardService, ICredentialService credentialService)
|
||||
public DashboardController(ICardService cardService)
|
||||
{
|
||||
this.cardService = cardService;
|
||||
this.credentialService = credentialService;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<DashboardResponse> GetDashboard()
|
||||
{
|
||||
var users = await cardService.GetUsersFromCards();
|
||||
var credentials = await credentialService.GetUserCredentialsFromCredentials();
|
||||
return new DashboardResponse
|
||||
{
|
||||
Users = users,
|
||||
UserCredentials = credentials
|
||||
Users = users
|
||||
};
|
||||
}
|
||||
|
||||
|
54
TaikoLocalServer/Controllers/Api/PlayHistoryController.cs
Normal file
54
TaikoLocalServer/Controllers/Api/PlayHistoryController.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using GameDatabase.Entities;
|
||||
using SharedProject.Models;
|
||||
using SharedProject.Models.Responses;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Api;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class PlayHistoryController(
|
||||
IUserDatumService userDatumService,
|
||||
ISongBestDatumService songBestDatumService,
|
||||
ISongPlayDatumService songPlayDatumService)
|
||||
: BaseController<PlayDataController>
|
||||
{
|
||||
private readonly ISongBestDatumService songBestDatumService = songBestDatumService;
|
||||
|
||||
[HttpGet("{baid}")]
|
||||
public async Task<ActionResult<SongHistoryResponse>> GetSongHistory(uint baid)
|
||||
{
|
||||
var user = await userDatumService.GetFirstUserDatumOrNull(baid);
|
||||
if (user is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var playLogs = await songPlayDatumService.GetSongPlayDatumByBaid(baid);
|
||||
var songHistory = playLogs.Select(play => new SongHistoryData
|
||||
{
|
||||
SongId = play.SongId,
|
||||
Difficulty = play.Difficulty,
|
||||
Score = play.Score,
|
||||
ScoreRank = play.ScoreRank,
|
||||
Crown = play.Crown,
|
||||
GoodCount = play.GoodCount,
|
||||
OkCount = play.OkCount,
|
||||
MissCount = play.MissCount,
|
||||
HitCount = play.HitCount,
|
||||
DrumrollCount = play.DrumrollCount,
|
||||
ComboCount = play.ComboCount,
|
||||
PlayTime = play.PlayTime,
|
||||
SongNumber = play.SongNumber
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var favoriteSongs = await userDatumService.GetFavoriteSongIds(baid);
|
||||
var favoriteSet = favoriteSongs.ToHashSet();
|
||||
foreach (var song in songHistory.Where(song => favoriteSet.Contains(song.SongId)))
|
||||
{
|
||||
song.IsFavorite = true;
|
||||
}
|
||||
|
||||
return Ok(new SongHistoryResponse{SongHistoryData = songHistory});
|
||||
}
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Serilog.Sinks.File.Header;
|
||||
using TaikoLocalServer.Logging;
|
||||
using GameDatabase.Context;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.HttpLogging;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using TaikoLocalServer.Middlewares;
|
||||
using TaikoLocalServer.Services.Extentions;
|
||||
using TaikoLocalServer.Settings;
|
||||
@ -39,6 +42,7 @@ try
|
||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/Database.json", optional: false, reloadOnChange: false);
|
||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/ServerSettings.json", optional: false, reloadOnChange: false);
|
||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/DataSettings.json", optional: true, reloadOnChange: false);
|
||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/AuthSettings.json", optional: true, reloadOnChange: false);
|
||||
|
||||
builder.Host.UseSerilog((context, configuration) =>
|
||||
{
|
||||
@ -65,6 +69,27 @@ try
|
||||
builder.Services.AddSingleton<IGameDataService, GameDataService>();
|
||||
builder.Services.Configure<ServerSettings>(builder.Configuration.GetSection(nameof(ServerSettings)));
|
||||
builder.Services.Configure<DataSettings>(builder.Configuration.GetSection(nameof(DataSettings)));
|
||||
builder.Services.Configure<AuthSettings>(builder.Configuration.GetSection(nameof(AuthSettings)));
|
||||
// Add Authentication with JWT
|
||||
builder.Services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = builder.Configuration.GetSection(nameof(AuthSettings))["JwtIssuer"],
|
||||
ValidAudience = builder.Configuration.GetSection(nameof(AuthSettings))["JwtAudience"],
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration.GetSection(nameof(AuthSettings))["JwtKey"] ?? throw new InvalidOperationException()))
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.AddControllers().AddProtoBufNet();
|
||||
builder.Services.AddDbContext<TaikoDbContext>(option =>
|
||||
{
|
||||
@ -125,13 +150,12 @@ try
|
||||
app.UseBlazorFrameworkFiles();
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
|
||||
|
||||
|
||||
app.UseHttpLogging();
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
await next();
|
||||
|
||||
|
||||
if (context.Response.StatusCode >= 400)
|
||||
{
|
||||
Log.Error("Unknown request from: {RemoteIpAddress} {Method} {Path} {StatusCode}",
|
||||
|
@ -4,15 +4,8 @@ using Swan.Mapping;
|
||||
|
||||
namespace TaikoLocalServer.Services;
|
||||
|
||||
public class CredentialService : ICredentialService
|
||||
public class CredentialService(TaikoDbContext context) : ICredentialService
|
||||
{
|
||||
private readonly TaikoDbContext context;
|
||||
|
||||
public CredentialService(TaikoDbContext context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public async Task<List<UserCredential>> GetUserCredentialsFromCredentials()
|
||||
{
|
||||
return await context.Credentials.Select(credential => credential.CopyPropertiesToNew<UserCredential>(null)).ToListAsync();
|
||||
@ -48,4 +41,9 @@ public class CredentialService : ICredentialService
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<Credential?> GetCredentialByBaid(uint baid)
|
||||
{
|
||||
return await context.Credentials.FindAsync(baid);
|
||||
}
|
||||
}
|
@ -4,11 +4,13 @@ namespace TaikoLocalServer.Services.Interfaces;
|
||||
|
||||
public interface ICredentialService
|
||||
{
|
||||
public Task<List<UserCredential>> GetUserCredentialsFromCredentials();
|
||||
public Task<List<UserCredential>> GetUserCredentialsFromCredentials();
|
||||
|
||||
public Task AddCredential(Credential credential);
|
||||
public Task AddCredential(Credential credential);
|
||||
|
||||
public Task<bool> DeleteCredential(uint baid);
|
||||
public Task<bool> DeleteCredential(uint baid);
|
||||
|
||||
public Task<bool> UpdatePassword(uint baid, string password, string salt);
|
||||
public Task<bool> UpdatePassword(uint baid, string password, string salt);
|
||||
|
||||
public Task<Credential?> GetCredentialByBaid(uint baid);
|
||||
}
|
10
TaikoLocalServer/Settings/AuthSettings.cs
Normal file
10
TaikoLocalServer/Settings/AuthSettings.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace TaikoLocalServer.Settings;
|
||||
|
||||
public class AuthSettings
|
||||
{
|
||||
public string JwtKey { get; set; } = string.Empty;
|
||||
|
||||
public string JwtIssuer { get; set; } = string.Empty;
|
||||
|
||||
public string JwtAudience { get; set; } = string.Empty;
|
||||
}
|
@ -6,171 +6,183 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>1.1.0</Version>
|
||||
<LangVersion>12</LangVersion>
|
||||
<EnableConfigurationBindingGenerator>false</EnableConfigurationBindingGenerator>
|
||||
<EnableConfigurationBindingGenerator>false</EnableConfigurationBindingGenerator>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Templates\TemplateController.cs" />
|
||||
<Compile Remove="Templates\TemplateController.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetZip" Version="1.16.0" />
|
||||
<PackageReference Include="MediatR" Version="12.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.0-rc.1.23421.29" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0-rc.2.23480.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0-rc.2.23480.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Otp.NET" Version="1.4.0" />
|
||||
<PackageReference Include="protobuf-net" Version="3.2.30" />
|
||||
<PackageReference Include="protobuf-net.AspNetCore" Version="3.2.12" />
|
||||
<PackageReference Include="Riok.Mapperly" Version="3.5.0-next.1" />
|
||||
<PackageReference Include="Riok.Mapperly" Version="3.5.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.2-dev-00334" />
|
||||
<PackageReference Include="Serilog.Expressions" Version="4.0.0-dev-00137" />
|
||||
<PackageReference Include="Serilog.Expressions" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File.Header" Version="1.0.2" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageReference Include="Swan.Core" Version="7.0.0-beta.2" />
|
||||
<PackageReference Include="Swan.Logging" Version="6.0.2-beta.96" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="Throw" Version="1.4.0" />
|
||||
<PackageReference Include="Yoh.Text.Json.NamingPolicies" Version="1.0.0" />
|
||||
<PackageReference Include="Yoh.Text.Json.NamingPolicies" Version="1.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Certificates\cert.pfx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Certificates\root.pfx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Remove="Configurations\ServerSettings.json" />
|
||||
<None Include="Configurations\ServerSettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Remove="Configurations\Database.json" />
|
||||
<None Include="Configurations\Database.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Remove="Configurations\DataSettings.json" />
|
||||
<None Include="Configurations\DataSettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Remove="Configurations\Kestrel.json" />
|
||||
<None Include="Configurations\Kestrel.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Remove="Configurations\Logging.json" />
|
||||
<None Include="Configurations\Logging.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Update="wwwroot\data\locked_songs_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\movie_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\music_order.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\musicinfo.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\shop_folder_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\token_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\wordlist.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\gaiden_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\qrcode_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\music_order.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\musicinfo.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\wordlist.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\don_cos_reward.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\don_cos_reward.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\shougou.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\shougou.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\neiro.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\neiro.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\don_cos_reward.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\music_order.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\musicinfo.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\neiro.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\shougou.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\wordlist.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\don_cos_reward.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\musicinfo.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\music_order.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\neiro.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\shougou.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\wordlist.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Update="Certificates\cert.pfx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Certificates\root.pfx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Remove="Configurations\ServerSettings.json" />
|
||||
<None Include="Configurations\AuthSettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Configurations\ServerSettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Remove="Configurations\Database.json" />
|
||||
<None Include="Configurations\Database.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Remove="Configurations\DataSettings.json" />
|
||||
<None Include="Configurations\DataSettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Remove="Configurations\Kestrel.json" />
|
||||
<None Include="Configurations\Kestrel.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Remove="Configurations\Logging.json" />
|
||||
<None Include="Configurations\Logging.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Update="wwwroot\data\locked_songs_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\movie_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\music_order.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\musicinfo.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\shop_folder_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\token_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\wordlist.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\gaiden_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\qrcode_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\music_order.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\musicinfo.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\wordlist.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\don_cos_reward.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\don_cos_reward.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\shougou.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\shougou.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\neiro.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\neiro.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\don_cos_reward.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\music_order.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\musicinfo.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\neiro.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\shougou.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\wordlist.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\locked_costume_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\locked_title_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\don_cos_reward.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\musicinfo.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\music_order.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\neiro.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\shougou.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable-bak\wordlist.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\data\dan_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\event_folder_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\intro_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\dan_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\event_folder_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\intro_data.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GameDatabase\GameDatabase.csproj" />
|
||||
<ProjectReference Include="..\SharedProject\SharedProject.csproj" />
|
||||
<ProjectReference Include="..\GameDatabase\GameDatabase.csproj" />
|
||||
<ProjectReference Include="..\SharedProject\SharedProject.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ProjectReference Include="..\TaikoWebUI\TaikoWebUI.csproj" />
|
||||
|
17
TaikoLocalServer/wwwroot/data/locked_costume_data.json
Normal file
17
TaikoLocalServer/wwwroot/data/locked_costume_data.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"Kigurumi": [
|
||||
|
||||
],
|
||||
"Head": [
|
||||
|
||||
],
|
||||
"Body": [
|
||||
|
||||
],
|
||||
"Face": [
|
||||
|
||||
],
|
||||
"Puchi": [
|
||||
|
||||
]
|
||||
}
|
8
TaikoLocalServer/wwwroot/data/locked_title_data.json
Normal file
8
TaikoLocalServer/wwwroot/data/locked_title_data.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"TitleNo": [
|
||||
|
||||
],
|
||||
"TitlePlateNo": [
|
||||
|
||||
]
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
<MudMenu Icon="@Icons.Material.Filled.Translate" Color="Color.Inherit" Size="Size.Small" Dense="true">
|
||||
@foreach (var culture in SupportedCultures)
|
||||
{
|
||||
<MudMenuItem OnClick="() => RequestCultureChange(culture.Key)">@culture.Value</MudMenuItem>
|
||||
<MudMenuItem OnClick="() => RequestCultureChange(culture.Key)" OnTouch="() => RequestCultureChange(culture.Key)">@culture.Value</MudMenuItem>
|
||||
}
|
||||
</MudMenu>
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
@inherits LayoutComponentBase
|
||||
@inject Blazored.LocalStorage.ILocalStorageService localStorage
|
||||
@inject Blazored.LocalStorage.ILocalStorageService LocalStorage
|
||||
@inject HttpClient Client
|
||||
@inject LoginService LoginService
|
||||
|
||||
<MudThemeProvider IsDarkMode="@_isDarkMode" Theme="@TaikoWebUiTheme" />
|
||||
<MudThemeProvider IsDarkMode="@isDarkMode" Theme="@taikoWebUiTheme" />
|
||||
<MudDialogProvider />
|
||||
<MudSnackbarProvider />
|
||||
|
||||
@ -14,7 +16,7 @@
|
||||
<ChooseLanguage />
|
||||
</MudStack>
|
||||
</MudAppBar>
|
||||
<MudDrawer Elevation="0" Style="border-right:1px solid #ededf0" @bind-Open="_drawerOpen">
|
||||
<MudDrawer Elevation="0" Style="border-right:1px solid #ededf0" @bind-Open="drawerOpen">
|
||||
<MudDrawerHeader>
|
||||
<MudText Typo="Typo.h6">TaikoWebUI</MudText>
|
||||
</MudDrawerHeader>
|
||||
@ -32,41 +34,61 @@
|
||||
</MudLayout>
|
||||
|
||||
@code {
|
||||
bool _drawerOpen = true;
|
||||
bool _isDarkMode = false;
|
||||
bool drawerOpen = true;
|
||||
bool isDarkMode = false;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var hasDrawerOpenEntry = await localStorage.ContainKeyAsync("drawerOpen");
|
||||
var hasDrawerOpenEntry = await LocalStorage.ContainKeyAsync("drawerOpen");
|
||||
|
||||
if (hasDrawerOpenEntry)
|
||||
{
|
||||
_drawerOpen = await localStorage.GetItemAsync<bool>("drawerOpen");
|
||||
drawerOpen = await LocalStorage.GetItemAsync<bool>("drawerOpen");
|
||||
}
|
||||
|
||||
var hasDarkModeEntry = await localStorage.ContainKeyAsync("isDarkMode");
|
||||
var hasDarkModeEntry = await LocalStorage.ContainKeyAsync("isDarkMode");
|
||||
|
||||
if (hasDarkModeEntry)
|
||||
{
|
||||
_isDarkMode = await localStorage.GetItemAsync<bool>("isDarkMode");
|
||||
isDarkMode = await LocalStorage.GetItemAsync<bool>("isDarkMode");
|
||||
}
|
||||
|
||||
if (LoginService.LoginRequired)
|
||||
{
|
||||
// If not logged in, attempt to use JwtToken from local storage to log in
|
||||
var hasJwtToken = await LocalStorage.ContainKeyAsync("authToken");
|
||||
if (hasJwtToken)
|
||||
{
|
||||
var authToken = await LocalStorage.GetItemAsync<string>("authToken");
|
||||
if (!string.IsNullOrWhiteSpace(authToken))
|
||||
{
|
||||
// Attempt to log in with the token
|
||||
var loginResult = await LoginService.LoginWithAuthToken(authToken, Client);
|
||||
if (!loginResult)
|
||||
{
|
||||
// Failed to log in with the token, remove it
|
||||
await LocalStorage.RemoveItemAsync("authToken");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DrawerToggle()
|
||||
{
|
||||
_drawerOpen = !_drawerOpen;
|
||||
await localStorage.SetItemAsync("drawerOpen", _drawerOpen);
|
||||
drawerOpen = !drawerOpen;
|
||||
await LocalStorage.SetItemAsync("drawerOpen", drawerOpen);
|
||||
}
|
||||
|
||||
private async Task ToggleDarkMode()
|
||||
{
|
||||
_isDarkMode = !_isDarkMode;
|
||||
await localStorage.SetItemAsync("isDarkMode", _isDarkMode);
|
||||
isDarkMode = !isDarkMode;
|
||||
await LocalStorage.SetItemAsync("isDarkMode", isDarkMode);
|
||||
}
|
||||
|
||||
private string DarkModeIcon => _isDarkMode ? Icons.Material.Filled.BrightnessLow : Icons.Material.Filled.Brightness2;
|
||||
private string DarkModeIcon => isDarkMode ? Icons.Material.Filled.BrightnessLow : Icons.Material.Filled.Brightness2;
|
||||
|
||||
MudTheme TaikoWebUiTheme = new MudTheme()
|
||||
readonly MudTheme taikoWebUiTheme = new()
|
||||
{
|
||||
Palette = new PaletteLight()
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
@using TaikoWebUI.Pages.Dialogs;
|
||||
|
||||
<MudNavMenu Rounded="true" Class="pa-2" Margin="Margin.Dense" Color="Color.Primary">
|
||||
<MudNavLink Href="/" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Dashboard">@Localizer["dashboard"]</MudNavLink>
|
||||
<MudNavLink Href="/" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Dashboard">@Localizer["Dashboard"]</MudNavLink>
|
||||
@if (LoginService.IsAdmin || !LoginService.LoginRequired)
|
||||
{
|
||||
<MudNavLink Href="/Users" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.People">@Localizer["Users"]</MudNavLink>
|
||||
@ -24,12 +24,13 @@
|
||||
{
|
||||
<MudDivider />
|
||||
<MudNavLink Href="@($"Users/{currentUser.Baid}/Profile")" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Person">@Localizer["Profile"]</MudNavLink>
|
||||
<MudNavGroup Title="Play Data" Expanded="true" Icon="@Icons.Material.Filled.EmojiEvents">
|
||||
<MudNavLink Href="@($"Users/{currentUser.Baid}/Songs")" Match="NavLinkMatch.All">@Localizer["Key_01"]</MudNavLink>
|
||||
<MudNavLink Href="@($"Users/{currentUser.Baid}/HighScores")" Match="NavLinkMatch.All">@Localizer["High Scores"]</MudNavLink>
|
||||
<MudNavLink Href="@($"Users/{currentUser.Baid}/DaniDojo")" Match="NavLinkMatch.All">@Localizer["Key_03"]</MudNavLink>
|
||||
<MudNavGroup Title=@Localizer["Play Data"] Expanded="true" Icon="@Icons.Material.Filled.EmojiEvents">
|
||||
<MudNavLink Href="@($"Users/{currentUser.Baid}/Songs")" Match="NavLinkMatch.All">@Localizer["Song List"]</MudNavLink>
|
||||
<MudNavLink Href="@($"Users/{currentUser.Baid}/HighScores")" Match="NavLinkMatch.All">@Localizer["High Scores"]</MudNavLink>
|
||||
<MudNavLink Href="@($"Users/{currentUser.Baid}/PlayHistory")" Match="NavLinkMatch.All">@Localizer["Play History"]</MudNavLink>
|
||||
<MudNavLink Href="@($"Users/{currentUser.Baid}/DaniDojo")" Match="NavLinkMatch.All">@Localizer["Dani Dojo"]</MudNavLink>
|
||||
</MudNavGroup>
|
||||
<MudNavGroup Title="Settings" Expanded="_settingsOpen" Icon="@Icons.Material.Filled.Settings">
|
||||
<MudNavGroup Title=@Localizer["Settings"] Expanded="_settingsOpen" Icon="@Icons.Material.Filled.Settings">
|
||||
<MudNavLink OnClick="ShowQrCode">@Localizer["Show QR Code"]</MudNavLink>
|
||||
<MudNavLink Href="/ChangePassword" Match="NavLinkMatch.All">@Localizer["Change Password"]</MudNavLink>
|
||||
<MudNavLink Href="@($"Users/{currentUser.Baid}/AccessCode")" Match="NavLinkMatch.All">@Localizer["Access Codes"]</MudNavLink>
|
||||
@ -73,7 +74,7 @@
|
||||
};
|
||||
|
||||
var options = new DialogOptions() { DisableBackdropClick = true };
|
||||
DialogService.Show<UserQrCodeDialog>("QR Code", parameters, options);
|
||||
DialogService.Show<UserQrCodeDialog>(@Localizer["QR Code"], parameters, options);
|
||||
|
||||
// Prevent the settings menu from closing
|
||||
_settingsOpen = true;
|
||||
|
@ -2,35 +2,84 @@
|
||||
|
||||
<MudCard Outlined="true" Elevation="0">
|
||||
<MudCardHeader>
|
||||
<MudText Typo="Typo.h6">Play History</MudText>
|
||||
<MudGrid Spacing="2">
|
||||
<MudItem xs="12" md="4">
|
||||
<MudText Typo="Typo.h6">@Localizer["Play History"]</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="8">
|
||||
<MudText Typo="Typo.h6">@Localizer["Total Plays"]:@Items.Count</MudText>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudCardHeader>
|
||||
|
||||
@if (Items != null && Items.Count > 0)
|
||||
@if (Items.Count > 0)
|
||||
{
|
||||
<MudCardContent Class="p-0">
|
||||
<MudTable Items="Items" Elevation="0" Striped="true">
|
||||
<HeaderContent>
|
||||
<MudTh>@Localizer["Play Time"]</MudTh>
|
||||
<MudTh>@Localizer["Difficulty"]</MudTh>
|
||||
<MudTh>@Localizer["Crown"]</MudTh>
|
||||
<MudTh>@Localizer["Rank"]</MudTh>
|
||||
<MudTh>@Localizer["Score"]</MudTh>
|
||||
<MudTh>@Localizer["Good"]</MudTh>
|
||||
<MudTh>@Localizer["Ok"]</MudTh>
|
||||
<MudTh>@Localizer["Bad"]</MudTh>
|
||||
<MudTh>@Localizer["Drumroll"]</MudTh>
|
||||
<MudTh>@Localizer["Max Combo"]</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel InitialDirection="SortDirection.Descending" T="SongPlayDatumDto" SortBy="x => x.PlayTime">
|
||||
@Localizer["Play Time"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongPlayDatumDto" SortBy="x => x.Difficulty">
|
||||
@Localizer["Difficulty"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongPlayDatumDto" SortBy="x => x.Crown">
|
||||
@Localizer["Crown"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongPlayDatumDto" SortBy="x => x.ScoreRank">
|
||||
@Localizer["Rank"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongPlayDatumDto" SortBy="x => x.Score">
|
||||
@Localizer["Score"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongPlayDatumDto" SortBy="x => x.GoodCount">
|
||||
@Localizer["Good"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongPlayDatumDto" SortBy="x => x.OkCount">
|
||||
@Localizer["OK"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongPlayDatumDto" SortBy="x => x.MissCount">
|
||||
@Localizer["Bad"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongPlayDatumDto" SortBy="x => x.DrumrollCount">
|
||||
@Localizer["Drumroll"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongPlayDatumDto" SortBy="x => x.ComboCount">
|
||||
@Localizer["MAX Combo"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.PlayTime.ToString(Localizer["DateFormat"])</MudTd>
|
||||
<MudTd>
|
||||
<img src="@ScoreUtils.GetDifficultyIcon(context.Difficulty)" alt="@context.Difficulty" title="@context.Difficulty" style="@IconStyle" />
|
||||
<img src="@ScoreUtils.GetDifficultyIcon(context.Difficulty)" alt="@context.Difficulty" title="@context.Difficulty" style="@IconStyle"/>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
<img src="@($"/images/crown_{context.Crown}.png")" alt="@(ScoreUtils.GetCrownText(context.Crown))" title="@(ScoreUtils.GetCrownText(context.Crown))" style="@IconStyle" />
|
||||
<img src="@($"/images/crown_{context.Crown}.png")" alt="@(ScoreUtils.GetCrownText(context.Crown))" title="@(ScoreUtils.GetCrownText(context.Crown))" style="@IconStyle"/>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
<img src="@($"/images/rank_{context.ScoreRank}.png")" alt="@(ScoreUtils.GetRankText(context.ScoreRank))" title="@(ScoreUtils.GetRankText(context.ScoreRank))" style="@IconStyle" />
|
||||
@if (context.ScoreRank is not ScoreRank.None)
|
||||
{
|
||||
<img src="@($"/images/rank_{context.ScoreRank}.png")" alt="@(ScoreUtils.GetRankText(context.ScoreRank))" title="@(ScoreUtils.GetRankText(context.ScoreRank))" style="@IconStyle"/>
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd>@context.Score</MudTd>
|
||||
<MudTd>@context.GoodCount</MudTd>
|
||||
@ -46,13 +95,13 @@
|
||||
{
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2" Class="pt-4 pb-8" Color="Color.Surface" Align="Align.Center">
|
||||
@Localizer["No play history found."]
|
||||
@Localizer["No Play History Found"]
|
||||
</MudText>
|
||||
</MudCardContent>
|
||||
}
|
||||
</MudCard>
|
||||
|
||||
@code {
|
||||
[Parameter] public List<SongPlayDatumDto> Items { get; set; } = new List<SongPlayDatumDto>();
|
||||
[Parameter] public List<SongPlayDatumDto> Items { get; set; } = new();
|
||||
private const string IconStyle = "width:25px; height:25px;";
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
@using Microsoft.AspNetCore.Components;
|
||||
@using System.Text.Json
|
||||
@using Microsoft.AspNetCore.Components;
|
||||
@using TaikoWebUI.Pages.Dialogs;
|
||||
@inject TaikoWebUI.Utilities.StringUtil StringUtil;
|
||||
@inject IDialogService DialogService;
|
||||
@ -26,7 +27,7 @@
|
||||
<MudChip Variant="Variant.Outlined" Color="Color.Info" Size="Size.Small" Icon="@Icons.Material.TwoTone.AdminPanelSettings">@Localizer["Admin"]</MudChip>
|
||||
}
|
||||
</div>
|
||||
<MudText Typo="Typo.caption">User ID: @user?.Baid</MudText>
|
||||
<MudText Typo="Typo.caption">@Localizer["User"] BAID: @user?.Baid</MudText>
|
||||
</CardHeaderContent>
|
||||
<CardHeaderActions>
|
||||
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Dense="true" AnchorOrigin="Origin.BottomLeft"
|
||||
@ -54,6 +55,16 @@
|
||||
<MudDivider />
|
||||
}
|
||||
@if (LoginService.LoginRequired && LoginService.IsAdmin)
|
||||
{
|
||||
<MudMenuItem Icon="@Icons.Material.Filled.Password"
|
||||
OnClick="@(_ => GenerateInviteCode(user.Baid))"
|
||||
OnTouch="@(_ => GenerateInviteCode(user.Baid))"
|
||||
IconColor="@Color.Primary">
|
||||
@Localizer["Generate Invite Code"]
|
||||
</MudMenuItem>
|
||||
<MudDivider />
|
||||
}
|
||||
@if (LoginService.LoginRequired && LoginService.IsAdmin)
|
||||
{
|
||||
<MudMenuItem Icon="@Icons.Material.Filled.LockReset"
|
||||
OnClick="@(_ => ResetPassword(user))"
|
||||
@ -76,7 +87,7 @@
|
||||
</CardHeaderActions>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2" Style="font-weight:bold">Access Code</MudText>
|
||||
<MudText Typo="Typo.body2" Style="font-weight:bold">@Localizer["Access Code"]</MudText>
|
||||
<MudText Style="font-family:monospace;overflow:hidden;overflow-x:scroll">
|
||||
@if (user.AccessCodes.Count > 0)
|
||||
{
|
||||
@ -91,7 +102,12 @@
|
||||
</MudText>
|
||||
@if (user.AccessCodes.Count > 1)
|
||||
{
|
||||
<MudText Typo="Typo.caption">... and @(user.AccessCodes.Count - 1) other access code(s)</MudText>
|
||||
<MudText Typo="Typo.caption">... @Localizer["and"] @(user.AccessCodes.Count - 1) @Localizer["other access code(s)"]</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
// Empty line to keep the layout consistent
|
||||
<MudText Typo="Typo.caption"> </MudText>
|
||||
}
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
@ -104,19 +120,20 @@
|
||||
<MudMenu Size="Size.Small"
|
||||
Dense="true"
|
||||
Color="Color.Primary"
|
||||
Label="@Localizer["view play data"]"
|
||||
Label="@Localizer["View Play Data"]"
|
||||
StartIcon="@Icons.Material.Filled.EmojiEvents"
|
||||
EndIcon="@Icons.Material.Filled.KeyboardArrowDown"
|
||||
FullWidth="true"
|
||||
AnchorOrigin="Origin.BottomCenter"
|
||||
TransformOrigin="Origin.TopCenter">
|
||||
<MudMenuItem Href="@($"Users/{user.Baid}/HighScores")">@Localizer["High Scores"]</MudMenuItem>
|
||||
<MudMenuItem Href="@($"Users/{user.Baid}/Songs")">@Localizer["Song List"]</MudMenuItem>
|
||||
<MudMenuItem Href="@($"Users/{user.Baid}/DaniDojo")">@Localizer["dani dojo"]</MudMenuItem>
|
||||
</MudMenu>
|
||||
</MudStack>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
<MudMenuItem Href="@($"Users/{user.Baid}/HighScores")">@Localizer["High Scores"]</MudMenuItem>
|
||||
<MudMenuItem Href="@($"Users/{user.Baid}/PlayHistory")">@Localizer["Play History"]</MudMenuItem>
|
||||
<MudMenuItem Href="@($"Users/{user.Baid}/Songs")">@Localizer["Song List"]</MudMenuItem>
|
||||
<MudMenuItem Href="@($"Users/{user.Baid}/DaniDojo")">@Localizer["Dani Dojo"]</MudMenuItem>
|
||||
</MudMenu>
|
||||
</MudStack>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
}
|
||||
|
||||
@code {
|
||||
@ -139,7 +156,7 @@
|
||||
};
|
||||
|
||||
var options = new DialogOptions() { DisableBackdropClick = true };
|
||||
DialogService.Show<UserQrCodeDialog>("QR Code", parameters, options);
|
||||
DialogService.Show<UserQrCodeDialog>(Localizer["QR Code"], parameters, options);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@ -150,9 +167,9 @@
|
||||
if (LoginService.LoginRequired && !LoginService.IsAdmin)
|
||||
{
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
"Only admin can reset password.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
return;
|
||||
}
|
||||
var parameters = new DialogParameters
|
||||
@ -160,7 +177,7 @@
|
||||
["user"] = user
|
||||
};
|
||||
|
||||
var dialog = DialogService.Show<ResetPasswordConfirmDialog>("Reset Password", parameters, options);
|
||||
var dialog = DialogService.Show<ResetPasswordConfirmDialog>(Localizer["Reset Password"], parameters, options);
|
||||
var result = await dialog.Result;
|
||||
|
||||
if (result.Canceled) return;
|
||||
@ -174,9 +191,9 @@
|
||||
if (!LoginService.AllowUserDelete)
|
||||
{
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
"User deletion is disabled by admin.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
return;
|
||||
}
|
||||
var parameters = new DialogParameters
|
||||
@ -184,7 +201,7 @@
|
||||
["user"] = user
|
||||
};
|
||||
|
||||
var dialog = DialogService.Show<UserDeleteConfirmDialog>("Delete User", parameters, options);
|
||||
var dialog = DialogService.Show<UserDeleteConfirmDialog>(Localizer["Delete User"], parameters, options);
|
||||
var result = await dialog.Result;
|
||||
|
||||
if (result.Canceled) return;
|
||||
@ -193,4 +210,46 @@
|
||||
LoginService.Logout();
|
||||
NavigationManager.NavigateTo("/Users");
|
||||
}
|
||||
|
||||
private async Task GenerateInviteCode(uint baid)
|
||||
{
|
||||
var request = new GenerateOtpRequest
|
||||
{
|
||||
Baid = baid
|
||||
};
|
||||
|
||||
var responseMessage = await Client.PostAsJsonAsync("api/Auth/GenerateOtp", request);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode)
|
||||
{
|
||||
await DialogService.ShowMessageBox(
|
||||
Localizer["Error"],
|
||||
Localizer["Unknown Error"],
|
||||
Localizer["Dialog OK"], null, null, new DialogOptions { DisableBackdropClick = true });
|
||||
return;
|
||||
}
|
||||
|
||||
var responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
var responseJson = JsonSerializer.Deserialize<Dictionary<string, string>>(responseContent);
|
||||
if (responseJson == null)
|
||||
{
|
||||
await DialogService.ShowMessageBox(
|
||||
Localizer["Error"],
|
||||
Localizer["Unknown Error"],
|
||||
Localizer["Dialog OK"], null, null, new DialogOptions { DisableBackdropClick = true });
|
||||
return;
|
||||
}
|
||||
|
||||
var otp = responseJson["otp"];
|
||||
|
||||
var parameters = new DialogParameters
|
||||
{
|
||||
["otp"] = otp
|
||||
};
|
||||
|
||||
var options = new DialogOptions() { DisableBackdropClick = true };
|
||||
DialogService.Show<OTPDialog>(Localizer["Invite Code"], parameters, options);
|
||||
|
||||
|
||||
}
|
||||
}
|
748
TaikoWebUI/Localization/LocalizationResource.Designer.cs
generated
748
TaikoWebUI/Localization/LocalizationResource.Designer.cs
generated
@ -1,7 +1,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@ -60,6 +59,186 @@ namespace TaikoWebUI.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string _Invite_Code__Optional__ {
|
||||
get {
|
||||
return ResourceManager.GetString("\"Invite Code (Optional)\"", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Access_Code {
|
||||
get {
|
||||
return ResourceManager.GetString("Access Code", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Access_Code_is_Required {
|
||||
get {
|
||||
return ResourceManager.GetString("Access Code is Required", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Access_Codes {
|
||||
get {
|
||||
return ResourceManager.GetString("Access Codes", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Achievement_Panel {
|
||||
get {
|
||||
return ResourceManager.GetString("Achievement Panel", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Achievement_Panel_Difficulty {
|
||||
get {
|
||||
return ResourceManager.GetString("Achievement Panel Difficulty", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Add_Access_Code {
|
||||
get {
|
||||
return ResourceManager.GetString("Add Access Code", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string AI_Battle_Data {
|
||||
get {
|
||||
return ResourceManager.GetString("AI Battle Data", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string and {
|
||||
get {
|
||||
return ResourceManager.GetString("and", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Bad {
|
||||
get {
|
||||
return ResourceManager.GetString("Bad", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Best_Crown {
|
||||
get {
|
||||
return ResourceManager.GetString("Best Crown", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Best_Rank {
|
||||
get {
|
||||
return ResourceManager.GetString("Best Rank", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Chojin {
|
||||
get {
|
||||
return ResourceManager.GetString("Chojin", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Confirm_New_Password {
|
||||
get {
|
||||
return ResourceManager.GetString("Confirm New Password", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Confirm_Password {
|
||||
get {
|
||||
return ResourceManager.GetString("Confirm Password", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Confirm_Password_is_Required {
|
||||
get {
|
||||
return ResourceManager.GetString("Confirm Password is Required", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Copy_to_Clipboard {
|
||||
get {
|
||||
return ResourceManager.GetString("Copy to Clipboard", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Course_Songs {
|
||||
get {
|
||||
return ResourceManager.GetString("Course Songs", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Dani_Dojo {
|
||||
get {
|
||||
return ResourceManager.GetString("Dani Dojo", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Dashboard {
|
||||
get {
|
||||
return ResourceManager.GetString("Dashboard", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to MM/dd/yyyy h:mm:ss tt.
|
||||
/// </summary>
|
||||
@ -68,5 +247,572 @@ namespace TaikoWebUI.Localization {
|
||||
return ResourceManager.GetString("DateFormat", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Delete {
|
||||
get {
|
||||
return ResourceManager.GetString("Delete", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Dialog_OK {
|
||||
get {
|
||||
return ResourceManager.GetString("Dialog OK", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Difficulty {
|
||||
get {
|
||||
return ResourceManager.GetString("Difficulty", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Eighth_Dan {
|
||||
get {
|
||||
return ResourceManager.GetString("Eighth Dan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Error {
|
||||
get {
|
||||
return ResourceManager.GetString("Error", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Fifth_Dan {
|
||||
get {
|
||||
return ResourceManager.GetString("Fifth Dan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Fifth_Kyuu {
|
||||
get {
|
||||
return ResourceManager.GetString("Fifth Kyuu", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Filter_by_Genre {
|
||||
get {
|
||||
return ResourceManager.GetString("Filter by Genre", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string First_Dan {
|
||||
get {
|
||||
return ResourceManager.GetString("First Dan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string First_Kyuu {
|
||||
get {
|
||||
return ResourceManager.GetString("First Kyuu", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Fourth_Dan {
|
||||
get {
|
||||
return ResourceManager.GetString("Fourth Dan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Fourth_Kyuu {
|
||||
get {
|
||||
return ResourceManager.GetString("Fourth Kyuu", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Gaiden {
|
||||
get {
|
||||
return ResourceManager.GetString("Gaiden", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Generate_Invite_Code {
|
||||
get {
|
||||
return ResourceManager.GetString("Generate Invite Code", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Gold_Donderful_Combo {
|
||||
get {
|
||||
return ResourceManager.GetString("Gold Donderful Combo", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Gold_Full_Combo {
|
||||
get {
|
||||
return ResourceManager.GetString("Gold Full Combo", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string High_Scores {
|
||||
get {
|
||||
return ResourceManager.GetString("High Scores", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Invite_Code {
|
||||
get {
|
||||
return ResourceManager.GetString("Invite Code", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Kuroto {
|
||||
get {
|
||||
return ResourceManager.GetString("Kuroto", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Last_Play_Date {
|
||||
get {
|
||||
return ResourceManager.GetString("Last Play Date", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Last_Play_Time_5_Min_Around_Credit_End_ {
|
||||
get {
|
||||
return ResourceManager.GetString("Last Play Time(5 Min Around Credit End)", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Log_In {
|
||||
get {
|
||||
return ResourceManager.GetString("Log In", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Log_In_First {
|
||||
get {
|
||||
return ResourceManager.GetString("Log In First", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Log_Out {
|
||||
get {
|
||||
return ResourceManager.GetString("Log Out", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Meijin {
|
||||
get {
|
||||
return ResourceManager.GetString("Meijin", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string New_Access_Code {
|
||||
get {
|
||||
return ResourceManager.GetString("New Access Code", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string New_Password {
|
||||
get {
|
||||
return ResourceManager.GetString("New Password", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Ninth_Dan {
|
||||
get {
|
||||
return ResourceManager.GetString("Ninth Dan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string No_Play_History_Found {
|
||||
get {
|
||||
return ResourceManager.GetString("No Play History Found", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Not_Cleared {
|
||||
get {
|
||||
return ResourceManager.GetString("Not Cleared", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Old_Password {
|
||||
get {
|
||||
return ResourceManager.GetString("Old Password", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string other_access_code_s_ {
|
||||
get {
|
||||
return ResourceManager.GetString("other access code(s)", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Password {
|
||||
get {
|
||||
return ResourceManager.GetString("Password", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Password_is_Required {
|
||||
get {
|
||||
return ResourceManager.GetString("Password is Required", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Play_Data {
|
||||
get {
|
||||
return ResourceManager.GetString("Play Data", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Play_History {
|
||||
get {
|
||||
return ResourceManager.GetString("Play History", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Play_Time {
|
||||
get {
|
||||
return ResourceManager.GetString("Play Time", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string QR_Code {
|
||||
get {
|
||||
return ResourceManager.GetString("QR Code", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Rank {
|
||||
get {
|
||||
return ResourceManager.GetString("Rank", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Red_Donderful_Combo {
|
||||
get {
|
||||
return ResourceManager.GetString("Red Donderful Combo", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Red_Full_Combo {
|
||||
get {
|
||||
return ResourceManager.GetString("Red Full Combo", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Register {
|
||||
get {
|
||||
return ResourceManager.GetString("Register", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Search_by_Title__Artist_or_Date {
|
||||
get {
|
||||
return ResourceManager.GetString("Search by Title, Artist or Date", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Search_by_Title_or_Artist {
|
||||
get {
|
||||
return ResourceManager.GetString("Search by Title or Artist", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Second_Dan {
|
||||
get {
|
||||
return ResourceManager.GetString("Second Dan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Second_Kyuu {
|
||||
get {
|
||||
return ResourceManager.GetString("Second Kyuu", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Settings {
|
||||
get {
|
||||
return ResourceManager.GetString("Settings", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Seventh_Dan {
|
||||
get {
|
||||
return ResourceManager.GetString("Seventh Dan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Sixth_Dan {
|
||||
get {
|
||||
return ResourceManager.GetString("Sixth Dan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Song_List {
|
||||
get {
|
||||
return ResourceManager.GetString("Song List", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Song_Name {
|
||||
get {
|
||||
return ResourceManager.GetString("Song Name", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Song_Number {
|
||||
get {
|
||||
return ResourceManager.GetString("Song Number", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Song_Title___Artist {
|
||||
get {
|
||||
return ResourceManager.GetString("Song Title / Artist", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Success {
|
||||
get {
|
||||
return ResourceManager.GetString("Success", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Tatsujin {
|
||||
get {
|
||||
return ResourceManager.GetString("Tatsujin", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Tenth_Dan {
|
||||
get {
|
||||
return ResourceManager.GetString("Tenth Dan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Third_Dan {
|
||||
get {
|
||||
return ResourceManager.GetString("Third Dan", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Third_Kyuu {
|
||||
get {
|
||||
return ResourceManager.GetString("Third Kyuu", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Unknown_Error {
|
||||
get {
|
||||
return ResourceManager.GetString("Unknown Error", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Unregister {
|
||||
get {
|
||||
return ResourceManager.GetString("Unregister", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string User {
|
||||
get {
|
||||
return ResourceManager.GetString("User", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Users {
|
||||
get {
|
||||
return ResourceManager.GetString("Users", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string View_Play_Data {
|
||||
get {
|
||||
return ResourceManager.GetString("View Play Data", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,31 +117,28 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="dashboard" xml:space="preserve">
|
||||
<data name="Dashboard" xml:space="preserve">
|
||||
<value>Dashboard</value>
|
||||
</data>
|
||||
<data name="users" xml:space="preserve">
|
||||
<data name="Users" xml:space="preserve">
|
||||
<value>Users</value>
|
||||
</data>
|
||||
<data name="edit profile" xml:space="preserve">
|
||||
<value>Edit Profile</value>
|
||||
</data>
|
||||
<data name="user" xml:space="preserve">
|
||||
<data name="User" xml:space="preserve">
|
||||
<value>User</value>
|
||||
</data>
|
||||
<data name="view play data" xml:space="preserve">
|
||||
<data name="View Play Data" xml:space="preserve">
|
||||
<value>View Play Data</value>
|
||||
</data>
|
||||
<data name="high scores" xml:space="preserve">
|
||||
<value>Songs</value>
|
||||
</data>
|
||||
<data name="dani dojo" xml:space="preserve">
|
||||
<value>Dani Dojo</value>
|
||||
<data name="High Scores" xml:space="preserve">
|
||||
<value>High Scores</value>
|
||||
</data>
|
||||
<data name="Show QR Code" xml:space="preserve">
|
||||
<value>Show QR Code</value>
|
||||
</data>
|
||||
<data name="Manage Access Codes" xml:space="preserve">
|
||||
<data name="Access Codes" xml:space="preserve">
|
||||
<value>Manage Access Codes</value>
|
||||
</data>
|
||||
<data name="Change Password" xml:space="preserve">
|
||||
@ -156,7 +153,7 @@
|
||||
<data name="Welcome to TaikoWebUI!" xml:space="preserve">
|
||||
<value>Welcome to TaikoWebUI!</value>
|
||||
</data>
|
||||
<data name="Song" xml:space="preserve">
|
||||
<data name="Song Name" xml:space="preserve">
|
||||
<value>Song</value>
|
||||
</data>
|
||||
<data name="Level" xml:space="preserve">
|
||||
@ -207,7 +204,7 @@
|
||||
<data name="Total Donderful Combos" xml:space="preserve">
|
||||
<value>Total Donderful Combos</value>
|
||||
</data>
|
||||
<data name="Key_01" xml:space="preserve">
|
||||
<data name="Song List" xml:space="preserve">
|
||||
<value>Songs</value>
|
||||
</data>
|
||||
<data name="Hide" xml:space="preserve">
|
||||
@ -229,9 +226,9 @@
|
||||
<value>Crown</value>
|
||||
</data>
|
||||
<data name="No data." xml:space="preserve">
|
||||
<value>No data.</value>
|
||||
<value>No data</value>
|
||||
</data>
|
||||
<data name="Key_02" xml:space="preserve">
|
||||
<data name="Log In First" xml:space="preserve">
|
||||
<value>"Please log in by clicking on "Users" tab first.</value>
|
||||
</data>
|
||||
<data name="Total Hits" xml:space="preserve">
|
||||
@ -240,20 +237,20 @@
|
||||
<data name="Soul Gauge" xml:space="preserve">
|
||||
<value>Soul Gauge</value>
|
||||
</data>
|
||||
<data name="Songs" xml:space="preserve">
|
||||
<data name="Course Songs" xml:space="preserve">
|
||||
<value>Songs</value>
|
||||
</data>
|
||||
<data name="Conditions" xml:space="preserve">
|
||||
<value>Conditions</value>
|
||||
</data>
|
||||
<data name="Red" xml:space="preserve">
|
||||
<value>Red</value>
|
||||
<value>Red Clear</value>
|
||||
</data>
|
||||
<data name="Gold" xml:space="preserve">
|
||||
<value>Gold</value>
|
||||
</data>
|
||||
<data name="Failed" xml:space="preserve">
|
||||
<value>Failed</value>
|
||||
<data name="Not Cleared" xml:space="preserve">
|
||||
<value>Not Cleared</value>
|
||||
</data>
|
||||
<data name="Pass" xml:space="preserve">
|
||||
<value>Pass</value>
|
||||
@ -267,7 +264,7 @@
|
||||
<data name="Stage" xml:space="preserve">
|
||||
<value>Stage</value>
|
||||
</data>
|
||||
<data name="Key_03" xml:space="preserve">
|
||||
<data name="Dani Dojo" xml:space="preserve">
|
||||
<value>Dani Dojo</value>
|
||||
</data>
|
||||
<data name="Profile" xml:space="preserve">
|
||||
@ -384,4 +381,199 @@
|
||||
<data name="DateFormat" xml:space="preserve">
|
||||
<value>MM/dd/yyyy h:mm:ss tt</value>
|
||||
</data>
|
||||
<data name="Generate Invite Code" xml:space="preserve">
|
||||
<value>Generate Invite Code</value>
|
||||
</data>
|
||||
<data name="Register" xml:space="preserve">
|
||||
<value>Register</value>
|
||||
</data>
|
||||
<data name="Log In" xml:space="preserve">
|
||||
<value>Log In</value>
|
||||
</data>
|
||||
<data name="Log Out" xml:space="preserve">
|
||||
<value>Log Out</value>
|
||||
</data>
|
||||
<data name="Play Data" xml:space="preserve">
|
||||
<value>Play Data</value>
|
||||
</data>
|
||||
<data name="Add Access Code" xml:space="preserve">
|
||||
<value>Add Access Code</value>
|
||||
</data>
|
||||
<data name="New Access Code" xml:space="preserve">
|
||||
<value>New Access Code</value>
|
||||
</data>
|
||||
<data name="Delete" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="Access Code" xml:space="preserve">
|
||||
<value>Access Code</value>
|
||||
</data>
|
||||
<data name="Old Password" xml:space="preserve">
|
||||
<value>Old Password</value>
|
||||
</data>
|
||||
<data name="New Password" xml:space="preserve">
|
||||
<value>New Password</value>
|
||||
</data>
|
||||
<data name="Confirm New Password" xml:space="preserve">
|
||||
<value>Confirm New Password</value>
|
||||
</data>
|
||||
<data name="Dialog OK" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="QR Code" xml:space="preserve">
|
||||
<value>QR Code</value>
|
||||
</data>
|
||||
<data name="Chojin" xml:space="preserve">
|
||||
<value>Chojin</value>
|
||||
</data>
|
||||
<data name="Eighth Dan" xml:space="preserve">
|
||||
<value>Eighth Dan</value>
|
||||
</data>
|
||||
<data name="Fifth Dan" xml:space="preserve">
|
||||
<value>5th Dan</value>
|
||||
</data>
|
||||
<data name="Fifth Kyuu" xml:space="preserve">
|
||||
<value>5th Kyuu</value>
|
||||
</data>
|
||||
<data name="First Dan" xml:space="preserve">
|
||||
<value>1st Dan</value>
|
||||
</data>
|
||||
<data name="First Kyuu" xml:space="preserve">
|
||||
<value>1st Kyuu</value>
|
||||
</data>
|
||||
<data name="Fourth Dan" xml:space="preserve">
|
||||
<value>4th Dan</value>
|
||||
</data>
|
||||
<data name="Fourth Kyuu" xml:space="preserve">
|
||||
<value>4th Kyuu</value>
|
||||
</data>
|
||||
<data name="Gaiden" xml:space="preserve">
|
||||
<value>Gaiden</value>
|
||||
</data>
|
||||
<data name="Kuroto" xml:space="preserve">
|
||||
<value>Kuroto</value>
|
||||
</data>
|
||||
<data name="Meijin" xml:space="preserve">
|
||||
<value>Meijin</value>
|
||||
</data>
|
||||
<data name="Ninth Dan" xml:space="preserve">
|
||||
<value>9th Dan</value>
|
||||
</data>
|
||||
<data name="Second Dan" xml:space="preserve">
|
||||
<value>2nd Dan</value>
|
||||
</data>
|
||||
<data name="Second Kyuu" xml:space="preserve">
|
||||
<value>2nd Kyuu</value>
|
||||
</data>
|
||||
<data name="Seventh Dan" xml:space="preserve">
|
||||
<value>7th Dan</value>
|
||||
</data>
|
||||
<data name="Sixth Dan" xml:space="preserve">
|
||||
<value>6th Dan</value>
|
||||
</data>
|
||||
<data name="Tatsujin" xml:space="preserve">
|
||||
<value>Tatsujin</value>
|
||||
</data>
|
||||
<data name="Tenth Dan" xml:space="preserve">
|
||||
<value>10th Dan</value>
|
||||
</data>
|
||||
<data name="Third Dan" xml:space="preserve">
|
||||
<value>3rd Dan</value>
|
||||
</data>
|
||||
<data name="Third Kyuu" xml:space="preserve">
|
||||
<value>3rd Kyuu</value>
|
||||
</data>
|
||||
<data name="Gold Full Combo" xml:space="preserve">
|
||||
<value>Gold Full Combo</value>
|
||||
</data>
|
||||
<data name="Red Donderful Combo" xml:space="preserve">
|
||||
<value>Red Donderful Combo</value>
|
||||
</data>
|
||||
<data name="Red Full Combo" xml:space="preserve">
|
||||
<value>Red Full Combo</value>
|
||||
</data>
|
||||
<data name="Gold Donderful Combo" xml:space="preserve">
|
||||
<value>Gold Donderful Combo</value>
|
||||
</data>
|
||||
<data name="Song Title / Artist" xml:space="preserve">
|
||||
<value>Song Title / Artist</value>
|
||||
</data>
|
||||
<data name="Search by Title or Artist" xml:space="preserve">
|
||||
<value>Search by Title or Artist</value>
|
||||
</data>
|
||||
<data name="Filter by Genre" xml:space="preserve">
|
||||
<value>Filter by Genre</value>
|
||||
</data>
|
||||
<data name="Play History" xml:space="preserve">
|
||||
<value>Play History</value>
|
||||
</data>
|
||||
<data name="No Play History Found" xml:space="preserve">
|
||||
<value>No play history found</value>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Play Time" xml:space="preserve">
|
||||
<value>Play Time</value>
|
||||
</data>
|
||||
<data name="Rank" xml:space="preserve">
|
||||
<value>Rank</value>
|
||||
</data>
|
||||
<data name="Difficulty" xml:space="preserve">
|
||||
<value>Difficulty</value>
|
||||
</data>
|
||||
<data name="Song Number" xml:space="preserve">
|
||||
<value>Song Number</value>
|
||||
</data>
|
||||
<data name="Search by Title, Artist or Date" xml:space="preserve">
|
||||
<value>Search by Title, Artist or Date</value>
|
||||
</data>
|
||||
<data name="Unregister" xml:space="preserve">
|
||||
<value>Unregister</value>
|
||||
</data>
|
||||
<data name="and" xml:space="preserve">
|
||||
<value>and</value>
|
||||
</data>
|
||||
<data name="other access code(s)" xml:space="preserve">
|
||||
<value>other Access Code(s)</value>
|
||||
</data>
|
||||
<data name="Copy to Clipboard" xml:space="preserve">
|
||||
<value>Copy to Clipboard</value>
|
||||
</data>
|
||||
<data name="Invite Code" xml:space="preserve">
|
||||
<value>Invite Code</value>
|
||||
</data>
|
||||
<data name="Error" xml:space="preserve">
|
||||
<value>Error</value>
|
||||
</data>
|
||||
<data name="Access Code is Required" xml:space="preserve">
|
||||
<value>Access Code is required</value>
|
||||
</data>
|
||||
<data name=""Invite Code (Optional)"" xml:space="preserve">
|
||||
<value>"Invite Code (Optional)"</value>
|
||||
</data>
|
||||
<data name="Last Play Date" xml:space="preserve">
|
||||
<value>Last Play Date</value>
|
||||
</data>
|
||||
<data name="Last Play Time(5 Min Around Credit End)" xml:space="preserve">
|
||||
<value>Last Play Time(5 Min Around Credit End)</value>
|
||||
</data>
|
||||
<data name="Password is Required" xml:space="preserve">
|
||||
<value>Password is required</value>
|
||||
</data>
|
||||
<data name="Confirm Password" xml:space="preserve">
|
||||
<value>Confirm Password</value>
|
||||
</data>
|
||||
<data name="Confirm Password is Required" xml:space="preserve">
|
||||
<value>Confirm password is required</value>
|
||||
</data>
|
||||
<data name="Unknown Error" xml:space="preserve">
|
||||
<value>Unknown Error</value>
|
||||
</data>
|
||||
<data name="Success" xml:space="preserve">
|
||||
<value>Success</value>
|
||||
</data>
|
||||
</root>
|
@ -117,31 +117,28 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="dashboard" xml:space="preserve">
|
||||
<data name="Dashboard" xml:space="preserve">
|
||||
<value>メニュー</value>
|
||||
</data>
|
||||
<data name="users" xml:space="preserve">
|
||||
<data name="Users" xml:space="preserve">
|
||||
<value>ユーザー管理</value>
|
||||
</data>
|
||||
<data name="edit profile" xml:space="preserve">
|
||||
<value>プロフィール編集</value>
|
||||
</data>
|
||||
<data name="user" xml:space="preserve">
|
||||
<data name="User" xml:space="preserve">
|
||||
<value>ユーザー</value>
|
||||
</data>
|
||||
<data name="view play data" xml:space="preserve">
|
||||
<data name="View Play Data" xml:space="preserve">
|
||||
<value>プレイデータ</value>
|
||||
</data>
|
||||
<data name="high scores" xml:space="preserve">
|
||||
<value>演奏ゲーム</value>
|
||||
</data>
|
||||
<data name="dani dojo" xml:space="preserve">
|
||||
<value>段位道場</value>
|
||||
<data name="High Scores" xml:space="preserve">
|
||||
<value>自己ベスト</value>
|
||||
</data>
|
||||
<data name="Show QR Code" xml:space="preserve">
|
||||
<value>QRコード</value>
|
||||
</data>
|
||||
<data name="Manage Access Codes" xml:space="preserve">
|
||||
<data name="Access Codes" xml:space="preserve">
|
||||
<value>アクセスコード管理</value>
|
||||
</data>
|
||||
<data name="Change Password" xml:space="preserve">
|
||||
@ -156,7 +153,7 @@
|
||||
<data name="Welcome to TaikoWebUI!" xml:space="preserve">
|
||||
<value>TaikoWebUIへようこそ!</value>
|
||||
</data>
|
||||
<data name="Song" xml:space="preserve">
|
||||
<data name="Song Name" xml:space="preserve">
|
||||
<value>曲名</value>
|
||||
</data>
|
||||
<data name="Level" xml:space="preserve">
|
||||
@ -207,8 +204,8 @@
|
||||
<data name="Total Donderful Combos" xml:space="preserve">
|
||||
<value>ドンダフルコンボ回数</value>
|
||||
</data>
|
||||
<data name="Key_01" xml:space="preserve">
|
||||
<value>自己ベスト</value>
|
||||
<data name="Song List" xml:space="preserve">
|
||||
<value>曲目リスト</value>
|
||||
</data>
|
||||
<data name="Hide" xml:space="preserve">
|
||||
<value>隠す</value>
|
||||
@ -229,9 +226,9 @@
|
||||
<value>王冠</value>
|
||||
</data>
|
||||
<data name="No data." xml:space="preserve">
|
||||
<value>データがありません。</value>
|
||||
<value>データがありません</value>
|
||||
</data>
|
||||
<data name="Key_02" xml:space="preserve">
|
||||
<data name="Log In First" xml:space="preserve">
|
||||
<value>"ユーザー管理"タブでログインしてください。</value>
|
||||
</data>
|
||||
<data name="Total Hits" xml:space="preserve">
|
||||
@ -240,7 +237,7 @@
|
||||
<data name="Soul Gauge" xml:space="preserve">
|
||||
<value>魂ゲージ</value>
|
||||
</data>
|
||||
<data name="Songs" xml:space="preserve">
|
||||
<data name="Course Songs" xml:space="preserve">
|
||||
<value>課題曲</value>
|
||||
</data>
|
||||
<data name="Conditions" xml:space="preserve">
|
||||
@ -252,8 +249,8 @@
|
||||
<data name="Gold" xml:space="preserve">
|
||||
<value>金合格</value>
|
||||
</data>
|
||||
<data name="Failed" xml:space="preserve">
|
||||
<value>不合格</value>
|
||||
<data name="Not Cleared" xml:space="preserve">
|
||||
<value>未合格</value>
|
||||
</data>
|
||||
<data name="Pass" xml:space="preserve">
|
||||
<value>合格</value>
|
||||
@ -267,7 +264,7 @@
|
||||
<data name="Stage" xml:space="preserve">
|
||||
<value>曲目</value>
|
||||
</data>
|
||||
<data name="Key_03" xml:space="preserve">
|
||||
<data name="Dani Dojo" xml:space="preserve">
|
||||
<value>段位道場</value>
|
||||
</data>
|
||||
<data name="Profile" xml:space="preserve">
|
||||
@ -378,4 +375,205 @@
|
||||
<data name="DateFormat" xml:space="preserve">
|
||||
<value>yyyy/MM/dd HH:mm:ss</value>
|
||||
</data>
|
||||
<data name="Generate Invite Code" xml:space="preserve">
|
||||
<value>招待コード生成</value>
|
||||
</data>
|
||||
<data name="Register" xml:space="preserve">
|
||||
<value>登録</value>
|
||||
</data>
|
||||
<data name="reset_password_confirm_dialog_1" xml:space="preserve">
|
||||
<value>本当にこのユーザーのパスワードをリセットしますか?</value>
|
||||
</data>
|
||||
<data name="reset_password_confirm_dialog_2" xml:space="preserve">
|
||||
<value>これにより、ユーザーの現在のパスワードは削除され、ユーザーは再度登録する必要があります。</value>
|
||||
</data>
|
||||
<data name="Log In" xml:space="preserve">
|
||||
<value>ログイン</value>
|
||||
</data>
|
||||
<data name="Log Out" xml:space="preserve">
|
||||
<value>ログアウト</value>
|
||||
</data>
|
||||
<data name="Play Data" xml:space="preserve">
|
||||
<value>プレイデータ</value>
|
||||
</data>
|
||||
<data name="Add Access Code" xml:space="preserve">
|
||||
<value>アクセスコード追加</value>
|
||||
</data>
|
||||
<data name="New Access Code" xml:space="preserve">
|
||||
<value>新しいアクセスコード</value>
|
||||
</data>
|
||||
<data name="Delete" xml:space="preserve">
|
||||
<value>削除</value>
|
||||
</data>
|
||||
<data name="Access Code" xml:space="preserve">
|
||||
<value>アクセスコード</value>
|
||||
</data>
|
||||
<data name="Old Password" xml:space="preserve">
|
||||
<value>旧パスワード</value>
|
||||
</data>
|
||||
<data name="New Password" xml:space="preserve">
|
||||
<value>新しいパスワード</value>
|
||||
</data>
|
||||
<data name="Confirm New Password" xml:space="preserve">
|
||||
<value>パスワードの再入力</value>
|
||||
</data>
|
||||
<data name="Dialog OK" xml:space="preserve">
|
||||
<value>確認</value>
|
||||
</data>
|
||||
<data name="QR Code" xml:space="preserve">
|
||||
<value>QRコード</value>
|
||||
</data>
|
||||
<data name="Chojin" xml:space="preserve">
|
||||
<value>超人</value>
|
||||
</data>
|
||||
<data name="Eighth Dan" xml:space="preserve">
|
||||
<value>八段</value>
|
||||
</data>
|
||||
<data name="Fifth Dan" xml:space="preserve">
|
||||
<value>五段</value>
|
||||
</data>
|
||||
<data name="Fifth Kyuu" xml:space="preserve">
|
||||
<value>五級</value>
|
||||
</data>
|
||||
<data name="First Dan" xml:space="preserve">
|
||||
<value>一段</value>
|
||||
</data>
|
||||
<data name="First Kyuu" xml:space="preserve">
|
||||
<value>一級</value>
|
||||
</data>
|
||||
<data name="Fourth Dan" xml:space="preserve">
|
||||
<value>四段</value>
|
||||
</data>
|
||||
<data name="Fourth Kyuu" xml:space="preserve">
|
||||
<value>四級</value>
|
||||
</data>
|
||||
<data name="Gaiden" xml:space="preserve">
|
||||
<value>外伝</value>
|
||||
</data>
|
||||
<data name="Kuroto" xml:space="preserve">
|
||||
<value>玄人</value>
|
||||
</data>
|
||||
<data name="Meijin" xml:space="preserve">
|
||||
<value>名人</value>
|
||||
</data>
|
||||
<data name="Ninth Dan" xml:space="preserve">
|
||||
<value>九段</value>
|
||||
</data>
|
||||
<data name="Second Dan" xml:space="preserve">
|
||||
<value>二段</value>
|
||||
</data>
|
||||
<data name="Second Kyuu" xml:space="preserve">
|
||||
<value>二級</value>
|
||||
</data>
|
||||
<data name="Seventh Dan" xml:space="preserve">
|
||||
<value>七段</value>
|
||||
</data>
|
||||
<data name="Sixth Dan" xml:space="preserve">
|
||||
<value>六段</value>
|
||||
</data>
|
||||
<data name="Tatsujin" xml:space="preserve">
|
||||
<value>達人</value>
|
||||
</data>
|
||||
<data name="Tenth Dan" xml:space="preserve">
|
||||
<value>十段</value>
|
||||
</data>
|
||||
<data name="Third Dan" xml:space="preserve">
|
||||
<value>三段</value>
|
||||
</data>
|
||||
<data name="Third Kyuu" xml:space="preserve">
|
||||
<value>三級</value>
|
||||
</data>
|
||||
<data name="Gold Full Combo" xml:space="preserve">
|
||||
<value>金金合格</value>
|
||||
</data>
|
||||
<data name="Red Donderful Combo" xml:space="preserve">
|
||||
<value>虹赤合格</value>
|
||||
</data>
|
||||
<data name="Red Full Combo" xml:space="preserve">
|
||||
<value>金赤合格</value>
|
||||
</data>
|
||||
<data name="Gold Donderful Combo" xml:space="preserve">
|
||||
<value>虹金合格</value>
|
||||
</data>
|
||||
<data name="Song Title / Artist" xml:space="preserve">
|
||||
<value>曲名 / Artist</value>
|
||||
</data>
|
||||
<data name="Search by Title or Artist" xml:space="preserve">
|
||||
<value>曲名・アーティスト名で検索</value>
|
||||
</data>
|
||||
<data name="Filter by Genre" xml:space="preserve">
|
||||
<value>ジャンル検索</value>
|
||||
</data>
|
||||
<data name="Play History" xml:space="preserve">
|
||||
<value>プレー履歴</value>
|
||||
</data>
|
||||
<data name="No Play History Found" xml:space="preserve">
|
||||
<value>プレー履歴なし</value>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>パスワード</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>設定</value>
|
||||
</data>
|
||||
<data name="Play Time" xml:space="preserve">
|
||||
<value>プレー時間</value>
|
||||
</data>
|
||||
<data name="Rank" xml:space="preserve">
|
||||
<value>ランク</value>
|
||||
</data>
|
||||
<data name="Difficulty" xml:space="preserve">
|
||||
<value>難易度</value>
|
||||
</data>
|
||||
<data name="Song Number" xml:space="preserve">
|
||||
<value>曲数</value>
|
||||
</data>
|
||||
<data name="Search by Title, Artist or Date" xml:space="preserve">
|
||||
<value>曲名・アーティスト名・日付で検索</value>
|
||||
</data>
|
||||
<data name="Unregister" xml:space="preserve">
|
||||
<value>登録解除</value>
|
||||
</data>
|
||||
<data name="and" xml:space="preserve">
|
||||
<value>と</value>
|
||||
</data>
|
||||
<data name="other access code(s)" xml:space="preserve">
|
||||
<value>他のアクセスコード</value>
|
||||
</data>
|
||||
<data name="Copy to Clipboard" xml:space="preserve">
|
||||
<value>クリップボードにコピー</value>
|
||||
</data>
|
||||
<data name="Invite Code" xml:space="preserve">
|
||||
<value>招待コード</value>
|
||||
</data>
|
||||
<data name="Error" xml:space="preserve">
|
||||
<value>エラー</value>
|
||||
</data>
|
||||
<data name="Access Code is Required" xml:space="preserve">
|
||||
<value>アクセスコードが必要です</value>
|
||||
</data>
|
||||
<data name=""Invite Code (Optional)"" xml:space="preserve">
|
||||
<value>招待コード(任意)</value>
|
||||
</data>
|
||||
<data name="Last Play Date" xml:space="preserve">
|
||||
<value>前回プレイデート</value>
|
||||
</data>
|
||||
<data name="Last Play Time(5 Min Around Credit End)" xml:space="preserve">
|
||||
<value>前回プレー時間(クレジット終了5分以内)</value>
|
||||
</data>
|
||||
<data name="Password is Required" xml:space="preserve">
|
||||
<value>パスワードが必要です</value>
|
||||
</data>
|
||||
<data name="Confirm Password" xml:space="preserve">
|
||||
<value>パスワードの再入力</value>
|
||||
</data>
|
||||
<data name="Confirm Password is Required" xml:space="preserve">
|
||||
<value>アクセスコードの再入力が必要です</value>
|
||||
</data>
|
||||
<data name="Unknown Error" xml:space="preserve">
|
||||
<value>未知のエラー</value>
|
||||
</data>
|
||||
<data name="Success" xml:space="preserve">
|
||||
<value>成功</value>
|
||||
</data>
|
||||
</root>
|
@ -120,4 +120,253 @@
|
||||
<data name="DateFormat" xml:space="preserve">
|
||||
<value>MM/dd/yyyy h:mm:ss tt</value>
|
||||
</data>
|
||||
<data name="Generate Invite Code" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Register" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Log In" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Achievement Panel" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Achievement Panel Difficulty" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="AI Battle Data" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Bad" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Best Crown" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Best Rank" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Log Out" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Play Data" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="High Scores" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Access Codes" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Add Access Code" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="New Access Code" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Delete" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Access Code" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Old Password" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="New Password" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Confirm New Password" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Dialog OK" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="QR Code" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Fifth Kyuu" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Fourth Kyuu" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Third Kyuu" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Second Kyuu" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="First Kyuu" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="First Dan" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Second Dan" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Third Dan" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Fourth Dan" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Fifth Dan" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Sixth Dan" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Seventh Dan" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Eighth Dan" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Ninth Dan" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Tenth Dan" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Kuroto" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Meijin" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Chojin" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Tatsujin" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Gaiden" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Gold Full Combo" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Red Full Combo" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Red Donderful Combo" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Gold Donderful Combo" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Song List" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Log In First" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Dani Dojo" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Course Songs" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Song Name" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Song Title / Artist" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Search by Title or Artist" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Filter by Genre" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Play History" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="No Play History Found" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Play Time" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Rank" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Difficulty" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Song Number" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Search by Title, Artist or Date" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Users" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Dashboard" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Unregister" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="and" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="other access code(s)" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Copy to Clipboard" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Invite Code" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Error" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="View Play Data" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Not Cleared" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="User" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Access Code is Required" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name=""Invite Code (Optional)"" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Last Play Date" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Last Play Time(5 Min Around Credit End)" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Password is Required" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Confirm Password" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Confirm Password is Required" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Unknown Error" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Success" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
</root>
|
@ -117,31 +117,28 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="dashboard" xml:space="preserve">
|
||||
<data name="Dashboard" xml:space="preserve">
|
||||
<value>主页</value>
|
||||
</data>
|
||||
<data name="users" xml:space="preserve">
|
||||
<data name="Users" xml:space="preserve">
|
||||
<value>用户管理</value>
|
||||
</data>
|
||||
<data name="edit profile" xml:space="preserve">
|
||||
<value>编辑档案</value>
|
||||
</data>
|
||||
<data name="user" xml:space="preserve">
|
||||
<data name="User" xml:space="preserve">
|
||||
<value>用户</value>
|
||||
</data>
|
||||
<data name="view play data" xml:space="preserve">
|
||||
<data name="View Play Data" xml:space="preserve">
|
||||
<value>查看记录</value>
|
||||
</data>
|
||||
<data name="high scores" xml:space="preserve">
|
||||
<value>演奏模式</value>
|
||||
</data>
|
||||
<data name="dani dojo" xml:space="preserve">
|
||||
<value>段位道场</value>
|
||||
<data name="High Scores" xml:space="preserve">
|
||||
<value>最高分</value>
|
||||
</data>
|
||||
<data name="Show QR Code" xml:space="preserve">
|
||||
<value>查看二维码</value>
|
||||
</data>
|
||||
<data name="Manage Access Codes" xml:space="preserve">
|
||||
<data name="Access Codes" xml:space="preserve">
|
||||
<value>管理访问码</value>
|
||||
</data>
|
||||
<data name="Change Password" xml:space="preserve">
|
||||
@ -156,7 +153,7 @@
|
||||
<data name="Welcome to TaikoWebUI!" xml:space="preserve">
|
||||
<value>欢迎来到TaikoWebUI!</value>
|
||||
</data>
|
||||
<data name="Song" xml:space="preserve">
|
||||
<data name="Song Name" xml:space="preserve">
|
||||
<value>曲名</value>
|
||||
</data>
|
||||
<data name="Level" xml:space="preserve">
|
||||
@ -207,8 +204,8 @@
|
||||
<data name="Total Donderful Combos" xml:space="preserve">
|
||||
<value>总完美连段次数</value>
|
||||
</data>
|
||||
<data name="Key_01" xml:space="preserve">
|
||||
<value>最佳得分</value>
|
||||
<data name="Song List" xml:space="preserve">
|
||||
<value>曲目列表</value>
|
||||
</data>
|
||||
<data name="Hide" xml:space="preserve">
|
||||
<value>隐藏</value>
|
||||
@ -229,18 +226,18 @@
|
||||
<value>王冠</value>
|
||||
</data>
|
||||
<data name="No data." xml:space="preserve">
|
||||
<value>没有数据.</value>
|
||||
<value>没有数据</value>
|
||||
</data>
|
||||
<data name="Key_02" xml:space="preserve">
|
||||
<data name="Log In First" xml:space="preserve">
|
||||
<value>"请先在用户管理那边登录</value>
|
||||
</data>
|
||||
<data name="Total Hits" xml:space="preserve">
|
||||
<value>"总打击次数</value>
|
||||
<value>总打击次数</value>
|
||||
</data>
|
||||
<data name="Soul Gauge" xml:space="preserve">
|
||||
<value>魂条</value>
|
||||
</data>
|
||||
<data name="Songs" xml:space="preserve">
|
||||
<data name="Course Songs" xml:space="preserve">
|
||||
<value>课题曲</value>
|
||||
</data>
|
||||
<data name="Conditions" xml:space="preserve">
|
||||
@ -252,8 +249,8 @@
|
||||
<data name="Gold" xml:space="preserve">
|
||||
<value>金合格</value>
|
||||
</data>
|
||||
<data name="Failed" xml:space="preserve">
|
||||
<value>不合格</value>
|
||||
<data name="Not Cleared" xml:space="preserve">
|
||||
<value>未合格</value>
|
||||
</data>
|
||||
<data name="Pass" xml:space="preserve">
|
||||
<value>合格</value>
|
||||
@ -267,7 +264,7 @@
|
||||
<data name="Stage" xml:space="preserve">
|
||||
<value>曲目</value>
|
||||
</data>
|
||||
<data name="Key_03" xml:space="preserve">
|
||||
<data name="Dani Dojo" xml:space="preserve">
|
||||
<value>段位道场</value>
|
||||
</data>
|
||||
<data name="Profile" xml:space="preserve">
|
||||
@ -378,4 +375,202 @@
|
||||
<data name="DateFormat" xml:space="preserve">
|
||||
<value>yyyy/M/d HH:mm:ss</value>
|
||||
</data>
|
||||
<data name="Generate Invite Code" xml:space="preserve">
|
||||
<value>生成邀请码</value>
|
||||
</data>
|
||||
<data name="Register" xml:space="preserve">
|
||||
<value>注册</value>
|
||||
</data>
|
||||
<data name="reset_password_confirm_dialog_1" xml:space="preserve">
|
||||
<value>确定要为这位用户重置密码吗?</value>
|
||||
</data>
|
||||
<data name="reset_password_confirm_dialog_2" xml:space="preserve">
|
||||
<value>重置密码后,用户需要再次注册</value>
|
||||
</data>
|
||||
<data name="Log In" xml:space="preserve">
|
||||
<value>登录</value>
|
||||
</data>
|
||||
<data name="Log Out" xml:space="preserve">
|
||||
<value>登出</value>
|
||||
</data>
|
||||
<data name="Play Data" xml:space="preserve">
|
||||
<value>游玩数据</value>
|
||||
</data>
|
||||
<data name="Add Access Code" xml:space="preserve">
|
||||
<value>新增访问码</value>
|
||||
</data>
|
||||
<data name="New Access Code" xml:space="preserve">
|
||||
<value>新访问码</value>
|
||||
</data>
|
||||
<data name="Delete" xml:space="preserve">
|
||||
<value>删除</value>
|
||||
</data>
|
||||
<data name="Access Code" xml:space="preserve">
|
||||
<value>访问码</value>
|
||||
</data>
|
||||
<data name="Old Password" xml:space="preserve">
|
||||
<value>现有密码</value>
|
||||
</data>
|
||||
<data name="New Password" xml:space="preserve">
|
||||
<value>新密码</value>
|
||||
</data>
|
||||
<data name="Confirm New Password" xml:space="preserve">
|
||||
<value>再次输入新密码</value>
|
||||
</data>
|
||||
<data name="Dialog OK" xml:space="preserve">
|
||||
<value>确定</value>
|
||||
</data>
|
||||
<data name="QR Code" xml:space="preserve">
|
||||
<value>二维码</value>
|
||||
</data>
|
||||
<data name="Chojin" xml:space="preserve">
|
||||
<value>超人</value>
|
||||
</data>
|
||||
<data name="Eighth Dan" xml:space="preserve">
|
||||
<value>八段</value>
|
||||
</data>
|
||||
<data name="Fifth Dan" xml:space="preserve">
|
||||
<value>五段</value>
|
||||
</data>
|
||||
<data name="Fifth Kyuu" xml:space="preserve">
|
||||
<value>五级</value>
|
||||
</data>
|
||||
<data name="First Dan" xml:space="preserve">
|
||||
<value>一段</value>
|
||||
</data>
|
||||
<data name="First Kyuu" xml:space="preserve">
|
||||
<value>一级</value>
|
||||
</data>
|
||||
<data name="Fourth Dan" xml:space="preserve">
|
||||
<value>四段</value>
|
||||
</data>
|
||||
<data name="Fourth Kyuu" xml:space="preserve">
|
||||
<value>四级</value>
|
||||
</data>
|
||||
<data name="Gaiden" xml:space="preserve">
|
||||
<value>外传</value>
|
||||
</data>
|
||||
<data name="Kuroto" xml:space="preserve">
|
||||
<value>玄人</value>
|
||||
</data>
|
||||
<data name="Meijin" xml:space="preserve">
|
||||
<value>名人</value>
|
||||
</data>
|
||||
<data name="Ninth Dan" xml:space="preserve">
|
||||
<value>九段</value>
|
||||
</data>
|
||||
<data name="Second Dan" xml:space="preserve">
|
||||
<value>二段</value>
|
||||
</data>
|
||||
<data name="Second Kyuu" xml:space="preserve">
|
||||
<value>二级</value>
|
||||
</data>
|
||||
<data name="Seventh Dan" xml:space="preserve">
|
||||
<value>七段</value>
|
||||
</data>
|
||||
<data name="Sixth Dan" xml:space="preserve">
|
||||
<value>六段</value>
|
||||
</data>
|
||||
<data name="Tatsujin" xml:space="preserve">
|
||||
<value>达人</value>
|
||||
</data>
|
||||
<data name="Tenth Dan" xml:space="preserve">
|
||||
<value>十段</value>
|
||||
</data>
|
||||
<data name="Third Dan" xml:space="preserve">
|
||||
<value>三段</value>
|
||||
</data>
|
||||
<data name="Third Kyuu" xml:space="preserve">
|
||||
<value>三级</value>
|
||||
</data>
|
||||
<data name="Gold Full Combo" xml:space="preserve">
|
||||
<value>金金合格</value>
|
||||
</data>
|
||||
<data name="Red Donderful Combo" xml:space="preserve">
|
||||
<value>虹赤合格</value>
|
||||
</data>
|
||||
<data name="Red Full Combo" xml:space="preserve">
|
||||
<value>金赤合格</value>
|
||||
</data>
|
||||
<data name="Gold Donderful Combo" xml:space="preserve">
|
||||
<value>虹金合格</value>
|
||||
</data>
|
||||
<data name="Song Title / Artist" xml:space="preserve">
|
||||
<value>曲名 / Artist</value>
|
||||
</data>
|
||||
<data name="Search by Title or Artist" xml:space="preserve">
|
||||
<value>曲名/Artist名搜索</value>
|
||||
</data>
|
||||
<data name="Filter by Genre" xml:space="preserve">
|
||||
<value>分类过滤</value>
|
||||
</data>
|
||||
<data name="Play History" xml:space="preserve">
|
||||
<value>游玩历史</value>
|
||||
</data>
|
||||
<data name="No Play History Found" xml:space="preserve">
|
||||
<value>沒有游玩历史</value>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>密码</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>设定</value>
|
||||
</data>
|
||||
<data name="Play Time" xml:space="preserve">
|
||||
<value>游玩时间</value>
|
||||
</data>
|
||||
<data name="Rank" xml:space="preserve">
|
||||
<value>评价</value>
|
||||
</data>
|
||||
<data name="Difficulty" xml:space="preserve">
|
||||
<value>难度</value>
|
||||
</data>
|
||||
<data name="Song Number" xml:space="preserve">
|
||||
<value>曲数</value>
|
||||
</data>
|
||||
<data name="Search by Title, Artist or Date" xml:space="preserve">
|
||||
<value>曲名/Artist名/日期搜索</value>
|
||||
</data>
|
||||
<data name="Unregister" xml:space="preserve">
|
||||
<value>注销账号</value>
|
||||
</data>
|
||||
<data name="and" xml:space="preserve">
|
||||
<value>和</value>
|
||||
</data>
|
||||
<data name="other access code(s)" xml:space="preserve">
|
||||
<value>个其他访问码</value>
|
||||
</data>
|
||||
<data name="Copy to Clipboard" xml:space="preserve">
|
||||
<value>复制到粘贴板</value>
|
||||
</data>
|
||||
<data name="Invite Code" xml:space="preserve">
|
||||
<value>邀请码</value>
|
||||
</data>
|
||||
<data name="Error" xml:space="preserve">
|
||||
<value>错误</value>
|
||||
</data>
|
||||
<data name="Access Code is Required" xml:space="preserve">
|
||||
<value>访问码为必填项</value>
|
||||
</data>
|
||||
<data name=""Invite Code (Optional)"" xml:space="preserve">
|
||||
<value>邀请码(可选)</value>
|
||||
</data>
|
||||
<data name="Last Play Time(5 Min Around Credit End)" xml:space="preserve">
|
||||
<value>最后游玩时间(游戏结束5分钟内)</value>
|
||||
</data>
|
||||
<data name="Password is Required" xml:space="preserve">
|
||||
<value>密码为必填项</value>
|
||||
</data>
|
||||
<data name="Confirm Password" xml:space="preserve">
|
||||
<value>再次输入密码</value>
|
||||
</data>
|
||||
<data name="Confirm Password is Required" xml:space="preserve">
|
||||
<value>再次输入密码为必填项</value>
|
||||
</data>
|
||||
<data name="Unknown Error" xml:space="preserve">
|
||||
<value>不明错误</value>
|
||||
</data>
|
||||
<data name="Success" xml:space="preserve">
|
||||
<value>成功</value>
|
||||
</data>
|
||||
</root>
|
@ -117,32 +117,29 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="dashboard" xml:space="preserve">
|
||||
<data name="Dashboard" xml:space="preserve">
|
||||
<value>首頁</value>
|
||||
</data>
|
||||
<data name="users" xml:space="preserve">
|
||||
<data name="Users" xml:space="preserve">
|
||||
<value>管理用戶</value>
|
||||
</data>
|
||||
<data name="edit profile" xml:space="preserve">
|
||||
<value>編輯檔案</value>
|
||||
</data>
|
||||
<data name="user" xml:space="preserve">
|
||||
<data name="User" xml:space="preserve">
|
||||
<value>用戶</value>
|
||||
</data>
|
||||
<data name="view play data" xml:space="preserve">
|
||||
<data name="View Play Data" xml:space="preserve">
|
||||
<value>查看記錄</value>
|
||||
</data>
|
||||
<data name="high scores" xml:space="preserve">
|
||||
<value>演奏模式</value>
|
||||
</data>
|
||||
<data name="dani dojo" xml:space="preserve">
|
||||
<value>段位道場</value>
|
||||
<data name="High Scores" xml:space="preserve">
|
||||
<value>最高分</value>
|
||||
</data>
|
||||
<data name="Show QR Code" xml:space="preserve">
|
||||
<value>查看QR Code</value>
|
||||
</data>
|
||||
<data name="Manage Access Codes" xml:space="preserve">
|
||||
<value>管理Access Codes</value>
|
||||
<data name="Access Codes" xml:space="preserve">
|
||||
<value>管理訪問碼</value>
|
||||
</data>
|
||||
<data name="Change Password" xml:space="preserve">
|
||||
<value>更改密碼</value>
|
||||
@ -156,7 +153,7 @@
|
||||
<data name="Welcome to TaikoWebUI!" xml:space="preserve">
|
||||
<value>歡迎來到TaikoWebUI!</value>
|
||||
</data>
|
||||
<data name="Song" xml:space="preserve">
|
||||
<data name="Song Name" xml:space="preserve">
|
||||
<value>曲名</value>
|
||||
</data>
|
||||
<data name="Level" xml:space="preserve">
|
||||
@ -207,8 +204,8 @@
|
||||
<data name="Total Donderful Combos" xml:space="preserve">
|
||||
<value>總全良次數</value>
|
||||
</data>
|
||||
<data name="Key_01" xml:space="preserve">
|
||||
<value>最佳得分</value>
|
||||
<data name="Song List" xml:space="preserve">
|
||||
<value>曲目列表</value>
|
||||
</data>
|
||||
<data name="Hide" xml:space="preserve">
|
||||
<value>隱藏</value>
|
||||
@ -229,18 +226,18 @@
|
||||
<value>皇冠</value>
|
||||
</data>
|
||||
<data name="No data." xml:space="preserve">
|
||||
<value>沒有數據.</value>
|
||||
<value>沒有數據</value>
|
||||
</data>
|
||||
<data name="Key_02" xml:space="preserve">
|
||||
<data name="Log In First" xml:space="preserve">
|
||||
<value>"請先在管理用戶那邊登入</value>
|
||||
</data>
|
||||
<data name="Total Hits" xml:space="preserve">
|
||||
<value>"總打擊次數</value>
|
||||
<value>總打擊次數</value>
|
||||
</data>
|
||||
<data name="Soul Gauge" xml:space="preserve">
|
||||
<value>魂條</value>
|
||||
</data>
|
||||
<data name="Songs" xml:space="preserve">
|
||||
<data name="Course Songs" xml:space="preserve">
|
||||
<value>課題曲</value>
|
||||
</data>
|
||||
<data name="Conditions" xml:space="preserve">
|
||||
@ -252,8 +249,8 @@
|
||||
<data name="Gold" xml:space="preserve">
|
||||
<value>金合格</value>
|
||||
</data>
|
||||
<data name="Failed" xml:space="preserve">
|
||||
<value>不合格</value>
|
||||
<data name="Not Cleared" xml:space="preserve">
|
||||
<value>未合格</value>
|
||||
</data>
|
||||
<data name="Pass" xml:space="preserve">
|
||||
<value>合格</value>
|
||||
@ -267,7 +264,7 @@
|
||||
<data name="Stage" xml:space="preserve">
|
||||
<value>曲目</value>
|
||||
</data>
|
||||
<data name="Key_03" xml:space="preserve">
|
||||
<data name="Dani Dojo" xml:space="preserve">
|
||||
<value>段位道埸</value>
|
||||
</data>
|
||||
<data name="Profile" xml:space="preserve">
|
||||
@ -378,4 +375,202 @@
|
||||
<data name="DateFormat" xml:space="preserve">
|
||||
<value>yyyy/M/d HH:mm:ss</value>
|
||||
</data>
|
||||
<data name="Generate Invite Code" xml:space="preserve">
|
||||
<value>生成邀請碼</value>
|
||||
</data>
|
||||
<data name="Register" xml:space="preserve">
|
||||
<value>注冊</value>
|
||||
</data>
|
||||
<data name="reset_password_confirm_dialog_1" xml:space="preserve">
|
||||
<value>確定要為這位用戶重置密碼嗎?</value>
|
||||
</data>
|
||||
<data name="reset_password_confirm_dialog_2" xml:space="preserve">
|
||||
<value>重置密碼后,用戶需要再次注冊</value>
|
||||
</data>
|
||||
<data name="Log In" xml:space="preserve">
|
||||
<value>登錄</value>
|
||||
</data>
|
||||
<data name="Log Out" xml:space="preserve">
|
||||
<value>登出</value>
|
||||
</data>
|
||||
<data name="Play Data" xml:space="preserve">
|
||||
<value>游玩數據</value>
|
||||
</data>
|
||||
<data name="Add Access Code" xml:space="preserve">
|
||||
<value>新增訪問碼</value>
|
||||
</data>
|
||||
<data name="New Access Code" xml:space="preserve">
|
||||
<value>新訪問碼</value>
|
||||
</data>
|
||||
<data name="Delete" xml:space="preserve">
|
||||
<value>删除</value>
|
||||
</data>
|
||||
<data name="Access Code" xml:space="preserve">
|
||||
<value>訪問碼</value>
|
||||
</data>
|
||||
<data name="Old Password" xml:space="preserve">
|
||||
<value>現有密碼</value>
|
||||
</data>
|
||||
<data name="New Password" xml:space="preserve">
|
||||
<value>新密碼</value>
|
||||
</data>
|
||||
<data name="Confirm New Password" xml:space="preserve">
|
||||
<value>再次輸入新密碼</value>
|
||||
</data>
|
||||
<data name="Dialog OK" xml:space="preserve">
|
||||
<value>確認</value>
|
||||
</data>
|
||||
<data name="QR Code" xml:space="preserve">
|
||||
<value>查看QR Code</value>
|
||||
</data>
|
||||
<data name="Chojin" xml:space="preserve">
|
||||
<value>超人</value>
|
||||
</data>
|
||||
<data name="Eighth Dan" xml:space="preserve">
|
||||
<value>八段</value>
|
||||
</data>
|
||||
<data name="Gaiden" xml:space="preserve">
|
||||
<value>外傳</value>
|
||||
</data>
|
||||
<data name="Fourth Kyuu" xml:space="preserve">
|
||||
<value>四級</value>
|
||||
</data>
|
||||
<data name="Fourth Dan" xml:space="preserve">
|
||||
<value>四段</value>
|
||||
</data>
|
||||
<data name="First Kyuu" xml:space="preserve">
|
||||
<value>一級</value>
|
||||
</data>
|
||||
<data name="First Dan" xml:space="preserve">
|
||||
<value>一段</value>
|
||||
</data>
|
||||
<data name="Fifth Kyuu" xml:space="preserve">
|
||||
<value>五級</value>
|
||||
</data>
|
||||
<data name="Fifth Dan" xml:space="preserve">
|
||||
<value>五段</value>
|
||||
</data>
|
||||
<data name="Kuroto" xml:space="preserve">
|
||||
<value>玄人</value>
|
||||
</data>
|
||||
<data name="Meijin" xml:space="preserve">
|
||||
<value>名人</value>
|
||||
</data>
|
||||
<data name="Ninth Dan" xml:space="preserve">
|
||||
<value>九段</value>
|
||||
</data>
|
||||
<data name="Second Dan" xml:space="preserve">
|
||||
<value>二段</value>
|
||||
</data>
|
||||
<data name="Second Kyuu" xml:space="preserve">
|
||||
<value>二級</value>
|
||||
</data>
|
||||
<data name="Seventh Dan" xml:space="preserve">
|
||||
<value>七段</value>
|
||||
</data>
|
||||
<data name="Sixth Dan" xml:space="preserve">
|
||||
<value>六段</value>
|
||||
</data>
|
||||
<data name="Tatsujin" xml:space="preserve">
|
||||
<value>達人</value>
|
||||
</data>
|
||||
<data name="Tenth Dan" xml:space="preserve">
|
||||
<value>十段</value>
|
||||
</data>
|
||||
<data name="Third Dan" xml:space="preserve">
|
||||
<value>三段</value>
|
||||
</data>
|
||||
<data name="Third Kyuu" xml:space="preserve">
|
||||
<value>三級</value>
|
||||
</data>
|
||||
<data name="Gold Full Combo" xml:space="preserve">
|
||||
<value>金金合格</value>
|
||||
</data>
|
||||
<data name="Red Donderful Combo" xml:space="preserve">
|
||||
<value>虹赤合格</value>
|
||||
</data>
|
||||
<data name="Red Full Combo" xml:space="preserve">
|
||||
<value>金赤合格</value>
|
||||
</data>
|
||||
<data name="Gold Donderful Combo" xml:space="preserve">
|
||||
<value>虹金合格</value>
|
||||
</data>
|
||||
<data name="Song Title / Artist" xml:space="preserve">
|
||||
<value>曲名 / Artist</value>
|
||||
</data>
|
||||
<data name="Search by Title or Artist" xml:space="preserve">
|
||||
<value>曲名/Artist名搜索</value>
|
||||
</data>
|
||||
<data name="Filter by Genre" xml:space="preserve">
|
||||
<value>分類過濾</value>
|
||||
</data>
|
||||
<data name="Play History" xml:space="preserve">
|
||||
<value>游玩歷史</value>
|
||||
</data>
|
||||
<data name="No Play History Found" xml:space="preserve">
|
||||
<value>没有游玩歷史</value>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>密碼</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>設定</value>
|
||||
</data>
|
||||
<data name="Play Time" xml:space="preserve">
|
||||
<value>游玩時間</value>
|
||||
</data>
|
||||
<data name="Rank" xml:space="preserve">
|
||||
<value>評價</value>
|
||||
</data>
|
||||
<data name="Difficulty" xml:space="preserve">
|
||||
<value>難度</value>
|
||||
</data>
|
||||
<data name="Song Number" xml:space="preserve">
|
||||
<value>曲數</value>
|
||||
</data>
|
||||
<data name="Search by Title, Artist or Date" xml:space="preserve">
|
||||
<value>曲名/Artist名/日期搜索</value>
|
||||
</data>
|
||||
<data name="Unregister" xml:space="preserve">
|
||||
<value>注銷賬號</value>
|
||||
</data>
|
||||
<data name="and" xml:space="preserve">
|
||||
<value>和</value>
|
||||
</data>
|
||||
<data name="other access code(s)" xml:space="preserve">
|
||||
<value>個其他訪問碼</value>
|
||||
</data>
|
||||
<data name="Copy to Clipboard" xml:space="preserve">
|
||||
<value>複製到粘貼板</value>
|
||||
</data>
|
||||
<data name="Invite Code" xml:space="preserve">
|
||||
<value>邀請碼</value>
|
||||
</data>
|
||||
<data name="Error" xml:space="preserve">
|
||||
<value> 錯誤</value>
|
||||
</data>
|
||||
<data name="Access Code is Required" xml:space="preserve">
|
||||
<value>訪問碼為必填項</value>
|
||||
</data>
|
||||
<data name=""Invite Code (Optional)"" xml:space="preserve">
|
||||
<value>邀請碼(可選)</value>
|
||||
</data>
|
||||
<data name="Last Play Time(5 Min Around Credit End)" xml:space="preserve">
|
||||
<value>最後游玩時間(游戲結束5分鐘内)</value>
|
||||
</data>
|
||||
<data name="Password is Required" xml:space="preserve">
|
||||
<value>密碼為必填項</value>
|
||||
</data>
|
||||
<data name="Confirm Password" xml:space="preserve">
|
||||
<value>再次輸入密碼</value>
|
||||
</data>
|
||||
<data name="Confirm Password is Required" xml:space="preserve">
|
||||
<value>再次輸入密碼為必填項</value>
|
||||
</data>
|
||||
<data name="Unknown Error" xml:space="preserve">
|
||||
<value>不明錯誤</value>
|
||||
</data>
|
||||
<data name="Success" xml:space="preserve">
|
||||
<value>成功</value>
|
||||
</data>
|
||||
</root>
|
@ -21,20 +21,20 @@
|
||||
else
|
||||
{
|
||||
<MudBreadcrumbs Items="breadcrumbs" Class="p-0 mb-2"></MudBreadcrumbs>
|
||||
<MudText Typo="Typo.h4">Access Codes</MudText>
|
||||
<MudText Typo="Typo.h4">@Localizer["Access Codes"]</MudText>
|
||||
<MudGrid Class="my-4 pb-10">
|
||||
<MudItem xs="12">
|
||||
<MudCard Outlined="true" Class="mb-6">
|
||||
<MudCardContent>
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12">
|
||||
<MudText Typo="Typo.h6">Add Access Code</MudText>
|
||||
<MudText Typo="Typo.h6">@Localizer["Add Access Code"]</MudText>
|
||||
<MudForm @ref="bindAccessCodeForm">
|
||||
<MudGrid Spacing="2" Class="mt-4">
|
||||
<MudItem xs="12" md="10">
|
||||
<MudTextField @bind-value="inputAccessCode" InputType="InputType.Text" T="string"
|
||||
FullWidth="true" Required="@true" RequiredError="Access Code is required" Variant="Variant.Outlined" Margin="Margin.Dense"
|
||||
Label="New Access Code" />
|
||||
Label=@Localizer["New Access Code"] />
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="2">
|
||||
<MudButton OnClick="OnBind" FullWidth="true" StartIcon="@Icons.Material.Filled.AddCard" Color="Color.Primary" Variant="Variant.Filled" Class="mt-1">Add</MudButton>
|
||||
@ -50,7 +50,7 @@
|
||||
<MudCardContent>
|
||||
<MudGrid Spacing="3" Class="pb-2">
|
||||
<MudItem xs="12">
|
||||
<MudText Typo="Typo.h6">Access Codes</MudText>
|
||||
<MudText Typo="Typo.h6">@Localizer["Access Code"]</MudText>
|
||||
</MudItem>
|
||||
@for (var idx = 0; idx < User.AccessCodes.Count; idx++)
|
||||
{
|
||||
|
@ -26,14 +26,14 @@ public partial class AccessCode
|
||||
|
||||
if (LoginService.IsLoggedIn && !LoginService.IsAdmin)
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Dashboard", href: "/"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Dashboard"], href: "/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Users", href: "/Users"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
||||
};
|
||||
breadcrumbs.Add(new BreadcrumbItem($"{userSetting?.MyDonName}", href: null, disabled: true));
|
||||
breadcrumbs.Add(new BreadcrumbItem("Access Codes", href: $"/Users/{Baid}/AccessCode", disabled: false));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Access Codes"], href: $"/Users/{Baid}/AccessCode", disabled: false));
|
||||
}
|
||||
|
||||
private async Task InitializeUser()
|
||||
|
@ -19,24 +19,24 @@ else
|
||||
<MudCard Elevation="0" Outlined="true">
|
||||
<MudCardContent>
|
||||
<MudForm @ref="changePasswordForm">
|
||||
<MudText Typo="Typo.h5" Class="mb-4">Change Password</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mb-4">@Localizer["Change Password"]</MudText>
|
||||
<div style="display:flex;flex-direction:column;gap:15px;">
|
||||
<MudTextField @bind-value="cardNum" InputType="InputType.Text" T="string"
|
||||
FullWidth="true" Required="@true" RequiredError="Access code is required"
|
||||
Label="Access Code" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
Label=@Localizer["Access Code"] Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudTextField @bind-Value="oldPassword" InputType="InputType.Password"
|
||||
T="string" FullWidth="true" Required="@true"
|
||||
RequiredError="Old Password is required"
|
||||
Label="Old Password" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
Label=@Localizer["Old Password"] Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudTextField @bind-Value="newPassword" InputType="InputType.Password"
|
||||
T="string" FullWidth="true" Required="@true"
|
||||
RequiredError="Password is required"
|
||||
Label="New Password" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
Label=@Localizer["New Password"] Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudTextField @bind-Value="confirmNewPassword" InputType="InputType.Password"
|
||||
T="string" FullWidth="true" Required="@true"
|
||||
RequiredError="Confirm password is required"
|
||||
Label="Confirm New Password" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudButton OnClick="OnChangePassword" FullWidth="true" Class="mt-3" StartIcon="@Icons.Material.Filled.Edit" Color="Color.Primary" Variant="Variant.Filled">Change password</MudButton>
|
||||
Label=@Localizer["Confirm New Password"] Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudButton OnClick="OnChangePassword" FullWidth="true" Class="mt-3" StartIcon="@Icons.Material.Filled.Edit" Color="Color.Primary" Variant="Variant.Filled">@Localizer["Change Password"]</MudButton>
|
||||
</div>
|
||||
</MudForm>
|
||||
</MudCardContent>
|
||||
|
@ -26,37 +26,50 @@ public partial class ChangePassword
|
||||
{
|
||||
case 0:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
"Only admin can log in.",
|
||||
"Ok");
|
||||
Localizer["Dialog OK"]);
|
||||
NavigationManager.NavigateTo("/Users");
|
||||
break;
|
||||
case 1:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Success",
|
||||
Localizer["Success"],
|
||||
"Password changed successfully.",
|
||||
"Ok");
|
||||
Localizer["Dialog OK"]);
|
||||
NavigationManager.NavigateTo("/Users");
|
||||
break;
|
||||
case 2:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
"Confirm new password is not the same as new password.",
|
||||
"Ok");
|
||||
Localizer["Dialog OK"]);
|
||||
break;
|
||||
case 3:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
(MarkupString)
|
||||
"Card number not found.<br />Please play one game with this card number to register it.",
|
||||
"Ok");
|
||||
Localizer["Dialog OK"]);
|
||||
break;
|
||||
case 4:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
(MarkupString)
|
||||
"Old password is wrong!",
|
||||
"Ok");
|
||||
Localizer["Dialog OK"]);
|
||||
break;
|
||||
case 5:
|
||||
await DialogService.ShowMessageBox(
|
||||
Localizer["Error"],
|
||||
(MarkupString)
|
||||
"Card number not registered.<br />Please use register button to create a password first.",
|
||||
Localizer["Dialog OK"]);
|
||||
break;
|
||||
case 6:
|
||||
await DialogService.ShowMessageBox(
|
||||
Localizer["Error"],
|
||||
Localizer["Unknown Error"],
|
||||
Localizer["Dialog OK"]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
else
|
||||
{
|
||||
<MudBreadcrumbs Items="breadcrumbs" Class="p-0 mb-2"></MudBreadcrumbs>
|
||||
<MudText Typo="Typo.h4">@Localizer["Key_03"]</MudText>
|
||||
<MudText Typo="Typo.h4">@Localizer["Dani Dojo"]</MudText>
|
||||
<MudGrid Class="my-4 pb-10">
|
||||
<MudItem xs="12">
|
||||
<MudPaper Elevation="0" Outlined="true">
|
||||
@ -58,7 +58,7 @@ else
|
||||
<MudCard Outlined="true">
|
||||
<MudCardHeader Class="pb-0">
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">@Localizer["Key_01"]</MudText>
|
||||
<MudText Typo="Typo.h6">@Localizer["Score"]</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent Class="d-flex py-10" Style="justify-content:center">
|
||||
@ -119,7 +119,7 @@ else
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-4">@Localizer["Songs"]</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-4">@Localizer["Course Songs"]</MudText>
|
||||
<MudGrid>
|
||||
<MudItem xs="12">
|
||||
<MudGrid Class="d-block">
|
||||
@ -214,7 +214,7 @@ else
|
||||
var redRequirement = GetSoulGauge(danData, false);
|
||||
var goldRequirement = GetSoulGauge(danData, true);
|
||||
var barClass = "bar-default";
|
||||
var resultText = @Localizer["Failed"];
|
||||
var resultText = @Localizer["Not Cleared"];
|
||||
}
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.subtitle2" Style="font-weight:bold;">@Localizer["Result"]</MudText>
|
||||
@ -284,7 +284,7 @@ else
|
||||
var redRequirement = border.RedBorderTotal;
|
||||
var goldRequirement = border.GoldBorderTotal;
|
||||
var barClass = "bar-default";
|
||||
var resultText = @Localizer["Failed"];
|
||||
var resultText = @Localizer["Not Cleared"];
|
||||
}
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.subtitle2" Style="font-weight:bold;">@Localizer["Result"]</MudText>
|
||||
@ -370,7 +370,7 @@ else
|
||||
var redRequirement = GetSongBorderCondition(border, songNumber, false);
|
||||
var goldRequirement = GetSongBorderCondition(border, songNumber, true);
|
||||
var barClass = "bar-default";
|
||||
var resultText = @Localizer["Failed"];
|
||||
var resultText = @Localizer["Not Cleared"];
|
||||
|
||||
<MudItem xs="12" md="4">
|
||||
<MudCard Outlined="true">
|
||||
|
@ -31,48 +31,48 @@ public partial class DaniDojo
|
||||
|
||||
if (LoginService.IsLoggedIn && !LoginService.IsAdmin)
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Dashboard", href: "/"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Dashboard"], href: "/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Users", href: "/Users"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
||||
};
|
||||
breadcrumbs.Add(new BreadcrumbItem($"{userSetting?.MyDonName}", href: null, disabled: true));
|
||||
breadcrumbs.Add(new BreadcrumbItem("Dani Dojo", href: $"/Users/{Baid}/DaniDojo", disabled: false));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Dani Dojo"], href: $"/Users/{Baid}/DaniDojo", disabled: false));
|
||||
}
|
||||
|
||||
private static string GetDanClearStateString(DanClearState danClearState)
|
||||
private string GetDanClearStateString(DanClearState danClearState)
|
||||
{
|
||||
return danClearState switch
|
||||
{
|
||||
DanClearState.NotClear => "Not Cleared",
|
||||
DanClearState.RedNormalClear => "Red Clear",
|
||||
DanClearState.RedFullComboClear => "Red Full Combo",
|
||||
DanClearState.RedPerfectClear => "Red Donderful Combo",
|
||||
DanClearState.GoldNormalClear => "Gold Clear",
|
||||
DanClearState.GoldFullComboClear => "Gold Full Combo",
|
||||
DanClearState.GoldPerfectClear => "Gold Donderful Combo",
|
||||
DanClearState.NotClear => Localizer["Failed"],
|
||||
DanClearState.RedNormalClear => Localizer["Red"],
|
||||
DanClearState.RedFullComboClear => Localizer["Red Full Combo"],
|
||||
DanClearState.RedPerfectClear => Localizer["Red Donderful Combo"],
|
||||
DanClearState.GoldNormalClear => Localizer["Gold"],
|
||||
DanClearState.GoldFullComboClear => Localizer["Gold Full Combo"],
|
||||
DanClearState.GoldPerfectClear => Localizer["Gold Donderful Combo"],
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetDanRequirementString(DanConditionType danConditionType)
|
||||
private string GetDanRequirementString(DanConditionType danConditionType)
|
||||
{
|
||||
return danConditionType switch
|
||||
{
|
||||
DanConditionType.TotalHitCount => "Total Hits",
|
||||
DanConditionType.GoodCount => "Good Hits",
|
||||
DanConditionType.OkCount => "OK Hits",
|
||||
DanConditionType.BadCount => "Bad Hits",
|
||||
DanConditionType.SoulGauge => "Soul Gauge",
|
||||
DanConditionType.DrumrollCount => "Drumroll Hits",
|
||||
DanConditionType.Score => "Score",
|
||||
DanConditionType.ComboCount => "MAX Combo",
|
||||
DanConditionType.TotalHitCount => Localizer["Total Hits"],
|
||||
DanConditionType.GoodCount => Localizer["Good"],
|
||||
DanConditionType.OkCount => Localizer["OK"],
|
||||
DanConditionType.BadCount => Localizer["Bad"],
|
||||
DanConditionType.SoulGauge => Localizer["Soul Gauge"],
|
||||
DanConditionType.DrumrollCount => Localizer["Drumroll"],
|
||||
DanConditionType.Score => Localizer["Score"],
|
||||
DanConditionType.ComboCount => Localizer["MAX Combo"],
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetDanRequirementTitle(DanData.OdaiBorder data)
|
||||
private string GetDanRequirementTitle(DanData.OdaiBorder data)
|
||||
{
|
||||
var danConditionType = (DanConditionType)data.OdaiType;
|
||||
|
||||
@ -134,30 +134,30 @@ public partial class DaniDojo
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetDanTitle(string title)
|
||||
private string GetDanTitle(string title)
|
||||
{
|
||||
return title switch
|
||||
{
|
||||
"5kyuu" => "Fifth Kyuu",
|
||||
"4kyuu" => "Fourth Kyuu",
|
||||
"3kyuu" => "Third Kyuu",
|
||||
"2kyuu" => "Second Kyuu",
|
||||
"1kyuu" => "First Kyuu",
|
||||
"1dan" => "First Dan",
|
||||
"2dan" => "Second Dan",
|
||||
"3dan" => "Third Dan",
|
||||
"4dan" => "Fourth Dan",
|
||||
"5dan" => "Fifth Dan",
|
||||
"6dan" => "Sixth Dan",
|
||||
"7dan" => "Seventh Dan",
|
||||
"8dan" => "Eighth Dan",
|
||||
"9dan" => "Ninth Dan",
|
||||
"10dan" => "Tenth Dan",
|
||||
"11dan" => "Kuroto",
|
||||
"12dan" => "Meijin",
|
||||
"13dan" => "Chojin",
|
||||
"14dan" => "Tatsujin",
|
||||
"15dan" => "Gaiden",
|
||||
"5kyuu" => Localizer["Fifth Kyuu"],
|
||||
"4kyuu" => Localizer["Fourth Kyuu"],
|
||||
"3kyuu" => Localizer["Third Kyuu"],
|
||||
"2kyuu" => Localizer["Second Kyuu"],
|
||||
"1kyuu" => Localizer["First Kyuu"],
|
||||
"1dan" => Localizer["First Dan"],
|
||||
"2dan" => Localizer["Second Dan"],
|
||||
"3dan" => Localizer["Third Dan"],
|
||||
"4dan" => Localizer["Fourth Dan"],
|
||||
"5dan" => Localizer["Fifth Dan"],
|
||||
"6dan" => Localizer["Sixth Dan"],
|
||||
"7dan" => Localizer["Seventh Dan"],
|
||||
"8dan" => Localizer["Eighth Dan"],
|
||||
"9dan" => Localizer["Ninth Dan"],
|
||||
"10dan" => Localizer["Tenth Dan"],
|
||||
"11dan" => Localizer["Kuroto"],
|
||||
"12dan" => Localizer["Meijin"],
|
||||
"13dan" => Localizer["Chojin"],
|
||||
"14dan" => Localizer["Tatsujin"],
|
||||
"15dan" => Localizer["Gaiden"],
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
@page "/"
|
||||
|
||||
<MudText Typo="Typo.h4">@Localizer["dashboard"]</MudText>
|
||||
<MudText Typo="Typo.h4">@Localizer["Dashboard"]</MudText>
|
||||
|
||||
<MudText Class="mt-8">
|
||||
@Localizer["Welcome to TaikoWebUI!"]
|
||||
|
36
TaikoWebUI/Pages/Dialogs/OTPDialog.razor
Normal file
36
TaikoWebUI/Pages/Dialogs/OTPDialog.razor
Normal file
@ -0,0 +1,36 @@
|
||||
@inject HttpClient Client
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IJSRuntime Js
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudText Typo="Typo.h6">@Otp</MudText>
|
||||
<div style="height: 1rem"></div>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary"
|
||||
OnClick="@(_ => CopyToClipboard(Otp))">
|
||||
@Localizer["Copy to Clipboard"]
|
||||
</MudButton>
|
||||
<div style="height: 1rem"></div>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton Color="Color.Primary" OnClick="@Submit">@Localizer["Dialog OK"]</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
MudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string Otp { get; set; } = "";
|
||||
|
||||
private async Task CopyToClipboard(string text)
|
||||
{
|
||||
await Js.InvokeVoidAsync("clipboardCopy.copyText", text);
|
||||
}
|
||||
|
||||
private void Submit()
|
||||
{
|
||||
MudDialog.Close(DialogResult.Ok(true));
|
||||
}
|
||||
}
|
@ -2,9 +2,7 @@
|
||||
|
||||
public partial class ResetPasswordConfirmDialog
|
||||
{
|
||||
|
||||
[CascadingParameter]
|
||||
MudDialogInstance MudDialog { get; set; } = null!;
|
||||
[CascadingParameter] private MudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public User User { get; set; } = new();
|
||||
@ -13,14 +11,12 @@ public partial class ResetPasswordConfirmDialog
|
||||
|
||||
private async Task ResetPassword()
|
||||
{
|
||||
var request = new SetPasswordRequest
|
||||
var request = new ResetPasswordRequest
|
||||
{
|
||||
Baid = User.Baid,
|
||||
Password = "",
|
||||
Salt = ""
|
||||
Baid = User.Baid
|
||||
};
|
||||
var responseMessage = await Client.PostAsJsonAsync("api/Credentials", request);
|
||||
|
||||
|
||||
var responseMessage = await Client.PostAsJsonAsync("api/Auth/ResetPassword", request);
|
||||
if (!responseMessage.IsSuccessStatusCode)
|
||||
{
|
||||
Snackbar.Add("Something went wrong when resetting password!", Severity.Error);
|
||||
|
@ -5,7 +5,7 @@
|
||||
<MudExtensions.MudBarcode Value="@qrCode" BarcodeFormat="ZXing.BarcodeFormat.QR_CODE" Height="300" Width="300" />
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton Color="Color.Primary" OnClick="Submit">Ok</MudButton>
|
||||
<MudButton Color="Color.Primary" OnClick="Submit">@Localizer["Dialog OK"]</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
|
||||
|
@ -50,14 +50,14 @@ public partial class HighScores
|
||||
// Breadcrumbs
|
||||
if (LoginService.IsLoggedIn && !LoginService.IsAdmin)
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Dashboard", href: "/"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Dashboard"], href: "/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Users", href: "/Users"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
||||
};
|
||||
breadcrumbs.Add(new BreadcrumbItem($"{userSetting?.MyDonName}", href: null, disabled: true));
|
||||
breadcrumbs.Add(new BreadcrumbItem("High Scores", href: $"/Users/{Baid}/HighScores", disabled: false));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["High Scores"], href: $"/Users/{Baid}/HighScores", disabled: false));
|
||||
}
|
||||
|
||||
private async Task OnFavoriteToggled(SongBestData data)
|
||||
|
@ -21,11 +21,11 @@
|
||||
<div style="display:flex;flex-direction:column;gap:15px;">
|
||||
<MudTextField @bind-value="inputAccessCode" InputType="InputType.Text" T="string"
|
||||
FullWidth="true" Required="@true" RequiredError="Access code is required"
|
||||
Label="Access Code" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
Label=@Localizer["Access Code"] Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudTextField @bind-Value="inputPassword" InputType="InputType.Password"
|
||||
T="string" FullWidth="true" Required="@true"
|
||||
RequiredError="Password is required"
|
||||
Label="Password" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
Label=@Localizer["Password"] Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudButton OnClick="OnLogin" FullWidth="true" StartIcon="@Icons.Material.Filled.Login" Color="Color.Primary" Variant="Variant.Filled">@Localizer["Log In"]</MudButton>
|
||||
</div>
|
||||
</MudForm>
|
||||
|
@ -17,15 +17,15 @@ public partial class Login
|
||||
{
|
||||
if (response != null)
|
||||
{
|
||||
var result = LoginService.Login(inputAccessCode, inputPassword, response);
|
||||
var options = new DialogOptions() { DisableBackdropClick = true };
|
||||
var result = await LoginService.Login(inputAccessCode, inputPassword, Client);
|
||||
var options = new DialogOptions { DisableBackdropClick = true };
|
||||
switch (result)
|
||||
{
|
||||
case 0:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
"Only admin can log in.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
await loginForm.ResetAsync();
|
||||
break;
|
||||
case 1:
|
||||
@ -33,23 +33,29 @@ public partial class Login
|
||||
break;
|
||||
case 2:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
"Wrong password!",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
break;
|
||||
case 3:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
(MarkupString)
|
||||
"Access code not found.<br />Please play one game with this access code to register it.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
break;
|
||||
case 4:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
(MarkupString)
|
||||
"Access code not registered.<br />Please use register button to create a password first.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
break;
|
||||
case 5:
|
||||
await DialogService.ShowMessageBox(
|
||||
Localizer["Error"],
|
||||
Localizer["Unknown Error"],
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
145
TaikoWebUI/Pages/PlayHistory.razor
Normal file
145
TaikoWebUI/Pages/PlayHistory.razor
Normal file
@ -0,0 +1,145 @@
|
||||
@inject IGameDataService GameDataService
|
||||
@inject HttpClient Client
|
||||
@inject LoginService LoginService
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject NavigationManager NavigationManager
|
||||
@using TaikoWebUI.Utilities;
|
||||
@using TaikoWebUI.Shared.Models;
|
||||
@using SharedProject.Enums;
|
||||
|
||||
@page "/Users/{baid:int}/PlayHistory"
|
||||
|
||||
<MudBreadcrumbs Items="breadcrumbs" Class="p-0 mb-2"></MudBreadcrumbs>
|
||||
<MudText Typo="Typo.h4">@Localizer["Play History"]</MudText>
|
||||
|
||||
<MudGrid Class="my-8">
|
||||
@if (response is null)
|
||||
{
|
||||
<MudContainer Style="display:flex;margin:50px 0;align-items:center;justify-content:center;">
|
||||
<MudProgressCircular Indeterminate="true" Size="Size.Large" Color="Color.Primary" />
|
||||
</MudContainer>
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (LoginService.LoginRequired && (!LoginService.IsLoggedIn || (LoginService.GetLoggedInUser().Baid != Baid && !LoginService.IsAdmin)))
|
||||
{
|
||||
<MudItem xs="12">
|
||||
<MudText Align="Align.Center" Class="my-8">
|
||||
@Localizer["Log In First"]
|
||||
</MudText>
|
||||
</MudItem>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudItem xs="12">
|
||||
<MudTable Items="@songHistoryDataMap.Values.ToList()" Elevation="0" Outlined="true" Filter=@FilterSongs Virtualize="true" RowsPerPage="25">
|
||||
<ToolBarContent>
|
||||
<MudGrid Spacing="2">
|
||||
<MudItem xs="12" md="4">
|
||||
<MudText Typo="Typo.h6">@Localizer["Total Plays"]:@songHistoryDataMap.Values.Count</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="8">
|
||||
<MudTextField @bind-Value="Search"
|
||||
Placeholder=@Localizer["Search by Title, Artist or Date"]
|
||||
Variant="Variant.Outlined"
|
||||
Clearable="true"
|
||||
Immediate="true"
|
||||
Margin="Margin.Dense"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||
IconSize="Size.Medium"/>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</ToolBarContent>
|
||||
<HeaderContent>
|
||||
<MudTh>
|
||||
<MudTableSortLabel InitialDirection="SortDirection.Descending" T="List<SongHistoryData>" SortBy="x => x[0].PlayTime">
|
||||
@Localizer["Play Time"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd Style="width:400px">
|
||||
<MudText>
|
||||
@CultureInfo.CurrentCulture.TextInfo.ToTitleCase(context[0].PlayTime.ToString(Localizer["DateFormat"]))
|
||||
</MudText>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
<ChildRowContent>
|
||||
<MudTable Items="@context" T="SongHistoryData" Context="songHistoryData" Elevation="0" Striped="false" Hover="false" ReadOnly="true">
|
||||
<HeaderContent>
|
||||
<MudTh>@Localizer["Difficulty"]</MudTh>
|
||||
<MudTh>@Localizer["Level"]</MudTh>
|
||||
<MudTh>@Localizer["Song Name"]</MudTh>
|
||||
<MudTh>@Localizer["Genre"]</MudTh>
|
||||
<MudTh>@Localizer["Score"]</MudTh>
|
||||
<MudTh>@Localizer["Crown"]</MudTh>
|
||||
<MudTh>@Localizer["Rank"]</MudTh>
|
||||
<MudTh>@Localizer["Good"]</MudTh>
|
||||
<MudTh>@Localizer["OK"]</MudTh>
|
||||
<MudTh>@Localizer["Bad"]</MudTh>
|
||||
<MudTh>@Localizer["Drumroll"]</MudTh>
|
||||
<MudTh>@Localizer["MAX Combo"]</MudTh>
|
||||
<MudTh>@Localizer["Song Number"]</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
@* Difficulty rating *@
|
||||
<MudTd DataLabel="Difficulty" Style="text-align:center"><MudIcon Style=@IconStyle Icon="@GetDifficultyIcon(songHistoryData.Difficulty)" /></MudTd>
|
||||
@* Star rating *@
|
||||
<MudTd DataLabel="Stars" Style="text-align:center">
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Star" Size="Size.Small" />
|
||||
<MudText Typo="Typo.caption" Style="line-height:1;margin-top:2px;margin-right:2px;">@songHistoryData.Stars</MudText>
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
|
||||
@* Song title *@
|
||||
<MudTd DataLabel="Song">
|
||||
<div>
|
||||
<a href="@($"/Users/{Baid}/Songs/{songHistoryData.SongId}")">
|
||||
<MudText Typo="Typo.body2" Style="font-weight:bold">@songHistoryData.MusicName</MudText>
|
||||
<MudText Typo="Typo.caption">@songHistoryData.MusicArtist</MudText>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<MudToggleIconButton Toggled="@songHistoryData.IsFavorite"
|
||||
ToggledChanged="@(async () => await OnFavoriteToggled(songHistoryData))"
|
||||
Icon="@Icons.Material.Filled.FavoriteBorder" Color="@Color.Secondary"
|
||||
ToggledIcon="@Icons.Material.Filled.Favorite" ToggledColor="@Color.Secondary"
|
||||
Size="Size.Small"
|
||||
ToggledSize="Size.Small"
|
||||
Title="Add to favorites" ToggledTitle="Remove from favorites" />
|
||||
</div>
|
||||
</MudTd>
|
||||
|
||||
@* Genre display *@
|
||||
<MudTd DataLabel="Genre" Style="text-align:left">
|
||||
<MudChip Style=@GetGenreStyle(songHistoryData.Genre) Size="Size.Small">@GetGenreTitle(songHistoryData.Genre)</MudChip>
|
||||
</MudTd>
|
||||
|
||||
<MudTd>@(songHistoryData.Score)</MudTd>
|
||||
<MudTd Style="text-align:center"><img src="@($"/images/crown_{songHistoryData.Crown}.png")" alt="@(GetCrownText(songHistoryData.Crown))" title="@(GetCrownText(songHistoryData.Crown))" style=@IconStyle /></MudTd>
|
||||
<MudTd Style="text-align:center">
|
||||
@if (songHistoryData.ScoreRank is not ScoreRank.None)
|
||||
{
|
||||
<img src="@($"/images/rank_{songHistoryData.ScoreRank}.png")" alt="@(GetRankText(songHistoryData.ScoreRank))" title="@(GetRankText(songHistoryData.ScoreRank))" style=@IconStyle />
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd>@(songHistoryData.GoodCount)</MudTd>
|
||||
<MudTd>@(songHistoryData.OkCount)</MudTd>
|
||||
<MudTd>@(songHistoryData.MissCount)</MudTd>
|
||||
<MudTd>@(songHistoryData.DrumrollCount)</MudTd>
|
||||
<MudTd>@(songHistoryData.ComboCount)</MudTd>
|
||||
<MudTd>@(songHistoryData.SongNumber + 1)</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</ChildRowContent>
|
||||
<PagerContent>
|
||||
<MudTablePager />
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
</MudItem>
|
||||
}
|
||||
}
|
||||
</MudGrid>
|
||||
|
177
TaikoWebUI/Pages/PlayHistory.razor.cs
Normal file
177
TaikoWebUI/Pages/PlayHistory.razor.cs
Normal file
@ -0,0 +1,177 @@
|
||||
using static MudBlazor.Colors;
|
||||
using System;
|
||||
using static MudBlazor.CategoryTypes;
|
||||
using System.Globalization;
|
||||
using Microsoft.JSInterop;
|
||||
using TaikoWebUI.Shared.Models;
|
||||
|
||||
namespace TaikoWebUI.Pages;
|
||||
|
||||
public partial class PlayHistory
|
||||
{
|
||||
[Parameter]
|
||||
public int Baid { get; set; }
|
||||
|
||||
private const string IconStyle = "width:25px; height:25px;";
|
||||
|
||||
private string Search { get; set; } = string.Empty;
|
||||
|
||||
private string? CurrentLanguage;
|
||||
|
||||
private SongHistoryResponse? response;
|
||||
|
||||
private Dictionary<DateTime, List<SongHistoryData>> songHistoryDataMap = new();
|
||||
|
||||
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
||||
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
response = await Client.GetFromJsonAsync<SongHistoryResponse>($"api/PlayHistory/{(uint)Baid}");
|
||||
response.ThrowIfNull();
|
||||
|
||||
CurrentLanguage = await JSRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||
|
||||
response.SongHistoryData.ForEach(data =>
|
||||
{
|
||||
var songId = data.SongId;
|
||||
data.Genre = GameDataService.GetMusicGenreBySongId(songId);
|
||||
data.MusicName = GameDataService.GetMusicNameBySongId(songId, string.IsNullOrEmpty(CurrentLanguage) ? "ja" : CurrentLanguage);
|
||||
data.MusicArtist = GameDataService.GetMusicArtistBySongId(songId, string.IsNullOrEmpty(CurrentLanguage) ? "ja" : CurrentLanguage);
|
||||
data.Stars = GameDataService.GetMusicStarLevel(songId, data.Difficulty);
|
||||
data.ShowDetails = false;
|
||||
});
|
||||
|
||||
songHistoryDataMap = response.SongHistoryData.GroupBy(data => data.PlayTime).ToDictionary(data => data.Key,data => data.ToList());
|
||||
foreach (var songHistoryDataList in songHistoryDataMap.Values)
|
||||
{
|
||||
songHistoryDataList.Sort((data1, data2) => data1.SongNumber.CompareTo(data2.SongNumber));
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetCrownText(CrownType crown)
|
||||
{
|
||||
return crown switch
|
||||
{
|
||||
CrownType.None => "Fail",
|
||||
CrownType.Clear => "Clear",
|
||||
CrownType.Gold => "Full Combo",
|
||||
CrownType.Dondaful => "Donderful Combo",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetRankText(ScoreRank rank)
|
||||
{
|
||||
return rank switch
|
||||
{
|
||||
ScoreRank.White => "Stylish",
|
||||
ScoreRank.Bronze => "Stylish",
|
||||
ScoreRank.Silver => "Stylish",
|
||||
ScoreRank.Gold => "Graceful",
|
||||
ScoreRank.Sakura => "Graceful",
|
||||
ScoreRank.Purple => "Graceful",
|
||||
ScoreRank.Dondaful => "Top Class",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetDifficultyTitle(Difficulty difficulty)
|
||||
{
|
||||
return difficulty switch
|
||||
{
|
||||
Difficulty.Easy => "Easy",
|
||||
Difficulty.Normal => "Normal",
|
||||
Difficulty.Hard => "Hard",
|
||||
Difficulty.Oni => "Oni",
|
||||
Difficulty.UraOni => "Ura Oni",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetDifficultyIcon(Difficulty difficulty)
|
||||
{
|
||||
return $"<image href='/images/difficulty_{difficulty}.png' alt='{difficulty}' width='24' height='24'/>";
|
||||
}
|
||||
|
||||
private static string GetGenreTitle(SongGenre genre)
|
||||
{
|
||||
return genre switch
|
||||
{
|
||||
SongGenre.Pop => "Pop",
|
||||
SongGenre.Anime => "Anime",
|
||||
SongGenre.Kids => "Kids",
|
||||
SongGenre.Vocaloid => "Vocaloid",
|
||||
SongGenre.GameMusic => "Game Music",
|
||||
SongGenre.NamcoOriginal => "NAMCO Original",
|
||||
SongGenre.Variety => "Variety",
|
||||
SongGenre.Classical => "Classical",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetGenreStyle(SongGenre genre)
|
||||
{
|
||||
return genre switch
|
||||
{
|
||||
SongGenre.Pop => "background: #42c0d2; color: #fff",
|
||||
SongGenre.Anime => "background: #ff90d3; color: #fff",
|
||||
SongGenre.Kids => "background: #fec000; color: #fff",
|
||||
SongGenre.Vocaloid => "background: #ddd; color: #000",
|
||||
SongGenre.GameMusic => "background: #cc8aea; color: #fff",
|
||||
SongGenre.NamcoOriginal => "background: #ff7027; color: #fff",
|
||||
SongGenre.Variety => "background: #1dc83b; color: #fff",
|
||||
SongGenre.Classical => "background: #bfa356; color: #000",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
|
||||
private bool FilterSongs(List<SongHistoryData> songHistoryDataList)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Search))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var language = CurrentLanguage ?? "ja";
|
||||
|
||||
if (songHistoryDataList[0].PlayTime
|
||||
.ToString("dddd d MMMM yyyy - HH:mm", CultureInfo.CreateSpecificCulture(language))
|
||||
.Contains(Search, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var songHistoryData in songHistoryDataList)
|
||||
{
|
||||
if (songHistoryData.MusicName.Contains(Search, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (songHistoryData.MusicArtist.Contains(Search, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task OnFavoriteToggled(SongHistoryData data)
|
||||
{
|
||||
var request = new SetFavoriteRequest
|
||||
{
|
||||
Baid = (uint)Baid,
|
||||
IsFavorite = !data.IsFavorite,
|
||||
SongId = data.SongId
|
||||
};
|
||||
var result = await Client.PostAsJsonAsync("api/FavoriteSongs", request);
|
||||
if (result.IsSuccessStatusCode)
|
||||
{
|
||||
data.IsFavorite = !data.IsFavorite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,100 +124,41 @@
|
||||
<MudGrid>
|
||||
<MudItem xs="12">
|
||||
<MudStack Spacing="4" Class="mb-8">
|
||||
@if (LoginService.AllowFreeProfileEditing)
|
||||
{
|
||||
<MudSelect @bind-Value="@response.Head" Label=@Localizer["Head"]>
|
||||
@for (var i = 0; i < costumeFlagArraySizes[1]; i++)
|
||||
{
|
||||
var index = (uint)i;
|
||||
var costumeTitle = GameDataService.GetHeadTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudSelect @bind-Value="@response.Body" Label=@Localizer["Body"]>
|
||||
@for (var i = 0; i < costumeFlagArraySizes[2]; i++)
|
||||
{
|
||||
var index = (uint)i;
|
||||
var costumeTitle = GameDataService.GetBodyTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudSelect @bind-Value="@response.Face" Label=@Localizer["Face"]>
|
||||
@for (var i = 0; i < costumeFlagArraySizes[3]; i++)
|
||||
{
|
||||
var index = (uint)i;
|
||||
var costumeTitle = GameDataService.GetFaceTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudSelect @bind-Value="@response.Kigurumi" Label=@Localizer["Kigurumi"]>
|
||||
@for (var i = 0; i < costumeFlagArraySizes[0]; i++)
|
||||
{
|
||||
var index = (uint)i;
|
||||
var costumeTitle = GameDataService.GetKigurumiTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudSelect @bind-Value="@response.Puchi" Label=@Localizer["Puchi"]>
|
||||
@for (var i = 0; i < costumeFlagArraySizes[4]; i++)
|
||||
{
|
||||
var index = (uint)i;
|
||||
var costumeTitle = GameDataService.GetPuchiTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudSelect @bind-Value="@response.Head" Label=@Localizer["Head"]>
|
||||
@foreach (var i in unlockedHeadCostumes)
|
||||
{
|
||||
var index = i;
|
||||
var costumeTitle = GameDataService.GetHeadTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudSelect @bind-Value="@response.Body" Label=@Localizer["Body"]>
|
||||
@foreach (var i in unlockedBodyCostumes)
|
||||
{
|
||||
var index = i;
|
||||
var costumeTitle = GameDataService.GetBodyTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudSelect @bind-Value="@response.Face" Label=@Localizer["Face"]>
|
||||
@foreach (var i in unlockedFaceCostumes)
|
||||
{
|
||||
var index = i;
|
||||
var costumeTitle = GameDataService.GetFaceTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudSelect @bind-Value="@response.Kigurumi" Label=@Localizer["Kigurumi"]>
|
||||
@foreach (var i in unlockedKigurumiCostumes)
|
||||
{
|
||||
var index = i;
|
||||
var costumeTitle = GameDataService.GetKigurumiTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudSelect @bind-Value="@response.Puchi" Label=@Localizer["Puchi"]>
|
||||
@foreach (var i in unlockedPuchiCostumes)
|
||||
{
|
||||
var index = i;
|
||||
var costumeTitle = GameDataService.GetPuchiTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
}
|
||||
<MudSelect @bind-Value="@response.Head" Label=@Localizer["Head"]>
|
||||
@foreach (var index in headUniqueIdList)
|
||||
{
|
||||
var costumeTitle = GameDataService.GetHeadTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudSelect @bind-Value="@response.Body" Label=@Localizer["Body"]>
|
||||
@foreach (var index in bodyUniqueIdList)
|
||||
{
|
||||
var costumeTitle = GameDataService.GetBodyTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudSelect @bind-Value="@response.Face" Label=@Localizer["Face"]>
|
||||
@foreach (var index in faceUniqueIdList)
|
||||
{
|
||||
var costumeTitle = GameDataService.GetFaceTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudSelect @bind-Value="@response.Kigurumi" Label=@Localizer["Kigurumi"]>
|
||||
@foreach (var index in kigurumiUniqueIdList)
|
||||
{
|
||||
var costumeTitle = GameDataService.GetKigurumiTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudSelect @bind-Value="@response.Puchi" Label=@Localizer["Puchi"]>
|
||||
@foreach (var index in puchiUniqueIdList)
|
||||
{
|
||||
var costumeTitle = GameDataService.GetPuchiTitle(index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="true">
|
||||
@ -311,7 +252,7 @@
|
||||
<MudStack Spacing="4" Class="sticky" Style="top:100px">
|
||||
<MudPaper Elevation="0" Outlined="true">
|
||||
<MudTabs Rounded="true" Border="true" PanelClass="pa-8">
|
||||
<MudTabPanel Text="@Localizer["Player"]">
|
||||
<MudTabPanel Text=@Localizer["Player"]>
|
||||
<MudItem style="height: auto">
|
||||
@* Player Visualizer *@
|
||||
<MudItem style="text-align: center;">
|
||||
@ -349,12 +290,13 @@
|
||||
<MudItem Style="position:absolute; top: 47%; left:0; right:1.1%; height:41%; width:min(96%, 320px); margin: 0 auto; z-index:2">
|
||||
@* Name textoffset to the right for Dan Rank *@
|
||||
<MudItem Style=@($"position:absolute; height:100%; right: 10%; {(response.IsDisplayDanOnNamePlate ? "width:46%;" : "width:80%;")}")>
|
||||
<MudText Id="nameplate-name-outline" Style="position:absolute; height:100%; top: 0; left: 0; right: 0; margin: auto auto; font-family: 'Nijiiro', sans-serif; -webkit-text-stroke: 5px; -webkit-text-stroke-color: black">@response.MyDonName</MudText>
|
||||
<MudText Id="nameplate-name-outline" Style="position:absolute; height:100%; top: 0; left: 0; right: 0; margin: auto auto; font-family: 'Nijiiro', sans-serif; -webkit-text-stroke-width: 5px; -webkit-text-stroke-color: black">@response.MyDonName</MudText>
|
||||
<MudText Id="nameplate-name" Style="position:absolute; height:100%; top: 0; left: 0; right: 0; margin: auto auto; font-family: 'Nijiiro', sans-serif; color:white">@response.MyDonName</MudText>
|
||||
</MudItem>
|
||||
</MudItem>
|
||||
<MudImage onload="nameplateLoaded()" Id="nameplate" Fluid="true" Style="position: relative; top: 0; left: 0;" Src="images/Nameplates/nameplate.png" />
|
||||
<MudImage Fluid="true" Style="position:absolute; top: 0; left: 0; right: 0; margin: 0 auto;" Src=@($"images/Nameplates/nameplate_{TitlePlateStrings[response.TitlePlateId].Replace(' ', '_')}.png") />
|
||||
<MudImage onload="nameplateLoaded()" Id="nameplate" Fluid="true" Style="position: relative; bottom: 0; left: 0;" Src="images/Nameplates/nameplate.png" />
|
||||
@* Check if image does not exist, use nameplate_Wood.png *@
|
||||
<MudImage Fluid="true" Style="position:absolute; bottom: 0%; left: 0; right: 0; margin: 0 auto;" onerror="this.src='images/Nameplates/nameplate_Wood.png'" Src=@($"images/Nameplates/nameplate_{TitlePlateStrings[response.TitlePlateId].Replace(' ', '_')}.png") />
|
||||
@if (response.IsDisplayDanOnNamePlate)
|
||||
{
|
||||
<MudImage Fluid="true" Style="position:absolute; top: 0; left: 0; right: 0; margin: 0 auto;" Src="images/Nameplates/nameplate_dan.png" />
|
||||
|
@ -135,16 +135,16 @@ public partial class Profile
|
||||
"Synth Drum", "Shuriken", "Bubble Pop", "Electric Guitar"
|
||||
};
|
||||
|
||||
private static readonly string[] LanguageStrings =
|
||||
{
|
||||
"Japanese", "English", "Chinese (Traditional)", "Korean", "Chinese (Simplified)"
|
||||
};
|
||||
|
||||
private static readonly string[] TitlePlateStrings =
|
||||
{
|
||||
"Wood", "Rainbow", "Gold", "Purple",
|
||||
"AI 1", "AI 2", "AI 3", "AI 4"
|
||||
};
|
||||
|
||||
private static readonly string[] LanguageStrings =
|
||||
{
|
||||
"Japanese", "English", "Chinese (Traditional)", "Korean", "Chinese (Simplified)"
|
||||
};
|
||||
|
||||
private static readonly string[] DifficultySettingCourseStrings =
|
||||
{
|
||||
@ -169,14 +169,14 @@ public partial class Profile
|
||||
private Dictionary<Difficulty, List<SongBestData>> songBestDataMap = new();
|
||||
|
||||
private Difficulty highestDifficulty = Difficulty.Easy;
|
||||
|
||||
private List<int> costumeFlagArraySizes = new();
|
||||
|
||||
private List<uint> unlockedHeadCostumes = new();
|
||||
private List<uint> unlockedBodyCostumes = new();
|
||||
private List<uint> unlockedFaceCostumes = new();
|
||||
private List<uint> unlockedKigurumiCostumes = new();
|
||||
private List<uint> unlockedPuchiCostumes = new();
|
||||
|
||||
private List<uint> kigurumiUniqueIdList = new();
|
||||
private List<uint> headUniqueIdList = new();
|
||||
private List<uint> bodyUniqueIdList = new();
|
||||
private List<uint> faceUniqueIdList = new();
|
||||
private List<uint> puchiUniqueIdList = new();
|
||||
private List<uint> titleUniqueIdList = new();
|
||||
private List<uint> titlePlateIdList = new();
|
||||
|
||||
private int[] scoresArray = new int[10];
|
||||
|
||||
@ -189,25 +189,17 @@ public partial class Profile
|
||||
|
||||
if (LoginService.IsLoggedIn && !LoginService.IsAdmin)
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Dashboard", href: "/"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Dashboard"], href: "/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Users", href: "/Users"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
||||
};
|
||||
breadcrumbs.Add(new BreadcrumbItem($"{response.MyDonName}", href: null, disabled: true));
|
||||
breadcrumbs.Add(new BreadcrumbItem("Profile", href: $"/Users/{Baid}/Profile", disabled: false));
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
unlockedHeadCostumes = response.UnlockedHead.Distinct().OrderBy(x => x).ToList();
|
||||
unlockedBodyCostumes = response.UnlockedBody.Distinct().OrderBy(x => x).ToList();
|
||||
unlockedFaceCostumes = response.UnlockedFace.Distinct().OrderBy(x => x).ToList();
|
||||
unlockedKigurumiCostumes = response.UnlockedKigurumi.Distinct().OrderBy(x => x).ToList();
|
||||
unlockedPuchiCostumes = response.UnlockedPuchi.Distinct().OrderBy(x => x).ToList();
|
||||
}
|
||||
|
||||
costumeFlagArraySizes = GameDataService.GetCostumeFlagArraySizes();
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Profile"], href: $"/Users/{Baid}/Profile", disabled: false));
|
||||
|
||||
InitializeAvailableCostumes();
|
||||
InitializeAvailableTitles();
|
||||
|
||||
songresponse = await Client.GetFromJsonAsync<SongBestResponse>($"api/PlayData/{Baid}");
|
||||
songresponse.ThrowIfNull();
|
||||
@ -229,16 +221,86 @@ public partial class Profile
|
||||
.CompareTo(GameDataService.GetMusicIndexBySongId(data2.SongId)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)Difficulty.UraOni; i++)
|
||||
for (var i = 0; i < (int)Difficulty.UraOni; i++)
|
||||
if (songBestDataMap.TryGetValue((Difficulty)i, out var values))
|
||||
{
|
||||
highestDifficulty = (Difficulty)i;
|
||||
}
|
||||
|
||||
|
||||
UpdateScores(response.AchievementDisplayDifficulty);
|
||||
|
||||
if (response != null) UpdateScores(response.AchievementDisplayDifficulty);
|
||||
}
|
||||
|
||||
private void InitializeAvailableCostumes()
|
||||
{
|
||||
var unlockedKigurumi = response != null ? response.UnlockedKigurumi : new List<uint>();
|
||||
var unlockedHead = response != null ? response.UnlockedHead : new List<uint>();
|
||||
var unlockedBody = response != null ? response.UnlockedBody : new List<uint>();
|
||||
var unlockedFace = response != null ? response.UnlockedFace : new List<uint>();
|
||||
var unlockedPuchi = response != null ? response.UnlockedPuchi : new List<uint>();
|
||||
|
||||
if (LoginService.AllowFreeProfileEditing)
|
||||
{
|
||||
kigurumiUniqueIdList = GameDataService.GetKigurumiUniqueIdList();
|
||||
headUniqueIdList = GameDataService.GetHeadUniqueIdList();
|
||||
bodyUniqueIdList = GameDataService.GetBodyUniqueIdList();
|
||||
faceUniqueIdList = GameDataService.GetFaceUniqueIdList();
|
||||
puchiUniqueIdList = GameDataService.GetPuchiUniqueIdList();
|
||||
|
||||
// Lock costumes in LockedCostumesList but not in UnlockedCostumesList
|
||||
var lockedKigurumiUniqueIdList = GameDataService.GetLockedKigurumiUniqueIdList().Except(unlockedKigurumi).ToList();
|
||||
var lockedHeadUniqueIdList = GameDataService.GetLockedHeadUniqueIdList().Except(unlockedHead).ToList();
|
||||
var lockedBodyUniqueIdList = GameDataService.GetLockedBodyUniqueIdList().Except(unlockedBody).ToList();
|
||||
var lockedFaceUniqueIdList = GameDataService.GetLockedFaceUniqueIdList().Except(unlockedFace).ToList();
|
||||
var lockedPuchiUniqueIdList = GameDataService.GetLockedPuchiUniqueIdList().Except(unlockedPuchi).ToList();
|
||||
|
||||
lockedKigurumiUniqueIdList.ForEach(id => kigurumiUniqueIdList.Remove(id));
|
||||
lockedHeadUniqueIdList.ForEach(id => headUniqueIdList.Remove(id));
|
||||
lockedBodyUniqueIdList.ForEach(id => bodyUniqueIdList.Remove(id));
|
||||
lockedFaceUniqueIdList.ForEach(id => faceUniqueIdList.Remove(id));
|
||||
lockedPuchiUniqueIdList.ForEach(id => puchiUniqueIdList.Remove(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only unlock costumes that are in both UnlockedCostumesList and CostumeList
|
||||
kigurumiUniqueIdList = GameDataService.GetKigurumiUniqueIdList().Intersect(unlockedKigurumi).ToList();
|
||||
headUniqueIdList = GameDataService.GetHeadUniqueIdList().Intersect(unlockedHead).ToList();
|
||||
bodyUniqueIdList = GameDataService.GetBodyUniqueIdList().Intersect(unlockedBody).ToList();
|
||||
faceUniqueIdList = GameDataService.GetFaceUniqueIdList().Intersect(unlockedFace).ToList();
|
||||
puchiUniqueIdList = GameDataService.GetPuchiUniqueIdList().Intersect(unlockedPuchi).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeAvailableTitlePlates()
|
||||
{
|
||||
titlePlateIdList = GameDataService.GetTitlePlateIdList().Except(GameDataService.GetLockedTitlePlateIdList()).ToList();
|
||||
// Cut off ids longer than TitlePlateStrings
|
||||
titlePlateIdList = titlePlateIdList.Where(id => id < TitlePlateStrings.Length).Except(GameDataService.GetLockedTitlePlateIdList()).ToList();
|
||||
}
|
||||
|
||||
private void InitializeAvailableTitles()
|
||||
{
|
||||
InitializeAvailableTitlePlates();
|
||||
|
||||
var unlockedTitle = response != null ? response.UnlockedTitle : new List<uint>();
|
||||
|
||||
if (LoginService.AllowFreeProfileEditing)
|
||||
{
|
||||
titleUniqueIdList = GameDataService.GetTitleUniqueIdList();
|
||||
|
||||
var titles = GameDataService.GetTitles();
|
||||
// Lock titles in LockedTitlesList but not in UnlockedTitle
|
||||
var lockedTitleUniqueIdList = GameDataService.GetLockedTitleUniqueIdList().Except(unlockedTitle).ToList();
|
||||
// Lock titles with rarity not in titlePlateIdList and not in unlockedTitle
|
||||
lockedTitleUniqueIdList.AddRange(titles.Where(title => !titlePlateIdList.Contains(title.TitleRarity) && !unlockedTitle.Contains(title.TitleId)).Select(title => title.TitleId));
|
||||
titleUniqueIdList = titleUniqueIdList.Except(lockedTitleUniqueIdList).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only unlock titles that are in both UnlockedTitlesList and TitleList
|
||||
titleUniqueIdList = GameDataService.GetTitleUniqueIdList().Intersect(unlockedTitle).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveOptions()
|
||||
{
|
||||
isSavingOptions = true;
|
||||
@ -246,7 +308,7 @@ public partial class Profile
|
||||
isSavingOptions = false;
|
||||
|
||||
// Adjust breadcrumb if name is changed
|
||||
if (response != null && response.MyDonName != null)
|
||||
if (response != null)
|
||||
{
|
||||
breadcrumbs[^2] = new BreadcrumbItem($"{response.MyDonName}", href: null, disabled: true);
|
||||
}
|
||||
@ -260,49 +322,47 @@ public partial class Profile
|
||||
|
||||
if (difficulty is Difficulty.None) difficulty = highestDifficulty;
|
||||
|
||||
if (songBestDataMap.TryGetValue(difficulty, out var values))
|
||||
if (!songBestDataMap.TryGetValue(difficulty, out var values)) return;
|
||||
|
||||
foreach (var value in values)
|
||||
{
|
||||
foreach (var value in values)
|
||||
switch (value.BestScoreRank)
|
||||
{
|
||||
switch (value.BestScoreRank)
|
||||
{
|
||||
case ScoreRank.Dondaful:
|
||||
scoresArray[0]++;
|
||||
break;
|
||||
case ScoreRank.Gold:
|
||||
scoresArray[1]++;
|
||||
break;
|
||||
case ScoreRank.Sakura:
|
||||
scoresArray[2]++;
|
||||
break;
|
||||
case ScoreRank.Purple:
|
||||
scoresArray[3]++;
|
||||
break;
|
||||
case ScoreRank.White:
|
||||
scoresArray[4]++;
|
||||
break;
|
||||
case ScoreRank.Bronze:
|
||||
scoresArray[5]++;
|
||||
break;
|
||||
case ScoreRank.Silver:
|
||||
scoresArray[6]++;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (value.BestCrown)
|
||||
{
|
||||
case CrownType.Clear:
|
||||
scoresArray[7]++;
|
||||
break;
|
||||
case CrownType.Gold:
|
||||
scoresArray[8]++;
|
||||
break;
|
||||
case CrownType.Dondaful:
|
||||
scoresArray[9]++;
|
||||
break;
|
||||
}
|
||||
case ScoreRank.Dondaful:
|
||||
scoresArray[0]++;
|
||||
break;
|
||||
case ScoreRank.Gold:
|
||||
scoresArray[1]++;
|
||||
break;
|
||||
case ScoreRank.Sakura:
|
||||
scoresArray[2]++;
|
||||
break;
|
||||
case ScoreRank.Purple:
|
||||
scoresArray[3]++;
|
||||
break;
|
||||
case ScoreRank.White:
|
||||
scoresArray[4]++;
|
||||
break;
|
||||
case ScoreRank.Bronze:
|
||||
scoresArray[5]++;
|
||||
break;
|
||||
case ScoreRank.Silver:
|
||||
scoresArray[6]++;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (value.BestCrown)
|
||||
{
|
||||
case CrownType.Clear:
|
||||
scoresArray[7]++;
|
||||
break;
|
||||
case CrownType.Gold:
|
||||
scoresArray[8]++;
|
||||
break;
|
||||
case CrownType.Dondaful:
|
||||
scoresArray[9]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static string CostumeOrDefault(string file, uint id, string defaultfile)
|
||||
|
@ -22,30 +22,32 @@ else
|
||||
<MudItem xs="12" md="6" lg="4">
|
||||
<MudCard Elevation="0" Outlined="true">
|
||||
<MudCardHeader>
|
||||
<MudText Typo="Typo.h5">Register</MudText>
|
||||
<MudText Typo="Typo.h5">@Localizer["Register"]</MudText>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudForm @ref="registerForm">
|
||||
<div style="display:flex;flex-direction:column;gap:15px;">
|
||||
<MudTextField @bind-value="accessCode" InputType="InputType.Text" T="string"
|
||||
FullWidth="true" Required="@true" RequiredError="Access Code is required"
|
||||
Label="Access Code" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
FullWidth="true" Required="@true" RequiredError=@Localizer["Access Code is required"]
|
||||
Label=@Localizer["Access Code"] Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
@if (LoginService.RegisterWithLastPlayTime)
|
||||
{
|
||||
<MudDatePicker @ref="datePicker" Label="Last Play Date" @bind-Date="date" AutoClose="true" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudTimePicker @ref="timePicker" AmPm="true" Label="Last Play Time(5 min around credit end)" @bind-Time="time" AutoClose="true" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudTextField @bind-value="inviteCode" InputType="InputType.Text" T="string"
|
||||
FullWidth="true" Label=@Localizer["Invite Code (Optional)"]/>
|
||||
<MudDatePicker @ref="datePicker" Label=@Localizer["Last Play Date"] @bind-Date="date" AutoClose="true" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudTimePicker @ref="timePicker" AmPm="true" Label=@Localizer["Last Play Time(5 Min Around Credit End)"] @bind-Time="time" AutoClose="true" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
}
|
||||
<MudTextField @bind-Value="password" InputType="InputType.Password"
|
||||
T="string" FullWidth="true" Required="@true"
|
||||
RequiredError="Password is required"
|
||||
Label="Password" Variant="Variant.Outlined" Margin="Margin.Dense">
|
||||
RequiredError=@Localizer["Password is Required"]
|
||||
Label=@Localizer["Password"] Variant="Variant.Outlined" Margin="Margin.Dense">
|
||||
</MudTextField>
|
||||
<MudTextField @bind-Value="confirmPassword" InputType="InputType.Password"
|
||||
T="string" FullWidth="true" Required="@true"
|
||||
RequiredError="Confirm password is required"
|
||||
Label="Confirm Password" Variant="Variant.Outlined" Margin="Margin.Dense">
|
||||
RequiredError=@Localizer["Confirm Password is Required"]
|
||||
Label=@Localizer["Confirm Password"] Variant="Variant.Outlined" Margin="Margin.Dense">
|
||||
</MudTextField>
|
||||
<MudButton OnClick="OnRegister" FullWidth="true" StartIcon="@Icons.Material.Filled.AddCard" Color="Color.Primary" Variant="Variant.Filled">Register</MudButton>
|
||||
<MudButton OnClick="OnRegister" FullWidth="true" StartIcon="@Icons.Material.Filled.AddCard" Color="Color.Primary" Variant="Variant.Filled">@Localizer["Register"]</MudButton>
|
||||
</div>
|
||||
</MudForm>
|
||||
</MudCardContent>
|
||||
|
@ -11,7 +11,8 @@ public partial class Register
|
||||
private MudTimePicker timePicker = new();
|
||||
private DateTime? date = DateTime.Today;
|
||||
private TimeSpan? time = new TimeSpan(00, 45, 00);
|
||||
|
||||
private string inviteCode = "";
|
||||
|
||||
private DashboardResponse? response;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
@ -25,51 +26,57 @@ public partial class Register
|
||||
var inputDateTime = date!.Value.Date + time!.Value;
|
||||
if (response != null)
|
||||
{
|
||||
var result = await LoginService.Register(accessCode, inputDateTime, password, confirmPassword, response, Client);
|
||||
var options = new DialogOptions() { DisableBackdropClick = true };
|
||||
var result = await LoginService.Register(accessCode, inputDateTime, password, confirmPassword, response, Client, inviteCode);
|
||||
var options = new DialogOptions { DisableBackdropClick = true };
|
||||
switch (result)
|
||||
{
|
||||
case 0:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
"Only admin can log in.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Error"],
|
||||
"Only admin can register.",
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
NavigationManager.NavigateTo("/");
|
||||
break;
|
||||
case 1:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Success",
|
||||
Localizer["Success"],
|
||||
"Access code registered successfully.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
NavigationManager.NavigateTo("/Login");
|
||||
break;
|
||||
case 2:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
"Confirm password is not the same as password.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
break;
|
||||
case 3:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
(MarkupString)
|
||||
"Access code not found.<br />Please play one game with this access code to register it.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
break;
|
||||
case 4:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
(MarkupString)
|
||||
"Access code is already registered, please use set password to login.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
NavigationManager.NavigateTo("/Login");
|
||||
break;
|
||||
case 5:
|
||||
await DialogService.ShowMessageBox(
|
||||
"Error",
|
||||
Localizer["Error"],
|
||||
(MarkupString)
|
||||
"Wrong last play time.<br />If you have forgotten when you last played, please play another game with this access code.",
|
||||
"Ok", null, null, options);
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
break;
|
||||
case 6:
|
||||
await DialogService.ShowMessageBox(
|
||||
Localizer["Error"],
|
||||
Localizer["Unknown Error"],
|
||||
Localizer["Dialog OK"], null, null, options);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -43,14 +43,14 @@ namespace TaikoWebUI.Pages
|
||||
|
||||
if (LoginService.IsLoggedIn && !LoginService.IsAdmin)
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Dashboard", href: "/"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Dashboard"], href: "/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Users", href: "/Users"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
||||
};
|
||||
breadcrumbs.Add(new BreadcrumbItem($"{userSetting?.MyDonName}", href: null, disabled: true));
|
||||
breadcrumbs.Add(new BreadcrumbItem("Songs", href: $"/Users/{Baid}/Songs", disabled: false));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Song List"], href: $"/Users/{Baid}/Songs", disabled: false));
|
||||
breadcrumbs.Add(new BreadcrumbItem(_songTitle, href: $"/Users/{Baid}/Songs/{SongId}", disabled: false));
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
@page "/Users/{baid:int}/Songs"
|
||||
|
||||
<MudBreadcrumbs Items="breadcrumbs" Class="p-0 mb-2"></MudBreadcrumbs>
|
||||
<MudText Typo="Typo.h4">@Localizer["Key_01"]</MudText>
|
||||
<MudText Typo="Typo.h4">@Localizer["Song List"]</MudText>
|
||||
|
||||
<MudGrid Class="my-8">
|
||||
@if (response is null)
|
||||
@ -65,12 +65,12 @@
|
||||
<HeaderContent>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicNameBySongId(context.SongId, CurrentLanguage)">
|
||||
Song Title / Artist
|
||||
@Localizer["Song Title / Artist"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="MusicDetail" SortBy="context => context.Genre">
|
||||
Genre
|
||||
@Localizer["Genre"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
@foreach (var difficulty in Enum.GetValues<Difficulty>())
|
||||
|
@ -37,14 +37,14 @@ public partial class SongList
|
||||
|
||||
if (LoginService.IsLoggedIn && !LoginService.IsAdmin)
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Dashboard", href: "/"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Dashboard"], href: "/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem("Users", href: "/Users"));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
||||
};
|
||||
breadcrumbs.Add(new BreadcrumbItem($"{userSetting?.MyDonName}", href: null, disabled: true));
|
||||
breadcrumbs.Add(new BreadcrumbItem("Songs", href: $"/Users/{Baid}/Songs", disabled: false));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Song List"], href: $"/Users/{Baid}/Songs", disabled: false));
|
||||
}
|
||||
|
||||
private async Task OnFavoriteToggled(SongBestData data)
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
@page "/Users"
|
||||
|
||||
<MudText Typo="Typo.h4">@Localizer["users"]</MudText>
|
||||
<MudText Typo="Typo.h4">@Localizer["Users"]</MudText>
|
||||
<MudGrid Class="my-8">
|
||||
@if (response is not null)
|
||||
{
|
||||
|
@ -8,8 +8,6 @@ public class GameDataService : IGameDataService
|
||||
{
|
||||
private readonly HttpClient client;
|
||||
private readonly Dictionary<uint, MusicDetail> musicMap = new();
|
||||
private List<int> costumeFlagArraySizes = new();
|
||||
private int titleFlagArraySize;
|
||||
private ImmutableDictionary<uint, DanData> danMap = ImmutableDictionary<uint, DanData>.Empty;
|
||||
private ImmutableHashSet<Title> titles = ImmutableHashSet<Title>.Empty;
|
||||
|
||||
@ -18,6 +16,23 @@ public class GameDataService : IGameDataService
|
||||
private string[] headTitles = { };
|
||||
private string[] kigurumiTitles = { };
|
||||
private string[] puchiTitles = { };
|
||||
|
||||
private List<uint> kigurumiUniqueIdList = new();
|
||||
private List<uint> headUniqueIdList = new();
|
||||
private List<uint> bodyUniqueIdList = new();
|
||||
private List<uint> faceUniqueIdList = new();
|
||||
private List<uint> puchiUniqueIdList = new();
|
||||
|
||||
private List<uint> titleUniqueIdList = new();
|
||||
private List<uint> titlePlateIdList = new();
|
||||
|
||||
private List<uint> lockedKigurumiUniqueIdList = new();
|
||||
private List<uint> lockedHeadUniqueIdList = new();
|
||||
private List<uint> lockedBodyUniqueIdList = new();
|
||||
private List<uint> lockedFaceUniqueIdList = new();
|
||||
private List<uint> lockedPuchiUniqueIdList = new();
|
||||
private List<uint> lockedTitleUniqueIdList = new();
|
||||
private List<uint> lockedTitlePlateIdList = new();
|
||||
|
||||
public GameDataService(HttpClient client)
|
||||
{
|
||||
@ -38,19 +53,30 @@ public class GameDataService : IGameDataService
|
||||
danMap = danData.ToImmutableDictionary(data => data.DanId);
|
||||
|
||||
// To prevent duplicate entries in wordlist
|
||||
var dict = wordList.WordListEntries.GroupBy(entry => entry.Key)
|
||||
var wordlistDict = wordList.WordListEntries.GroupBy(entry => entry.Key)
|
||||
.ToImmutableDictionary(group => group.Key, group => group.First());
|
||||
await Task.Run(() => InitializeMusicMap(musicInfo, dict, musicOrder));
|
||||
await Task.Run(() => InitializeMusicMap(musicInfo, wordlistDict, musicOrder));
|
||||
|
||||
InitializeCostumeFlagArraySizes(donCosRewardData);
|
||||
InitializeTitleFlagArraySize(shougouData);
|
||||
await Task.Run(() => InitializeCostumeIdLists(donCosRewardData));
|
||||
await Task.Run(() => InitializeTitleIdList(shougouData));
|
||||
|
||||
await Task.Run(() => InitializeHeadTitles(dict));
|
||||
await Task.Run(() => InitializeFaceTitles(dict));
|
||||
await Task.Run(() => InitializeBodyTitles(dict));
|
||||
await Task.Run(() => InitializePuchiTitles(dict));
|
||||
await Task.Run(() => InitializeKigurumiTitles(dict));
|
||||
await Task.Run(() => InitializeTitles(dict, shougouData));
|
||||
await Task.Run(() => InitializeHeadTitles(wordlistDict));
|
||||
await Task.Run(() => InitializeFaceTitles(wordlistDict));
|
||||
await Task.Run(() => InitializeBodyTitles(wordlistDict));
|
||||
await Task.Run(() => InitializePuchiTitles(wordlistDict));
|
||||
await Task.Run(() => InitializeKigurumiTitles(wordlistDict));
|
||||
await Task.Run(() => InitializeTitles(wordlistDict, shougouData));
|
||||
|
||||
var lockedCostumeDataDictionary = await client.GetFromJsonAsync<Dictionary<string, List<uint>>>($"{dataBaseUrl}/data/locked_costume_data.json") ?? throw new InvalidOperationException();
|
||||
lockedKigurumiUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Kigurumi") ?? new List<uint>();
|
||||
lockedHeadUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Head") ?? new List<uint>();
|
||||
lockedBodyUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Body") ?? new List<uint>();
|
||||
lockedFaceUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Face") ?? new List<uint>();
|
||||
lockedPuchiUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Puchi") ?? new List<uint>();
|
||||
|
||||
var lockedTitleDataDictionary = await client.GetFromJsonAsync<Dictionary<string, List<uint>>>($"{dataBaseUrl}/data/locked_title_data.json") ?? throw new InvalidOperationException();
|
||||
lockedTitleUniqueIdList = lockedTitleDataDictionary.GetValueOrDefault("TitleNo") ?? new List<uint>();
|
||||
lockedTitlePlateIdList = lockedTitleDataDictionary.GetValueOrDefault("TitlePlateNo") ?? new List<uint>();
|
||||
}
|
||||
|
||||
private async Task<T> GetData<T>(string dataBaseUrl, string fileBaseName) where T : notnull
|
||||
@ -150,16 +176,46 @@ public class GameDataService : IGameDataService
|
||||
{
|
||||
return titles;
|
||||
}
|
||||
|
||||
public List<int> GetCostumeFlagArraySizes()
|
||||
|
||||
public List<uint> GetKigurumiUniqueIdList()
|
||||
{
|
||||
return costumeFlagArraySizes;
|
||||
return kigurumiUniqueIdList;
|
||||
}
|
||||
|
||||
private void InitializeTitleFlagArraySize(Shougous? shougouData)
|
||||
|
||||
public List<uint> GetHeadUniqueIdList()
|
||||
{
|
||||
shougouData.ThrowIfNull("Shouldn't happen!");
|
||||
titleFlagArraySize = (int)shougouData.ShougouEntries.Max(entry => entry.UniqueId) + 1;
|
||||
return headUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetBodyUniqueIdList()
|
||||
{
|
||||
return bodyUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetFaceUniqueIdList()
|
||||
{
|
||||
return faceUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetPuchiUniqueIdList()
|
||||
{
|
||||
return puchiUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetTitleUniqueIdList()
|
||||
{
|
||||
return titleUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetTitlePlateIdList()
|
||||
{
|
||||
return titlePlateIdList;
|
||||
}
|
||||
|
||||
private void InitializeTitleIdList(Shougous? shougouData)
|
||||
{
|
||||
shougouData.ThrowIfNull("Shouldn't happen!");
|
||||
titleUniqueIdList = shougouData.ShougouEntries.Select(entry => entry.UniqueId).ToList();
|
||||
}
|
||||
|
||||
private void InitializeTitles(ImmutableDictionary<string, WordListEntry> dict, Shougous? shougouData)
|
||||
@ -167,7 +223,7 @@ public class GameDataService : IGameDataService
|
||||
shougouData.ThrowIfNull("Shouldn't happen!");
|
||||
|
||||
var set = ImmutableHashSet.CreateBuilder<Title>();
|
||||
for (var i = 1; i < titleFlagArraySize; i++)
|
||||
foreach (var i in titleUniqueIdList)
|
||||
{
|
||||
var key = $"syougou_{i}";
|
||||
|
||||
@ -188,41 +244,31 @@ public class GameDataService : IGameDataService
|
||||
|
||||
titles = set.ToImmutable();
|
||||
}
|
||||
|
||||
private void InitializeCostumeFlagArraySizes(DonCosRewards? donCosRewardData)
|
||||
|
||||
private void InitializeCostumeIdLists(DonCosRewards? donCosRewardData)
|
||||
{
|
||||
donCosRewardData.ThrowIfNull("Shouldn't happen!");
|
||||
var kigurumiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
kigurumiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "kigurumi")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var headUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Select(entry => entry.UniqueId).ToList();
|
||||
headUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "head")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var bodyUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Select(entry => entry.UniqueId).ToList();
|
||||
bodyUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "body")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var faceUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Select(entry => entry.UniqueId).ToList();
|
||||
faceUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "face")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var puchiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Select(entry => entry.UniqueId).ToList();
|
||||
puchiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "puchi")
|
||||
.Select(entry => entry.UniqueId);
|
||||
|
||||
costumeFlagArraySizes = new List<int>
|
||||
{
|
||||
(int)kigurumiUniqueIdList.Max() + 1,
|
||||
(int)headUniqueIdList.Max() + 1,
|
||||
(int)bodyUniqueIdList.Max() + 1,
|
||||
(int)faceUniqueIdList.Max() + 1,
|
||||
(int)puchiUniqueIdList.Max() + 1
|
||||
};
|
||||
.Select(entry => entry.UniqueId).ToList();
|
||||
}
|
||||
|
||||
private void InitializeKigurumiTitles(ImmutableDictionary<string, WordListEntry> dict)
|
||||
{
|
||||
var costumeKigurumiMax = costumeFlagArraySizes[0];
|
||||
kigurumiTitles = new string[costumeKigurumiMax];
|
||||
for (var i = 0; i < costumeKigurumiMax; i++)
|
||||
kigurumiTitles = new string[kigurumiUniqueIdList.Max() + 1];
|
||||
foreach (var i in kigurumiUniqueIdList)
|
||||
{
|
||||
var key = $"costume_kigurumi_{i}";
|
||||
|
||||
@ -233,9 +279,8 @@ public class GameDataService : IGameDataService
|
||||
|
||||
private void InitializeHeadTitles(ImmutableDictionary<string, WordListEntry> dict)
|
||||
{
|
||||
var costumeHeadMax = costumeFlagArraySizes[1];
|
||||
headTitles = new string[costumeHeadMax];
|
||||
for (var i = 0; i < costumeHeadMax; i++)
|
||||
headTitles = new string[headUniqueIdList.Max() + 1];
|
||||
foreach (var i in headUniqueIdList)
|
||||
{
|
||||
var key = $"costume_head_{i}";
|
||||
|
||||
@ -246,9 +291,8 @@ public class GameDataService : IGameDataService
|
||||
|
||||
private void InitializeBodyTitles(ImmutableDictionary<string, WordListEntry> dict)
|
||||
{
|
||||
var costumeBodyMax = costumeFlagArraySizes[2];
|
||||
bodyTitles = new string[costumeBodyMax];
|
||||
for (var i = 0; i < costumeBodyMax; i++)
|
||||
bodyTitles = new string[bodyUniqueIdList.Max() + 1];
|
||||
foreach (var i in bodyUniqueIdList)
|
||||
{
|
||||
var key = $"costume_body_{i}";
|
||||
|
||||
@ -259,9 +303,8 @@ public class GameDataService : IGameDataService
|
||||
|
||||
private void InitializeFaceTitles(ImmutableDictionary<string, WordListEntry> dict)
|
||||
{
|
||||
var costumeFaceMax = costumeFlagArraySizes[3];
|
||||
faceTitles = new string[costumeFaceMax];
|
||||
for (var i = 0; i < costumeFaceMax; i++)
|
||||
faceTitles = new string[faceUniqueIdList.Max() + 1];
|
||||
foreach (var i in faceUniqueIdList)
|
||||
{
|
||||
var key = $"costume_face_{i}";
|
||||
|
||||
@ -272,9 +315,8 @@ public class GameDataService : IGameDataService
|
||||
|
||||
private void InitializePuchiTitles(ImmutableDictionary<string, WordListEntry> dict)
|
||||
{
|
||||
var costumePuchiMax = costumeFlagArraySizes[4];
|
||||
puchiTitles = new string[costumePuchiMax];
|
||||
for (var i = 0; i < costumePuchiMax; i++)
|
||||
puchiTitles = new string[puchiUniqueIdList.Max() + 1];
|
||||
foreach (var i in puchiUniqueIdList)
|
||||
{
|
||||
var key = $"costume_puchi_{i}";
|
||||
|
||||
@ -322,4 +364,39 @@ public class GameDataService : IGameDataService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<uint> GetLockedKigurumiUniqueIdList()
|
||||
{
|
||||
return lockedKigurumiUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedHeadUniqueIdList()
|
||||
{
|
||||
return lockedHeadUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedBodyUniqueIdList()
|
||||
{
|
||||
return lockedBodyUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedFaceUniqueIdList()
|
||||
{
|
||||
return lockedFaceUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedPuchiUniqueIdList()
|
||||
{
|
||||
return lockedPuchiUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedTitleUniqueIdList()
|
||||
{
|
||||
return lockedTitleUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedTitlePlateIdList()
|
||||
{
|
||||
return lockedTitlePlateIdList;
|
||||
}
|
||||
}
|
@ -27,7 +27,21 @@ public interface IGameDataService
|
||||
public string GetFaceTitle(uint index);
|
||||
public string GetPuchiTitle(uint index);
|
||||
|
||||
public List<int> GetCostumeFlagArraySizes();
|
||||
public List<uint> GetKigurumiUniqueIdList();
|
||||
public List<uint> GetHeadUniqueIdList();
|
||||
public List<uint> GetBodyUniqueIdList();
|
||||
public List<uint> GetFaceUniqueIdList();
|
||||
public List<uint> GetPuchiUniqueIdList();
|
||||
public List<uint> GetTitleUniqueIdList();
|
||||
public List<uint> GetTitlePlateIdList();
|
||||
|
||||
public List<uint> GetLockedKigurumiUniqueIdList();
|
||||
public List<uint> GetLockedHeadUniqueIdList();
|
||||
public List<uint> GetLockedBodyUniqueIdList();
|
||||
public List<uint> GetLockedFaceUniqueIdList();
|
||||
public List<uint> GetLockedPuchiUniqueIdList();
|
||||
public List<uint> GetLockedTitleUniqueIdList();
|
||||
public List<uint> GetLockedTitlePlateIdList();
|
||||
|
||||
public ImmutableHashSet<Title> GetTitles();
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Options;
|
||||
using TaikoWebUI.Settings;
|
||||
using Blazored.LocalStorage;
|
||||
|
||||
namespace TaikoWebUI.Services;
|
||||
|
||||
@ -15,9 +17,14 @@ public class LoginService
|
||||
public bool RegisterWithLastPlayTime { get; }
|
||||
public bool AllowUserDelete { get; }
|
||||
public bool AllowFreeProfileEditing { get; }
|
||||
|
||||
public LoginService(IOptions<WebUiSettings> settings)
|
||||
public bool IsLoggedIn { get; private set; }
|
||||
private User LoggedInUser { get; set; } = new();
|
||||
public bool IsAdmin { get; private set; }
|
||||
private readonly ILocalStorageService localStorage;
|
||||
|
||||
public LoginService(IOptions<WebUiSettings> settings, ILocalStorageService localStorage)
|
||||
{
|
||||
this.localStorage = localStorage;
|
||||
IsLoggedIn = false;
|
||||
IsAdmin = false;
|
||||
var webUiSettings = settings.Value;
|
||||
@ -28,131 +35,158 @@ public class LoginService
|
||||
AllowUserDelete = webUiSettings.AllowUserDelete;
|
||||
AllowFreeProfileEditing = webUiSettings.AllowFreeProfileEditing;
|
||||
}
|
||||
|
||||
public bool IsLoggedIn { get; private set; }
|
||||
private User LoggedInUser { get; set; } = new();
|
||||
public bool IsAdmin { get; private set; }
|
||||
|
||||
|
||||
protected virtual void OnLoginStatusChanged()
|
||||
{
|
||||
LoginStatusChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public int Login(string inputCardNum, string inputPassword, DashboardResponse response)
|
||||
public async Task<int> Login(string inputAccessCode, string inputPassword, HttpClient client)
|
||||
{
|
||||
// strip spaces or dashes from card number
|
||||
inputCardNum = inputCardNum.Replace(" ", "").Replace("-", "");
|
||||
inputAccessCode = inputAccessCode.Replace(" ", "").Replace("-", "").Replace(":", "");
|
||||
|
||||
foreach (var user in response.Users.Where(user => user.AccessCodes.Contains(inputCardNum)))
|
||||
var request = new LoginRequest
|
||||
{
|
||||
foreach (var userCredential in response.UserCredentials.Where(userCredential => userCredential.Baid == user.Baid))
|
||||
AccessCode = inputAccessCode,
|
||||
Password = inputPassword
|
||||
};
|
||||
|
||||
var responseMessage = await client.PostAsJsonAsync("api/Auth/Login", request);
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode)
|
||||
{
|
||||
// Unauthorized, extract specific error message as json
|
||||
var responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
var responseJson = JsonSerializer.Deserialize<Dictionary<string, string>>(responseContent);
|
||||
// Unknown error message
|
||||
if (responseJson is null) return 5;
|
||||
var errorMessage = responseJson["message"];
|
||||
return errorMessage switch
|
||||
{
|
||||
if (userCredential.Password == "") return 4;
|
||||
if (ComputeHash(inputPassword, userCredential.Salt) != userCredential.Password) return 2;
|
||||
IsAdmin = user.IsAdmin;
|
||||
if (!IsAdmin && OnlyAdmin) return 0;
|
||||
IsLoggedIn = true;
|
||||
LoggedInUser = user;
|
||||
|
||||
OnLoginStatusChanged();
|
||||
|
||||
return 1;
|
||||
}
|
||||
"Access Code Not Found" => 3,
|
||||
"User Not Registered" => 4,
|
||||
"Invalid Password" => 2,
|
||||
_ => 5
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Authorized, store Jwt token
|
||||
var responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
var responseJson = JsonSerializer.Deserialize<Dictionary<string, string>>(responseContent);
|
||||
if (responseJson is null) return 5;
|
||||
|
||||
var authToken = responseJson["authToken"];
|
||||
await localStorage.SetItemAsync("authToken", authToken);
|
||||
|
||||
return await LoginWithAuthToken(authToken, client) == false ? 5 : 1;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
public async Task<int> Register(string inputCardNum, DateTime inputDateTime, string inputPassword, string inputConfirmPassword,
|
||||
DashboardResponse response, HttpClient client)
|
||||
public async Task<bool> LoginWithAuthToken(string authToken, HttpClient client)
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var jwtSecurityToken = handler.ReadJwtToken(authToken);
|
||||
|
||||
// Check whether token is expired
|
||||
if (jwtSecurityToken.ValidTo < DateTime.UtcNow) return false;
|
||||
|
||||
var baid = jwtSecurityToken.Claims.First(claim => claim.Type == ClaimTypes.Name).Value;
|
||||
var isAdmin = jwtSecurityToken.Claims.First(claim => claim.Type == ClaimTypes.Role).Value == "Admin";
|
||||
|
||||
var response = await client.GetFromJsonAsync<DashboardResponse>("api/Dashboard");
|
||||
|
||||
var user = response?.Users.FirstOrDefault(u => u.Baid == uint.Parse(baid));
|
||||
if (user is null) return false;
|
||||
|
||||
IsLoggedIn = true;
|
||||
IsAdmin = isAdmin;
|
||||
LoggedInUser = user;
|
||||
OnLoginStatusChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<int> Register(string inputCardNum, DateTime inputDateTime, string inputPassword,
|
||||
string inputConfirmPassword,
|
||||
DashboardResponse response, HttpClient client, string inviteCode)
|
||||
{
|
||||
if (OnlyAdmin) return 0;
|
||||
|
||||
if (inputPassword != inputConfirmPassword) return 2;
|
||||
|
||||
// strip spaces or dashes from card number
|
||||
inputCardNum = inputCardNum.Replace(" ", "").Replace("-", "");
|
||||
inputCardNum = inputCardNum.Replace(" ", "").Replace("-", "").Replace(":", "");
|
||||
|
||||
foreach (var user in response.Users.Where(user => user.AccessCodes.Contains(inputCardNum)))
|
||||
var request = new RegisterRequest
|
||||
{
|
||||
foreach (var userCredential in response.UserCredentials.Where(userCredential => userCredential.Baid == user.Baid))
|
||||
{
|
||||
if (RegisterWithLastPlayTime)
|
||||
{
|
||||
var userSettingResponse = await client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{user.Baid}");
|
||||
if (userSettingResponse is null) return 3;
|
||||
var lastPlayDateTime = userSettingResponse.LastPlayDateTime;
|
||||
var diffMinutes = (inputDateTime - lastPlayDateTime).Duration().TotalMinutes;
|
||||
if (diffMinutes > 5) return 5;
|
||||
}
|
||||
if (userCredential.Password != "") return 4;
|
||||
if (inputPassword != inputConfirmPassword) return 2;
|
||||
var salt = CreateSalt();
|
||||
var request = new SetPasswordRequest
|
||||
{
|
||||
Baid = user.Baid,
|
||||
Password = ComputeHash(inputPassword, salt),
|
||||
Salt = salt
|
||||
};
|
||||
var responseMessage = await client.PostAsJsonAsync("api/Credentials", request);
|
||||
return responseMessage.IsSuccessStatusCode ? 1 : 3;
|
||||
}
|
||||
}
|
||||
AccessCode = inputCardNum,
|
||||
Password = inputPassword,
|
||||
RegisterWithLastPlayTime = RegisterWithLastPlayTime,
|
||||
LastPlayDateTime = inputDateTime,
|
||||
InviteCode = inviteCode
|
||||
};
|
||||
|
||||
return 3;
|
||||
var responseMessage = await client.PostAsJsonAsync("api/Auth/Register", request);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) return 1;
|
||||
|
||||
// Unauthorized, extract specific error message as json
|
||||
var responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
var responseJson = JsonSerializer.Deserialize<Dictionary<string, string>>(responseContent);
|
||||
// Unknown error message
|
||||
if (responseJson is null) return 6;
|
||||
var errorMessage = responseJson["message"];
|
||||
return errorMessage switch
|
||||
{
|
||||
"Access Code Not Found" => 3,
|
||||
"User Already Registered" => 4,
|
||||
"Wrong Last Play Time" => 5,
|
||||
_ => 6
|
||||
};
|
||||
}
|
||||
|
||||
private static string CreateSalt()
|
||||
{
|
||||
//Generate a cryptographic random number.
|
||||
var randomNumber = new byte[32];
|
||||
var rng = RandomNumberGenerator.Create();
|
||||
rng.GetBytes(randomNumber);
|
||||
var salt = Convert.ToBase64String(randomNumber);
|
||||
|
||||
// Return a Base64 string representation of the random number.
|
||||
return salt;
|
||||
}
|
||||
|
||||
private static string ComputeHash(string inputPassword, string salt)
|
||||
{
|
||||
var encDataByte = Encoding.UTF8.GetBytes(inputPassword + salt);
|
||||
var encodedData = Convert.ToBase64String(encDataByte);
|
||||
encDataByte = Encoding.UTF8.GetBytes(encodedData);
|
||||
encodedData = Convert.ToBase64String(encDataByte);
|
||||
encDataByte = Encoding.UTF8.GetBytes(encodedData);
|
||||
encodedData = Convert.ToBase64String(encDataByte);
|
||||
encDataByte = Encoding.UTF8.GetBytes(encodedData);
|
||||
encodedData = Convert.ToBase64String(encDataByte);
|
||||
return encodedData;
|
||||
}
|
||||
|
||||
public async Task<int> ChangePassword(string inputCardNum, string inputOldPassword, string inputNewPassword,
|
||||
|
||||
public async Task<int> ChangePassword(string inputAccessCode, string inputOldPassword, string inputNewPassword,
|
||||
string inputConfirmNewPassword, DashboardResponse response, HttpClient client)
|
||||
{
|
||||
if (OnlyAdmin) return 0;
|
||||
foreach (var user in response.Users.Where(user => user.AccessCodes.Contains(inputCardNum)))
|
||||
|
||||
if (inputNewPassword != inputConfirmNewPassword) return 2;
|
||||
|
||||
var request = new ChangePasswordRequest
|
||||
{
|
||||
foreach (var userCredential in response.UserCredentials.Where(userCredential => userCredential.Baid == user.Baid))
|
||||
{
|
||||
if (userCredential.Password != ComputeHash(inputOldPassword, userCredential.Salt)) return 4;
|
||||
if (inputNewPassword != inputConfirmNewPassword) return 2;
|
||||
var request = new SetPasswordRequest
|
||||
{
|
||||
Baid = user.Baid,
|
||||
Password = ComputeHash(inputNewPassword, userCredential.Salt),
|
||||
Salt = userCredential.Salt
|
||||
};
|
||||
var responseMessage = await client.PostAsJsonAsync("api/Credentials", request);
|
||||
return responseMessage.IsSuccessStatusCode ? 1 : 3;
|
||||
}
|
||||
}
|
||||
|
||||
return 3;
|
||||
AccessCode = inputAccessCode,
|
||||
OldPassword = inputOldPassword,
|
||||
NewPassword = inputNewPassword
|
||||
};
|
||||
|
||||
var responseMessage = await client.PostAsJsonAsync("api/Auth/ChangePassword", request);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode) return 1;
|
||||
|
||||
// Unauthorized, extract specific error message as json
|
||||
var responseContent = await responseMessage.Content.ReadAsStringAsync();
|
||||
var responseJson = JsonSerializer.Deserialize<Dictionary<string, string>>(responseContent);
|
||||
// Unknown error message
|
||||
if (responseJson is null) return 6;
|
||||
var errorMessage = responseJson["message"];
|
||||
return errorMessage switch
|
||||
{
|
||||
"Access Code Not Found" => 3,
|
||||
"User Not Registered" => 5,
|
||||
"Wrong Old Password" => 4,
|
||||
_ => 6
|
||||
};
|
||||
}
|
||||
|
||||
public void Logout()
|
||||
public async Task Logout()
|
||||
{
|
||||
IsLoggedIn = false;
|
||||
LoggedInUser = new User();
|
||||
IsAdmin = false;
|
||||
|
||||
// Clear JWT token
|
||||
await localStorage.RemoveItemAsync("authToken");
|
||||
OnLoginStatusChanged();
|
||||
}
|
||||
|
||||
@ -174,7 +208,7 @@ public class LoginService
|
||||
{
|
||||
if (inputAccessCode.Trim() == "") return 4; /*Empty access code*/
|
||||
if (!IsLoggedIn && LoginRequired) return 0; /*User not connected and login is required*/
|
||||
if (LoginRequired && !IsAdmin && !(user.Baid == GetLoggedInUser().Baid)) return 5; /*User not admin trying to update someone elses Access Codes*/
|
||||
if (LoginRequired && !IsAdmin && user.Baid != GetLoggedInUser().Baid) return 5; /*User not admin trying to update someone elses Access Codes*/
|
||||
if (user.AccessCodes.Count >= boundAccessCodeUpperLimit) return 2; /*Limit of codes has been reached*/
|
||||
var request = new BindAccessCodeRequest
|
||||
{
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
public class Title
|
||||
{
|
||||
public int TitleId { get; set; }
|
||||
public uint TitleId { get; set; }
|
||||
|
||||
public string TitleName { get; init; } = string.Empty;
|
||||
|
||||
|
@ -13,59 +13,61 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autocomplete.Clients" Version="1.1.0" />
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||
<PackageReference Include="CodeBeam.MudBlazor.Extensions" Version="6.5.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0-rc.1.23421.29" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0-rc.1.23421.29" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0-rc.1.23419.4" />
|
||||
<PackageReference Include="MudBlazor" Version="6.17.0" />
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||
<PackageReference Include="CodeBeam.MudBlazor.Extensions" Version="6.9.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.4" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
||||
<PackageReference Include="MudBlazor" Version="6.19.1" />
|
||||
<PackageReference Include="Otp.NET" Version="1.4.0" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageReference Include="Swan.Core" Version="7.0.0-beta.2" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedProject\SharedProject.csproj" />
|
||||
<ProjectReference Include="..\SharedProject\SharedProject.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\musicinfo.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\music_order.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\wordlist.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\music_order.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\musicinfo.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\wordlist.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\musicinfo.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\music_order.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\wordlist.bin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\music_order.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\musicinfo.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\data\datatable\wordlist.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\AccessCode.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\ChangePassword.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\DaniDojo.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Dashboard.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Dialogs\AccessCodeDeleteConfirmDialog.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Dialogs\ChooseTitleDialog.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Dialogs\UserDeleteConfirmDialog.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Dialogs\UserQrCodeDialog.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\HighScores.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Profile.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Register.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Users.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\AccessCode.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\ChangePassword.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\DaniDojo.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Dashboard.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Dialogs\AccessCodeDeleteConfirmDialog.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Dialogs\ChooseTitleDialog.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Dialogs\UserDeleteConfirmDialog.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Dialogs\UserQrCodeDialog.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\HighScores.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Profile.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Register.razor" />
|
||||
<_ContentIncludedByDefault Remove="Pages\Pages\Users.razor" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -80,8 +82,8 @@
|
||||
<CustomToolNamespace>LocalizationResource</CustomToolNamespace>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\LocalizationResource.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>LocalizationResource.Designer.cs</LastGenOutput>
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>LocalizationResource.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\LocalizationResource.ja.resx">
|
||||
<SubType>Designer</SubType>
|
||||
@ -89,20 +91,20 @@
|
||||
<CustomToolNamespace>LocalizationResource</CustomToolNamespace>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\LocalizationResource.zh-Hant.resx">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<CustomToolNamespace>LocalizationResource</CustomToolNamespace>
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<CustomToolNamespace>LocalizationResource</CustomToolNamespace>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Localization\LocalizationResource.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>LocalizationResource.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\LocalizationResource.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>LocalizationResource.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
</Project>
|
7
TaikoWebUI/wwwroot/css/bootstrap/bootstrap.min.css
vendored
Normal file
7
TaikoWebUI/wwwroot/css/bootstrap/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
TaikoWebUI/wwwroot/css/bootstrap/bootstrap.min.css.map
Normal file
1
TaikoWebUI/wwwroot/css/bootstrap/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
@ -14,30 +14,42 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="loader-container">
|
||||
<div class="linear-progress"></div>
|
||||
<div class="loading-text">
|
||||
Loading...
|
||||
</div>
|
||||
<div id="app">
|
||||
<div class="loader-container">
|
||||
<div class="linear-progress"></div>
|
||||
<div class="loading-text">
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
<script src="_framework/blazor.webassembly.js"></script>
|
||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
<script src="js/textFit.min.js"></script>
|
||||
<script src="js/updateTextFit.js"></script>
|
||||
<script>
|
||||
window.blazorCulture = {
|
||||
get: () => localStorage['BlazorCulture'],
|
||||
set: (value) => localStorage['BlazorCulture'] = value
|
||||
};
|
||||
</script>
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
<script src="_framework/blazor.webassembly.js"></script>
|
||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
<script src="js/textFit.min.js"></script>
|
||||
<script src="js/updateTextFit.js"></script>
|
||||
<script>
|
||||
window.blazorCulture = {
|
||||
get: () => localStorage['BlazorCulture'],
|
||||
set: (value) => localStorage['BlazorCulture'] = value
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
window.clipboardCopy = {
|
||||
copyText: function(text) {
|
||||
navigator.clipboard.writeText(text).then(function () {
|
||||
alert("Copied to clipboard!");
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error("Failed to copy text: ", error);
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user