Compare commits

...

10 commits

Author SHA1 Message Date
BOT Alex
16e364b133 Possible snackbar continues show fix bug fix 2023-08-27 06:34:49 +02:00
BOT Alex
8fec07b3d5 Doesn't skip if answered wrong 2023-08-27 06:30:02 +02:00
BOT Alex
46664fac59 Changed some UI and added changing fonts 2023-08-27 06:22:01 +02:00
BOT Alex
ec55964c46 Merge branch 'master' of https://github.com/MagicBOTAlex/CCharLearn 2023-08-24 23:28:45 +02:00
BOT Alex
801609d5e7 Patch: Continue not working 2023-08-24 23:28:30 +02:00
BOT Alex
59e30e5817 Fixed a resizing annoyence 2023-08-12 14:24:12 +02:00
BOT Alex
eabb06d90f Added multi-platform speech of cchars 2023-07-17 14:08:47 +08:00
BOT Alex
bcec11c238 Fixed a wrapping bug 2023-07-17 14:05:55 +08:00
BOT Alex
0df2079172 Disabled service worker because it messed somethings up 2023-07-14 21:25:33 +08:00
BOT Alex
026a7cf2c9 Recentered easymode checkbox 2023-07-14 21:09:46 +08:00
14 changed files with 160 additions and 30 deletions

View file

