Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resizable fonts, some minor tabs fixes #42

Merged
merged 8 commits into from
Oct 28, 2023
Next Next commit
Implement resizable font settings for the page view BubbleID #28
aschuhardt committed Oct 28, 2023
commit e93ed0217a90cb3391dfd283fbcd6d33d9b1a8e7
105 changes: 105 additions & 0 deletions Database/SettingsDatabase.cs
Original file line number Diff line number Diff line change
@@ -26,6 +26,13 @@ internal class SettingsDatabase : ISettingsDatabase
private TabSide? _tabSide;
private bool? _tabsEnabled;
private bool? _swipeEnabled;
private int? _customFontSizeText;
private int? _customFontSizeH1;
private int? _customFontSizeH2;
private int? _customFontSizeH3;
private bool? _useCustomFontSize;
private string _customCss;
private bool? _useCustomCss;

public SettingsDatabase(ILogger<SettingsDatabase> logger, SQLiteConnection database)
{
@@ -224,6 +231,104 @@ public bool SwipeEnabled
}
}

public int CustomFontSizeText
{
get
{
_customFontSizeText ??= GetIntValue(16);
return _customFontSizeText.GetValueOrDefault();
}
set
{
if (SetField(ref _customFontSizeText, value))
SetIntValue(value);
}
}

public int CustomFontSizeH1
{
get
{
_customFontSizeH1 ??= GetIntValue(24);
return _customFontSizeH1.GetValueOrDefault();
}
set
{
if (SetField(ref _customFontSizeH1, value))
SetIntValue(value);
}
}

public int CustomFontSizeH2
{
get
{
_customFontSizeH2 ??= GetIntValue(20);
return _customFontSizeH2.GetValueOrDefault();
}
set
{
if (SetField(ref _customFontSizeH2, value))
SetIntValue(value);
}
}

public int CustomFontSizeH3
{
get
{
_customFontSizeH3 ??= GetIntValue(18);
return _customFontSizeH3.GetValueOrDefault();
}
set
{
if (SetField(ref _customFontSizeH3, value))
SetIntValue(value);
}
}

public bool UseCustomFontSize
{
get
{
_useCustomFontSize ??= GetBoolValue(false);
return _useCustomFontSize.GetValueOrDefault();
}
set
{
if (SetField(ref _useCustomFontSize, value))
SetBoolValue(value);
}
}

public bool UseCustomCss
{
get
{
_useCustomCss ??= GetBoolValue(false);
return _useCustomCss.GetValueOrDefault();
}
set
{
if (SetField(ref _useCustomCss, value))
SetBoolValue(value);
}
}

public string CustomCss
{
get
{
_customCss ??= GetStringValue();
return _customCss;
}
set
{
if (SetField(ref _customCss, value))
SetStringValue(value);
}
}

private void SetBoolValue(bool? value, [CallerMemberName] string name = null)
{
if (name == null)
7 changes: 7 additions & 0 deletions Interfaces/ISettingsDatabase.cs
Original file line number Diff line number Diff line change
@@ -18,4 +18,11 @@ public interface ISettingsDatabase : INotifyPropertyChanged
TabSide TabSide { get; set; }
bool TabsEnabled { get; set; }
bool SwipeEnabled { get; set; }
bool UseCustomFontSize { get; set; }
string CustomCss { get; set; }
int CustomFontSizeText { get; set; }
int CustomFontSizeH1 { get; set; }
int CustomFontSizeH2 { get; set; }
int CustomFontSizeH3 { get; set; }
bool UseCustomCss { get; set; }
}
89 changes: 83 additions & 6 deletions Services/Document/DocumentService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text;
using System.ComponentModel;
using System.Text;
using System.Web;
using HtmlAgilityPack;
using Microsoft.Extensions.Logging;
@@ -19,6 +20,9 @@ internal class DocumentService : IDocumentService
private readonly ILogger<DocumentService> _logger;
private readonly List<Task> _parallelRenderWorkload;
private readonly ISettingsDatabase _settingsDatabase;
private HtmlNode _customCssNode;
private HtmlNode _themeLinkNode;
private HtmlNode _fontSizeNode;
private HtmlNode _templateNode;

