diff --git a/MatrixUtils.Web/Pages/Dev/DevOptions.razor b/MatrixUtils.Web/Pages/Dev/DevOptions.razor
new file mode 100644
index 0000000..6ca0b53
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Dev/DevOptions.razor
@@ -0,0 +1,71 @@
+@page "/Dev/Options"
+@using ArcaneLibs.Extensions
+@using System.Text.Unicode
+@using System.Text
+@using System.Text.Json
+@inject NavigationManager NavigationManager
+@inject ILocalStorageService LocalStorage
+
+<PageTitle>Developer options</PageTitle>
+
+<h3>Rory&::MatrixUtils - Developer options</h3>
+<hr/>
+
+<p>
+ <span>Import local storage: </span>
+ <InputFile OnChange="ImportLocalStorage"></InputFile>
+</p>
+<p>
+ <span>Export local storage: </span>
+ <button @onclick="@ExportLocalStorage">Export</button>
+</p>
+
+@if (userSettings is not null) {
+ <InputCheckbox @bind-Value="@userSettings.DeveloperSettings.EnableLogViewers" @oninput="@LogStuff"></InputCheckbox>
+ <label> Enable log views</label>
+ <br/>
+ <InputCheckbox @bind-Value="@userSettings.DeveloperSettings.EnableConsoleLogging" @oninput="@LogStuff"></InputCheckbox>
+ <label> Enable console logging</label>
+ <br/>
+ <InputCheckbox @bind-Value="@userSettings.DeveloperSettings.EnablePortableDevtools" @oninput="@LogStuff"></InputCheckbox>
+ <label> Enable portable devtools</label>
+ <br/>
+}
+<br/>
+
+@code {
+
+ private RMUStorageWrapper.Settings? userSettings { get; set; }
+ protected override async Task OnInitializedAsync() {
+ // userSettings = await TieredStorage.DataStorageProvider.LoadObjectAsync<RMUStorageWrapper.Settings>("rmu.settings");
+
+ await base.OnInitializedAsync();
+ }
+
+ private async Task LogStuff() {
+ await Task.Delay(100);
+ Console.WriteLine($"Settings: {userSettings.ToJson()}");
+ await TieredStorage.DataStorageProvider.SaveObjectAsync("rmu.settings", userSettings);
+ }
+
+ private async Task ExportLocalStorage() {
+ var keys = await TieredStorage.DataStorageProvider.GetAllKeysAsync();
+ var data = new Dictionary<string, object>();
+ foreach (var key in keys) {
+ data.Add(key, await TieredStorage.DataStorageProvider.LoadObjectAsync<object>(key));
+ }
+ var dataUri = "data:application/json;base64,";
+ dataUri += Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(data)));
+ await JSRuntime.InvokeVoidAsync("window.open", dataUri, "_blank");
+ }
+
+ private async Task ImportLocalStorage(InputFileChangeEventArgs obj) {
+ if (obj.FileCount != 1) return;
+ var data = await JsonSerializer.DeserializeAsync<Dictionary<string, object>>(obj.File.OpenReadStream());
+ foreach (var (key, value) in data) {
+ await TieredStorage.DataStorageProvider.SaveObjectAsync(key, value);
+ }
+ NavigationManager.NavigateTo(NavigationManager.Uri, true, true);
+ }
+
+}
diff --git a/MatrixUtils.Web/Pages/Dev/DevUtilities.razor b/MatrixUtils.Web/Pages/Dev/DevUtilities.razor
new file mode 100644
index 0000000..a6a4a82
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Dev/DevUtilities.razor
@@ -0,0 +1,78 @@
+@page "/Dev/Utilities"
+@using System.Reflection
+@using ArcaneLibs.Extensions
+@using LibMatrix.Extensions
+@using LibMatrix.Homeservers
+@using MatrixUtils.Abstractions
+@inject ILocalStorageService LocalStorage
+@inject NavigationManager NavigationManager
+<h3>Debug Tools</h3>
+<hr/>
+@if (Rooms.Count == 0) {
+ <p>You are not in any rooms!</p>
+ @* <p>Loading progress: @checkedRoomCount/@totalRoomCount</p> *@
+}
+else {
+ <details>
+ <summary>Room List</summary>
+ @foreach (var room in Rooms) {
+ <a style="color: unset; text-decoration: unset;" href="/RoomStateViewer/@room.Replace('.', '~')">
+ <RoomListItem RoomInfo="@(new RoomInfo() { Room = hs.GetRoom(room) })" LoadData="true"></RoomListItem>
+ </a>
+ }
+ </details>
+}
+
+<details open>
+ <summary>Send GET request to URL</summary>
+ <div class="input-group">
+ <input type="text" class="form-control" @bind-value="GetRequestUrl" placeholder="URL">
+ <button class="btn btn-outline-secondary" type="button" @onclick="SendGetRequest">Send</button>
+ </div>
+ <br/>
+ <pre>@GetRequestResult</pre>
+</details>
+
+<div style="margin-bottom: 4em;"></div>
+<LogView></LogView>
+
+@code {
+ public List<string> Rooms { get; set; } = new();
+ public AuthenticatedHomeserverGeneric? hs { get; set; }
+
+ protected override async Task OnInitializedAsync() {
+ await base.OnInitializedAsync();
+ hs = await RMUStorage.GetCurrentSessionOrNavigate();
+ if (hs == null) return;
+ Rooms = (await hs.GetJoinedRooms()).Select(x => x.RoomId).ToList();
+ Console.WriteLine("Fetched joined rooms!");
+ }
+
+ //send req
+ string GetRequestUrl { get; set; } = "";
+ string GetRequestResult { get; set; } = "";
+
+ private async Task SendGetRequest() {
+ var httpClient = hs?.ClientHttpClient;
+ try {
+ var res = await httpClient.GetAsync(GetRequestUrl);
+ if (res.IsSuccessStatusCode) {
+ if (res.Content.Headers.ContentType.MediaType == "application/json")
+ GetRequestResult = (await res.Content.ReadFromJsonAsync<object>()).ToJson();
+ else
+ GetRequestResult = await res.Content.ReadAsStringAsync();
+ StateHasChanged();
+ return;
+ }
+ if (res.Content.Headers.ContentType.MediaType == "application/json")
+ GetRequestResult = $"Error: {res.StatusCode}\n" + (await res.Content.ReadFromJsonAsync<object>()).ToJson();
+ else
+ GetRequestResult = $"Error: {res.StatusCode}\n" + await res.Content.ReadAsStringAsync();
+ }
+ catch (Exception e) {
+ GetRequestResult = $"Error: {e}";
+ }
+ StateHasChanged();
+ }
+
+}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Dev/ModalTest.razor b/MatrixUtils.Web/Pages/Dev/ModalTest.razor
new file mode 100644
index 0000000..4a0487f
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Dev/ModalTest.razor
@@ -0,0 +1,88 @@
+@page "/Dev/ModalTest"
+@inject IJSRuntime JsRuntime
+<h3>ModalTest</h3>
+
+@foreach (var (key, value) in _windowInfos) {
+ @* <ModalWindow X="@value.X" Y="@value.Y" Title="@value.Title">@value.Content</ModalWindow> *@
+}
+@for (var i = 0; i < 5; i++) {
+ var i1 = i;
+ <ModalWindow X="@Random.Shared.Next(1400)" Y="@Random.Shared.Next(1000)" Title="@("Window " + i1)" OnCloseClicked="() => OnCloseClicked(i1)">
+ @for (var j = 0; j < i1; j++) {
+ <h1>@j</h1>
+ }
+ </ModalWindow>
+}
+
+@code {
+
+ private Dictionary<int, WindowInfo> _windowInfos = new();
+
+ private class WindowInfo {
+ public double X;
+ public double Y;
+ public string Title;
+ public RenderFragment Content;
+ }
+
+ protected override async Task OnInitializedAsync() {
+ double _x = 2;
+ double _xv = 20;
+ double _y = 0;
+ double multiplier = 1;
+
+ for (var i = 0; i < 200; i++) {
+ var i1 = i;
+ _windowInfos.Add(_windowInfos.Count, new WindowInfo {
+ X = _x,
+ Y = _y,
+ Title = "Win" + i1,
+ Content = builder => {
+ builder.OpenComponent<ModalWindow>(0);
+ builder.AddAttribute(1, "X", _x);
+ builder.AddAttribute(2, "Y", _y);
+ builder.AddAttribute(3, "Title", "Win" + i1);
+ builder.AddAttribute(4, "ChildContent", (RenderFragment)(builder2 => {
+ builder2.OpenElement(0, "h1");
+ builder2.AddContent(1, "Hello " + i1);
+ builder2.CloseElement();
+ }));
+ builder.CloseComponent();
+ }
+ });
+ //_x += _xv /= 1000/System.Math.Sqrt((double)_windowInfos.Count)*_windowInfos.Count.ToString().Length*multiplier;
+ _y += 20;
+ _x += 20;
+ var dimension = await JsRuntime.InvokeAsync<WindowDimension>("getWindowDimensions");
+ if (_x > dimension.Width - 100) _x %= dimension.Width - 100;
+ if (_y > dimension.Height - 50) {
+ _y %= dimension.Height - 50;
+ _xv = 20;
+ }
+ if (
+ (_windowInfos.Count < 10 && _windowInfos.Count % 2 == 0) ||
+ (_windowInfos.Count < 100 && _windowInfos.Count % 10 == 0) ||
+ (_windowInfos.Count < 1000 && _windowInfos.Count % 50 == 0) ||
+ (_windowInfos.Count < 10000 && _windowInfos.Count % 100 == 0)
+ ) {
+ StateHasChanged();
+ await Task.Delay(25);
+ }
+ if(_windowInfos.Count > 750) multiplier = 2;
+ if(_windowInfos.Count > 1500) multiplier = 3;
+
+ }
+
+ await base.OnInitializedAsync();
+ }
+
+ private void OnCloseClicked(int i1) {
+ Console.WriteLine("Close clicked on " + i1);
+ }
+
+ public class WindowDimension {
+ public int Width { get; set; }
+ public int Height { get; set; }
+ }
+
+}
|