@ -10,6 +10,7 @@ namespace CCharLearn
{ {
public class Program public class Program
{ {
public static int CCharsLeft = 0; public static int CCharsLeft = 0;
public static Action UpdateUiEvent; public static Action UpdateUiEvent;
@ -24,7 +25,7 @@ namespace CCharLearn
{ {
config.SnackbarConfiguration.ShowTransitionDuration = 100; config.SnackbarConfiguration.ShowTransitionDuration = 100;
config.SnackbarConfiguration.HideTransitionDuration = 100; config.SnackbarConfiguration.HideTransitionDuration = 100;
config.SnackbarConfiguration.VisibleStateDuration = 5000; config.SnackbarConfiguration.VisibleStateDuration = 3000;
config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.TopCenter; config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.TopCenter;
}); });
builder.Services.AddBlazoredLocalStorage(); builder.Services.AddBlazoredLocalStorage();

View file

@ -14,7 +14,7 @@
<MudSelectItem T="int" Value="@i" /> <MudSelectItem T="int" Value="@i" />
} }
</MudSelect> </MudSelect>
<MudContainer Class="justify-center d-flex pt-4"> <MudContainer Class="justify-center d-flex pt-4" Style="width:300px">
<MudButton Variant="Variant.Filled" OnClick=StartLearning Color="Color.Primary">@((!continueDataExists) ? "Start learning!" : "Start new!")</MudButton> <MudButton Variant="Variant.Filled" OnClick=StartLearning Color="Color.Primary">@((!continueDataExists) ? "Start learning!" : "Start new!")</MudButton>
<MudStack Spacing="0" Class="pa-0 pl-2 ma-0"> <MudStack Spacing="0" Class="pa-0 pl-2 ma-0">
@if (continueDataExists) @if (continueDataExists)
@ -27,7 +27,7 @@
<MudIconButton Class="pa-0 ma-0" OnClick="DeleteContinueData" Variant=Variant.Filled Color="Color.Error" Icon="@Icons.Material.Filled.Close"></MudIconButton> <MudIconButton Class="pa-0 ma-0" OnClick="DeleteContinueData" Variant=Variant.Filled Color="Color.Error" Icon="@Icons.Material.Filled.Close"></MudIconButton>
</MudStack> </MudStack>
</MudContainer> </MudContainer>
<MudProgressLinear Class="pa-0 ma-0" Color="Color.Warning" Size="Size.Small" Value="@(((float)chunkSize/(float)continueCharectersLeft)*100)" /> <MudProgressLinear Class="pa-0 ma-0" Color="Color.Warning" Size="Size.Small" Value="@(((float)continueCharectersLeft/(float)chunkSize))" />
</MudStack> </MudStack>
</MudButton> </MudButton>
} }
@ -35,14 +35,20 @@
</MudContainer> </MudContainer>
<MudContainer Class="justify-center d-flex"> <MudContainer Class="justify-center d-flex">
<MudCheckBox @bind-Checked="@IsEasyMode" Label="Easy mode" Color="Color.Primary"></MudCheckBox> <MudStack Class="pt-4 " Spacing="0">
<MudContainer Class="pa-4">
<MudText Typo="Typo.h6" Class="fw-bold">Modifiers:</MudText>
<MudCheckBox Class="mr-6" @bind-Checked="@IgnoreTone" Label="Ignore pinyin tones" Color="Color.Primary"></MudCheckBox>
<MudCheckBox Class="mr-6" @bind-Checked="@UseChangingFonts" Label="Changing fonts" Color="Color.Primary"></MudCheckBox>
</MudContainer>
</MudStack>
</MudContainer> </MudContainer>
<MudContainer Class="pt-16 justify-center d-flex"> <MudContainer Class="pt-4 justify-center d-flex">
@if (Charecters != null) @if (Charecters != null)
{ {
<MudPaper Class="overflow-scroll rounded-0" Style="height: 50vh;" Elevation="1"> <MudPaper Class="overflow-scroll rounded-lg" Style="height: 40vh;" Elevation="1">
<MudDataGrid FixedHeader=true Items="@Charecters"> <MudDataGrid Style="" SortMode="SortMode.None" Height="500" FixedHeader=true Items="@Charecters" Breakpoint="Breakpoint.None">
<Columns> <Columns>
<PropertyColumn Property="x => x.charcter" Title="CChar" /> <PropertyColumn Property="x => x.charcter" Title="CChar" />
<PropertyColumn Property="x => x.pinyin" Title="Pinyin" /> <PropertyColumn Property="x => x.pinyin" Title="Pinyin" />
@ -90,18 +96,30 @@
bool continueDataExists = false; bool continueDataExists = false;
int continueCharectersLeft = -1; int continueCharectersLeft = -1;
private bool isEasyMode; private bool ignoreTone;
public bool IsEasyMode public bool IgnoreTone
{ {
get { return isEasyMode; } get { return ignoreTone; }
set set
{ {
isEasyMode = value; ignoreTone = value;
SetEasyMode(); SetIgnoreTone();
} }
} }
private bool useChangingFonts;
public bool UseChangingFonts
{
get { return useChangingFonts; }
set
{
useChangingFonts = value;
SetChangingFonts();
}
}
protected async override Task OnInitializedAsync() protected async override Task OnInitializedAsync()
@ -109,6 +127,8 @@
if (await localStorage.ContainKeyAsync("Normalized_chunk_001.json")) if (await localStorage.ContainKeyAsync("Normalized_chunk_001.json"))
isSavedLocally = true; isSavedLocally = true;
continueDataExists = await localStorage.ContainKeyAsync("ContinueData");
SelectedChunk(); SelectedChunk();
StateHasChanged(); StateHasChanged();
} }
@ -151,9 +171,14 @@
StateHasChanged(); StateHasChanged();
} }
async void SetEasyMode() async void SetIgnoreTone()
{ {
await localStorage.SetItemAsync("EasyMode", isEasyMode); await localStorage.SetItemAsync("IgnoreTone", ignoreTone);
}
async void SetChangingFonts()
{
await localStorage.SetItemAsync("ChangingFonts", UseChangingFonts);
} }
async Task LoadAllChunksIntoLocalStorage() async Task LoadAllChunksIntoLocalStorage()
@ -205,7 +230,7 @@
{ {
if (firstRender) if (firstRender)
{ {
continueDataExists = await localStorage.ContainKeyAsync("ContinueData");
} }
if (continueDataExists) if (continueDataExists)
@ -213,9 +238,14 @@
continueCharectersLeft = await localStorage.GetItemAsync<int>("ContinueCharectersLeft"); continueCharectersLeft = await localStorage.GetItemAsync<int>("ContinueCharectersLeft");
} }
if (await localStorage.ContainKeyAsync("EasyMode")) if (await localStorage.ContainKeyAsync("IgnoreTone"))
{ {
isEasyMode = await localStorage.GetItemAsync<bool>("EasyMode"); ignoreTone = await localStorage.GetItemAsync<bool>("IgnoreTone");
}
if (await localStorage.ContainKeyAsync("ChangingFonts"))
{
UseChangingFonts = await localStorage.GetItemAsync<bool>("ChangingFonts");
} }
} }
} }

View file