public DocumentService(ISettingsDatabase settingsDatabase, ICacheService cache, ILogger<DocumentService> logger)
@@ -28,13 +32,23 @@ public DocumentService(ISettingsDatabase settingsDatabase, ICacheService cache,
_logger = logger;

_parallelRenderWorkload = new List<Task>();

_themeLinkNode = BuildThemeLinkNode();

if (_settingsDatabase.UseCustomCss)
_customCssNode = BuildCustomCssNode();

if (_settingsDatabase.UseCustomFontSize)
_fontSizeNode = BuildCustomFontSizeNode();

_settingsDatabase.PropertyChanged += SettingChanged;
}

public HtmlDocument CreateEmptyDocument()
{
var document = new HtmlDocument();
document.DocumentNode.CopyFrom(_templateNode, true);
InjectStylesheet(document);
InjectStyleElements(document);
return document;
}

@@ -46,7 +60,10 @@ public HtmlDocument LoadFromBuffer(Stream buffer)
// remove the old injected stylesheet so that the new one can be used
document.DocumentNode.Descendants("link").FirstOrDefault(n => n.HasClass("injected-stylesheet"))?.Remove();

InjectStylesheet(document);
foreach (var node in document.DocumentNode.Descendants("style"))
node.Remove();

InjectStyleElements(document);
return document;
}

@@ -137,11 +154,71 @@ public async Task<RenderedGemtextDocument> RenderGemtextAsHtml(GemtextResponse g
return new RenderedGemtextDocument { HtmlContents = document.DocumentNode.OuterHtml, Title = title };
}

private void InjectStylesheet(HtmlDocument document)
private void SettingChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(ISettingsDatabase.Theme):
_themeLinkNode = BuildThemeLinkNode();
break;
case nameof(ISettingsDatabase.CustomCss):
if (_settingsDatabase.UseCustomCss)
_customCssNode = BuildCustomCssNode();
break;
case nameof(ISettingsDatabase.CustomFontSizeText):
case nameof(ISettingsDatabase.CustomFontSizeH1):
case nameof(ISettingsDatabase.CustomFontSizeH2):
case nameof(ISettingsDatabase.CustomFontSizeH3):
if (_settingsDatabase.UseCustomFontSize)
_fontSizeNode = BuildCustomFontSizeNode();
break;
}
}

private void InjectStyleElements(HtmlDocument document)
{
var head = document.DocumentNode.ChildNodes.FindFirst("head");
head?.AppendChild(HtmlNode.CreateNode(
$"<link rel=\"stylesheet\" class=\"injected-stylesheet\" href=\"Themes/{_settingsDatabase.Theme}.css\" media=\"screen\" />"));
if (head == null)
return;

head.AppendChild(_themeLinkNode);

if (_settingsDatabase.UseCustomFontSize)
{
_fontSizeNode ??= BuildCustomFontSizeNode();
head.AppendChild(_fontSizeNode);
}

if (_settingsDatabase.UseCustomCss)
{
_customCssNode ??= BuildCustomCssNode();
head.AppendChild(_customCssNode);
}
}

private HtmlNode BuildThemeLinkNode()
{
return HtmlNode.CreateNode("<link rel=\"stylesheet\" class=\"injected-stylesheet\" " +
$"href=\"Themes/{_settingsDatabase.Theme}.css\" media=\"screen\" />");
}

private HtmlNode BuildCustomCssNode()
{
return HtmlNode.CreateNode($"<style class=\"custom-css\">{_settingsDatabase.CustomCss}</style>");
}

private HtmlNode BuildCustomFontSizeNode()
{
var textSize = _settingsDatabase.CustomFontSizeText;
var h1Size = _settingsDatabase.CustomFontSizeH1;
var h2Size = _settingsDatabase.CustomFontSizeH2;
var h3Size = _settingsDatabase.CustomFontSizeH3;
return HtmlNode.CreateNode("<style class=\"custom-fontsize\">" +
$"body {{ font-size: {textSize}px; }} " +
$"h1 {{ font-size: {h1Size}px; }} " +
$"h2 {{ font-size: {h2Size}px; }} " +
$"h3 {{ font-size: {h3Size}px; }} " +
"</style>");
}

private static async Task<MemoryStream> CreateInlinedImagePreview(Stream source, string mimetype)
81 changes: 65 additions & 16 deletions Views/SettingsPage.xaml
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
xmlns:views="clr-namespace:RosyCrow.Views"
xmlns:localization="clr-namespace:RosyCrow.Resources.Localization"
xmlns:models="clr-namespace:RosyCrow.Models"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="RosyCrow.Views.SettingsPage"
x:DataType="views:SettingsPage"
Title="{x:Static localization:Text.SettingsPage_Title}"
@@ -38,21 +39,52 @@
<Label Text="Show tabs" Grid.Column="0" VerticalTextAlignment="Center" />
<Switch IsToggled="{Binding TabsEnabled}" Grid.Column="1" />
</Grid>
<toolkit:Expander IsExpanded="{Binding TabsEnabled}">
<VerticalStackLayout>
<Grid ColumnDefinitions="*,Auto">
<Label Text="Tab button side" Grid.Column="0" VerticalTextAlignment="Center" />
<Picker SelectedItem="{Binding TabSide}" Grid.Column="1" IsEnabled="{Binding TabsEnabled}">
<Picker.ItemsSource>
<x:Array Type="{x:Type models:TabSide}">
<models:TabSide>Right</models:TabSide>
<models:TabSide>Left</models:TabSide>
</x:Array>
</Picker.ItemsSource>
</Picker>
</Grid>
<Grid ColumnDefinitions="*,Auto">
<Label Text="Swipe to move between tabs" Grid.Column="0" VerticalTextAlignment="Center" />
<Switch IsToggled="{Binding EnableSwipe}" IsEnabled="{Binding TabsEnabled}" Grid.Column="1" />
</Grid>
</VerticalStackLayout>
</toolkit:Expander>
<Grid ColumnDefinitions="*,Auto">
<Label Text="Swipe to move between tabs" Grid.Column="0" VerticalTextAlignment="Center" />
<Switch IsToggled="{Binding EnableSwipe}" IsEnabled="{Binding TabsEnabled}" Grid.Column="1" />
</Grid>
<Grid ColumnDefinitions="*,Auto">
<Label Text="Tab button side" Grid.Column="0" VerticalTextAlignment="Center" />
<Picker SelectedItem="{Binding TabSide}" Grid.Column="1" IsEnabled="{Binding TabsEnabled}">
<Picker.ItemsSource>
<x:Array Type="{x:Type models:TabSide}">
<models:TabSide>Right</models:TabSide>
<models:TabSide>Left</models:TabSide>
</x:Array>
</Picker.ItemsSource>
</Picker>
<Label Text="Use a custom font size" Grid.Column="0" VerticalTextAlignment="Center" />
<Switch IsToggled="{Binding UseCustomFontSize}" IsEnabled="{Binding TabsEnabled}" Grid.Column="1" />
</Grid>
<toolkit:Expander IsExpanded="{Binding UseCustomFontSize}" Padding="8,0,0,0">
<VerticalStackLayout>
<Label Text="Font Sizes" />
<Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="Auto,Auto,Auto,Auto">
<!-- This syntax sucks -->
<Label Text="Body" Grid.Column="0" Grid.Row="0" VerticalTextAlignment="Center" />
<Slider Value="{Binding CustomFontSizeText}" Minimum="8" Maximum="72" Grid.Column="1" Grid.Row="0" />
<Label Text="{Binding CustomFontSizeText}" Grid.Column="2" Grid.Row="0" />