@ -42,7 +42,14 @@
<MudContainer Style="width: 100px; height: 100px" Class="pa-8 ma-4 d-flex justify-center align-center"> <MudContainer Style="width: 100px; height: 100px" Class="pa-8 ma-4 d-flex justify-center align-center">
@if (!Answers.Any(x => x == null)) @if (!Answers.Any(x => x == null))
{ {
<p class="LargeCharecter">@GetDisplayChar()</p> if (useChagingFonts)
{
<p class="LargeCharecter" style="font-family: '@currentFont';">@GetDisplayChar()</p>
}
else
{
<p class="LargeCharecter">@GetDisplayChar()</p>
}
} }
</MudContainer> </MudContainer>
</MudPaper> </MudPaper>
@ -55,7 +62,7 @@
@for (int i = 0; i < Answers.Length; i++) @for (int i = 0; i < Answers.Length; i++)
{ {
int buttonIndex = i; int buttonIndex = i;
<MudButton Class="PinyinButtons ma-3" <MudButton Class="PinyinButtons ma-3"
Variant="Variant.Outlined" Variant="Variant.Outlined"
@onclick="() => SelectButton(buttonIndex)" @onclick="() => SelectButton(buttonIndex)"
Color="@(Answers[buttonIndex].isSelected ? Color.Primary : Color.Default)"> Color="@(Answers[buttonIndex].isSelected ? Color.Primary : Color.Default)">
@ -80,21 +87,39 @@
{ {
<MudButton Disabled="@(!(Answers.Any(x=>x.isSelected)))" OnClick="Submit" Class="px-8 py-3" Variant="Variant.Filled" Size="Size.Large" Color="Color.Success" Style="font-size: 20px;"> Submit</MudButton> <MudButton Disabled="@(!(Answers.Any(x=>x.isSelected)))" OnClick="Submit" Class="px-8 py-3" Variant="Variant.Filled" Size="Size.Large" Color="Color.Success" Style="font-size: 20px;"> Submit</MudButton>
} }
@if (isEasyMode) @if (ignoreTone)
{ {
<MudText Typo="Typo.caption">• Easy mode enabled</MudText> <MudText Typo="Typo.caption">• Easy mode enabled</MudText>
} }
@if (useChagingFonts)
{
<MudText Typo="Typo.caption">• Changing fonts enabled</MudText>
}
</MudStack> </MudStack>
</MudContainer> </MudContainer>
</MudStack> </MudStack>
</MudContainer> </MudContainer>
@*Used to load all fonts into memory instead of loading from http each time*@
@if (useChagingFonts && !hasLoadedFontsToMemory)
{
@for (int i = 0; i < extraFonts.Length; i++)
{
<p style="font-family: '@extraFonts[i]';">i</p>
}
}
@code { @code {
bool isSavedLocally = false; bool isSavedLocally = false;
bool isEasyMode = false; bool ignoreTone = false;
bool selectedCorrect = false; bool selectedCorrect = false;
bool useChagingFonts = false;
string? currentFont = null;
string[] extraFonts = { "HanyiSentyRubber", "mini-jian-caocuyuan", "myoungheihk", "UnboundedSans", "wt064", "XiaolaiSC-Regular", "chinese1", "chinese2" };
bool hasLoadedFontsToMemory = false;
public Answer[] Answers = new Answer[4]; public Answer[] Answers = new Answer[4];
public void SelectButton(int selectedIndex) public void SelectButton(int selectedIndex)
{ {
@ -129,9 +154,14 @@
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
Program.UpdateUiEvent += OnUiUpdate; Program.UpdateUiEvent += OnUiUpdate;
if (await localStorage.ContainKeyAsync("EasyMode")) if (await localStorage.ContainKeyAsync("IgnoreTone"))
{ {
isEasyMode = await localStorage.GetItemAsync<bool>("EasyMode"); ignoreTone = await localStorage.GetItemAsync<bool>("IgnoreTone");
}
if (await localStorage.ContainKeyAsync("ChangingFonts"))
{
useChagingFonts = await localStorage.GetItemAsync<bool>("ChangingFonts");
} }
bool continueLast = bool continueLast =
@ -148,13 +178,21 @@
await LoadCharectersFromChunk(); await LoadCharectersFromChunk();
} }
if (isEasyMode) if (ignoreTone)
DontSkipTheseCChar.ForEach(x => x.cchar.pinyin = x.cchar.pinyin.Unidecode()); DontSkipTheseCChar.ForEach(x => x.cchar.pinyin = x.cchar.pinyin.Unidecode());
if (useChagingFonts)
{
ChangeFont();
}
Program.CCharsLeft = DontSkipTheseCChar.Count; Program.CCharsLeft = DontSkipTheseCChar.Count;
Program.InvokeUiUpdate(); Program.InvokeUiUpdate();
GenerateQuestion(); GenerateQuestion();
await Task.Delay(100);
hasLoadedFontsToMemory = true;
} }
async Task LoadCharectersFromChunk() async Task LoadCharectersFromChunk()
@ -234,6 +272,12 @@
navigator.NavigateTo(""); navigator.NavigateTo("");
} }
async void ChangeFont()
{
int randomIndex = Random.Shared.Next(0, extraFonts.Length);
currentFont = extraFonts[randomIndex];
}
async void Submit() async void Submit()
{ {
bool isCorrect = Answers.Any(x => x.isCorrect && x.isSelected); bool isCorrect = Answers.Any(x => x.isCorrect && x.isSelected);
@ -244,6 +288,7 @@
{ {
Snackbar.Add($"<b>Definition:</b> {correctCChar.definition}", Severity.Success, config => { config.VisibleStateDuration = 1000; }); Snackbar.Add($"<b>Definition:</b> {correctCChar.definition}", Severity.Success, config => { config.VisibleStateDuration = 1000; });
increaseCCharStat(GetCorrectCCharStats(), StatType.NumOfCorrects); increaseCCharStat(GetCorrectCCharStats(), StatType.NumOfCorrects);
ChangeFont();
} }
else else
{ {
@ -272,7 +317,18 @@
await SaveContinueData(); await SaveContinueData();
GenerateQuestion(); if (isCorrect)
{
GenerateQuestion();
}
else
{
foreach (var anwser in Answers)
{
anwser.isSelected = false;
}
StateHasChanged();
}
} }
async Task SaveContinueData() async Task SaveContinueData()
@ -363,7 +419,7 @@
public void ShowMeaning() public void ShowMeaning()
{ {
Snackbar.Add($"<b>Definition:</b> {GetCorrectCChar().definition}", Severity.Info); Snackbar.Add($"<b>Definition:</b> {GetCorrectCChar().definition}", Severity.Info, conf => conf.VisibleStateDuration = 1000);
} }
public void ShowPinyin() public void ShowPinyin()
@ -378,7 +434,7 @@
if (firstRender) if (firstRender)
{ {
// Gets chinese voice on windows or iphone. // Gets chinese voice on windows or iphone.
this.SpeechVoice = ((IEnumerable<SpeechSynthesisVoice>)(await this.SpeechSynthesis.GetVoicesAsync())).FirstOrDefault(v => v.Name.Contains("Yaoyao") || v.Name.Contains("Ting-Ting")); this.SpeechVoice = ((IEnumerable<SpeechSynthesisVoice>)(await this.SpeechSynthesis.GetVoicesAsync())).FirstOrDefault(v => v.Name.Contains("Yaoyao") || v.Name.Contains("Ting-Ting") || v.Name.ToLower().Contains("cn"));
this.StateHasChanged(); this.StateHasChanged();
} }
} }
@ -387,7 +443,7 @@
{ {
if (SpeechVoice == null) if (SpeechVoice == null)
{ {
Snackbar.Add("Couldn't play sound", Severity.Error); Snackbar.Add("Couldn't play sound.\nLikely reason: Chinese speech not installed", Severity.Error);
return; return;
} }

View file

@ -0,0 +1 @@


View file

@ -96,4 +96,46 @@ a, .btn-link {
} }
.loading-progress-text:after { .loading-progress-text:after {
content: var(--blazor-load-percentage-text, "Loading"); content: var(--blazor-load-percentage-text, "Loading");
} }
@font-face {
font-family: 'HanyiSentyRubber';
src: url(../fonts/HanyiSentyRubber.ttf) format('truetype');
}
@font-face {
font-family: 'mini-jian-caocuyuan';
src: url(../fonts/mini-jian-caocuyuan.ttf) format('truetype');
}
@font-face {
font-family: 'myoungheihk';
src: url(../fonts/myoungheihk.ttf) format('truetype');
}
@font-face {
font-family: 'UnboundedSans';
src: url(../fonts/UnboundedSans.ttf) format('truetype');
}
@font-face {
font-family: 'wt064';
src: url(../fonts/wt064.ttf) format('truetype');
}
@font-face {
font-family: 'XiaolaiSC-Regular';
src: url(../fonts/XiaolaiSC-Regular.ttf) format('truetype');
}
/*优设标题黑*/
@font-face {
font-family: 'chinese1';
src: url(../fonts/chinese1.ttf) format('truetype');
}
/*站酷仓耳渔阳体*/
@font-face {
font-family: 'chinese2';
src: url(../fonts/chinese2.ttf) format('truetype');
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -31,7 +31,7 @@
</div> </div>
<script src="_framework/blazor.webassembly.js"></script> <script src="_framework/blazor.webassembly.js"></script>
<script src="_content/MudBlazor/MudBlazor.min.js"></script> <script src="_content/MudBlazor/MudBlazor.min.js"></script>
<script>navigator.serviceWorker.register('service-worker.js');</script> <!--<script>navigator.serviceWorker.register('service-worker.js');</script>-->
</body> </body>
</html> </html>