<Label Text="Heading 1" Grid.Column="0" Grid.Row="1" VerticalTextAlignment="Center" />
<Slider Value="{Binding CustomFontSizeH1}" Minimum="8" Maximum="72" Grid.Column="1" Grid.Row="1" />
<Label Text="{Binding CustomFontSizeH1}" Grid.Column="2" Grid.Row="1" />

<Label Text="Heading 2" Grid.Column="0" Grid.Row="2" VerticalTextAlignment="Center" />
<Slider Value="{Binding CustomFontSizeH2}" Minimum="8" Maximum="72" Grid.Column="1" Grid.Row="2" />
<Label Text="{Binding CustomFontSizeH2}" Grid.Column="2" Grid.Row="2" />

<Label Text="Heading 3" Grid.Column="0" VerticalTextAlignment="Center" Grid.Row="3" />
<Slider Value="{Binding CustomFontSizeH3}" Minimum="8" Maximum="72" Grid.Column="1" Grid.Row="3" />
<Label Text="{Binding CustomFontSizeH3}" Grid.Column="2" Grid.Row="3" />
</Grid>
</VerticalStackLayout>
</toolkit:Expander>
<Grid ColumnDefinitions="*,Auto">
<Label Text="{x:Static localization:Text.SettingsPage_Theme}" Grid.Column="0" VerticalOptions="Center" />
<!-- ReSharper disable once Xaml.BindingWithContextNotResolved -->
@@ -61,14 +93,31 @@
VerticalOptions="Center"
ItemsSource="{Binding Choices}"
ItemDisplayBinding="{Binding Path=Name}"
SelectedItem="{Binding SelectedTheme}"
SelectedIndexChanged="Picker_OnSelectedIndexChanged" />
SelectedItem="{Binding SelectedTheme}" />
</Grid>
<WebView
x:Name="ThemePreviewBrowser" HeightRequest="400" Margin="4,16"
SemanticProperties.Description="{x:Static localization:Text.SettingsPage_Preview}"
SemanticProperties.Hint="{x:Static localization:Text.SettingsPage_PreviewHint}"
Navigating="ThemePreviewBrowser_OnNavigating"/>
Navigating="ThemePreviewBrowser_OnNavigating" />
<!-- TODO: flesh-out custom CSS eventually -->
<!-- <Grid ColumnDefinitions="*,Auto"> -->
<!-- <Label Text="Use custom CSS" Grid.Column="0" VerticalTextAlignment="Center" /> -->
<!-- <Switch IsToggled="{Binding UseCustomCss}" Grid.Column="1" /> -->
<!-- </Grid> -->
<!-- <toolkit:Expander IsExpanded="{Binding UseCustomCss}"> -->
<!-- <VerticalStackLayout> -->
<!-- <Grid ColumnDefinitions="*,Auto,Auto"> -->
<!-- <Label Text="Custom CSS" Grid.Column="0" VerticalTextAlignment="Center" /> -->
<!-- <Button Text="Load" Grid.Column="1" /> -->
<!-- <Button Text="Save" Grid.Column="2" /> -->
<!-- </Grid> -->
<!-- <Border> -->
<!-- <Editor Text="{Binding CustomCss}" AutoSize="TextChanges" VerticalTextAlignment="Start" -->
<!-- HeightRequest="64" Placeholder="body { background: black; }" /> -->
<!-- </Border> -->
<!-- </VerticalStackLayout> -->
<!-- </toolkit:Expander> -->
<Button Text="{x:Static localization:Text.SettingsPage_ExportErrorLogs}" Command="{Binding ExportLogs}" />
<Button Text="{x:Static localization:Text.SettingsPage_WhatsNew}" Command="{Binding OpenWhatsNew}" />
<Button Text="{x:Static localization:Text.SettingsPage_About}" Command="{Binding OpenAbout}" />
Loading