Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ indent_size = 2
indent_size = 2

[*.{xaml}]
indent_size = 4
indent_size = 2
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
**/BundleArtifacts/
**/GeneratedArtifacts/
**/.vs/
**/.vscode/
# Ignore editor-local VSCode/VSCodium files, but commit the shared workspace
# config (issue #22: 2-space XAML for VSCodium).
**/.vscode/*
!.vscode/settings.json
!.vscode/extensions.json
*.user
*.suo
*.userosscache
Expand Down
7 changes: 7 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
// EditorConfig makes VSCodium honor .editorconfig (including 2-space XAML) for
// every file type, not just the [xml]/[xaml] overrides in settings.json.
"recommendations": [
"editorconfig.editorconfig"
]
}
13 changes: 13 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
// XAML is treated as XML by VSCodium. Force 2-space indentation and stop the
// editor from guessing indent width from file contents (issue #22).
"editor.detectIndentation": false,
"[xml]": {
"editor.tabSize": 2,
"editor.insertSpaces": true
},
"[xaml]": {
"editor.tabSize": 2,
"editor.insertSpaces": true
}
}
16 changes: 8 additions & 8 deletions App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PostXING.App.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
2 changes: 1 addition & 1 deletion AppShell.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
xmlns:views="clr-namespace:PostXING.App.Views"
x:Class="PostXING.App.AppShell"
Shell.FlyoutBehavior="Disabled">
<ShellContent Title="Open" ContentTemplate="{DataTemplate views:OpenPostPage}" Route="open" />
<ShellContent Title="Open" ContentTemplate="{DataTemplate views:OpenPostPage}" Route="open" />
</Shell>
7 changes: 3 additions & 4 deletions Platforms/Android/MainActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ namespace PostXING.App;
Theme = "@style/Maui.SplashTheme",
MainLauncher = true,
LaunchMode = LaunchMode.SingleTop,
// AdjustResize is kept as a hint, but target SDK 35+ edge-to-edge enforcement defeats it: the
// window no longer shrinks for the soft keyboard. So EditorPage reads the IME inset natively and
// pushes it into the editor JS, which sizes the editor above the keyboard (GH #39). Harmless
// where AdjustResize still works.
// AdjustResize so the soft keyboard shrinks the WebView viewport instead of panning the
// window up; CodeMirror inside the editor then auto-scrolls the cursor into view. Without
// this the keyboard can sit on top of the last few lines of text.
WindowSoftInputMode = SoftInput.AdjustResize,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
Expand Down
8 changes: 4 additions & 4 deletions Platforms/Windows/App.xaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<maui:MauiWinUIApplication
x:Class="PostXING.App.WinUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:maui="using:Microsoft.Maui">
x:Class="PostXING.App.WinUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:maui="using:Microsoft.Maui">
</maui:MauiWinUIApplication>
47 changes: 8 additions & 39 deletions Resources/Raw/editor/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -749,30 +749,20 @@
setCaretOffset(editor, offset);
}

// Keep the editor sized to the actual visible area above the Android soft keyboard. The visual
// viewport does NOT shrink for the soft keyboard on the Android WebView (measured: innerHeight,
// visualViewport.height and this var all stay full-height whether the keyboard is up or down), so
// the JS can't detect the keyboard on its own. Instead the Android host reads the IME inset
// natively and pushes it here (in device px) via setKeyboardInsetPx; we subtract it from
// innerHeight. On Windows hostInsetPx stays 0 and we use the visual viewport height unchanged
// (there's no soft keyboard to exclude there).
let hostInsetPx = 0; // soft-keyboard height in *device* px, pushed by the Android host (0 = hidden)
// Keep the editor sized to the visual viewport (the actual visible area, excluding the
// Android soft keyboard). Without this, AdjustResize doesn't always shrink the WebView's
// layout viewport, and content scrolls "off the bottom" behind the keyboard.
function syncEditorHeight() {
let h;
if (hostInsetPx > 0) {
const dpr = window.devicePixelRatio || 1;
h = Math.max(120, window.innerHeight - hostInsetPx / dpr);
} else {
h = window.visualViewport ? window.visualViewport.height : window.innerHeight;
}
document.documentElement.style.setProperty('--vv-h', h + 'px');
const vv = window.visualViewport;
if (!vv) return;
document.documentElement.style.setProperty('--vv-h', vv.height + 'px');
}
syncEditorHeight();
if (window.visualViewport) {
window.visualViewport.addEventListener('resize', () => {
syncEditorHeight();
// Once the new height is applied, bring the caret back into view; a frame's delay so the
// height has taken effect and the rects are fresh.
// Once the keyboard finishes appearing, bring the caret back into view; a frame's
// delay so the new height has been applied and rects are fresh.
requestAnimationFrame(scrollCaretIntoView);
});
}
Expand Down Expand Up @@ -853,19 +843,6 @@
scheduleOutgoing();
});

// Keep the caret visible as it moves — typing, newlines, arrows, taps — regardless of IME
// composition state. The input handler above defers to compositionend while composing, which
// would otherwise let the caret slide behind the keyboard mid-word; selectionchange fires on
// every caret move, so it covers that gap. Throttled to one frame.
let caretScrollScheduled = false;
document.addEventListener('selectionchange', () => {
if (caretScrollScheduled) return;
const sel = window.getSelection();
if (!sel || !sel.rangeCount || !editor.contains(sel.anchorNode)) return;
caretScrollScheduled = true;
requestAnimationFrame(() => { caretScrollScheduled = false; scrollCaretIntoView(); });
});

// Paste as plain text (strip styles from the OS clipboard).
editor.addEventListener('paste', (e) => {
e.preventDefault();
Expand Down Expand Up @@ -932,14 +909,6 @@
focus() {
editor.focus();
},
// Android host -> JS: the soft-keyboard height in device px (0 when hidden). The visual viewport
// doesn't shrink for the keyboard on the Android WebView, so this is the only reliable signal;
// we resize the editor to the visible area above the keyboard and pull the caret back into view.
setKeyboardInsetPx(px) {
hostInsetPx = (typeof px === 'number' && px > 0) ? px : 0;
syncEditorHeight();
requestAnimationFrame(scrollCaretIntoView);
},
getText() {
return editor.innerText;
},
Expand Down
76 changes: 38 additions & 38 deletions Resources/Styles/Colors.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,43 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

<!-- Blue Fenix brand tokens. Mirrors bluefenix.net/DESIGN.md. -->

<!-- Interactive accents -->
<Color x:Key="PhoenixBlue">#1E5BFF</Color>
<Color x:Key="PhoenixBlueHover">#4D7DFF</Color>
<Color x:Key="PhoenixBlueDeep">#0A2BC2</Color>
<Color x:Key="SignalCyan">#06B6D4</Color>
<Color x:Key="SignalCyanDeep">#0E7490</Color>
<Color x:Key="ForgeAmber">#E08A2E</Color>
<Color x:Key="ForgeAmberHover">#D97706</Color>
<Color x:Key="ForgeAmberDeep">#B25C00</Color>

<!-- Reserved historical -->
<Color x:Key="Ember">#7F170E</Color>

<!-- Ink stack (dark surfaces, tinted toward brand hue) -->
<Color x:Key="Ink1000">#08081A</Color>
<Color x:Key="Ink950">#0F0F1F</Color>
<Color x:Key="Ink850">#1A1A2E</Color>
<Color x:Key="Ink700">#2D2D4A</Color>

<!-- Paper stack (light surfaces and foregrounds) -->
<Color x:Key="Paper100">#FFFFFF</Color>
<Color x:Key="Paper300">#E5E7EB</Color>
<Color x:Key="Paper500">#9095A4</Color>
<Color x:Key="Paper600">#6B7080</Color>

<!-- Status -->
<Color x:Key="Success">#10B981</Color>
<Color x:Key="Warning">#F59E0B</Color>
<Color x:Key="Danger">#EF4444</Color>

<!-- Scrim (single value, both themes; spec calls for rgba(0,0,0,0.55)) -->
<Color x:Key="Scrim">#8C000000</Color>

<!-- Theme-resolved divider aliases (used by the implicit Hairline style). -->
<Color x:Key="DividerDark">#2D2D4A</Color>
<Color x:Key="DividerLight">#E5E7EB</Color>
<!-- Blue Fenix brand tokens. Mirrors bluefenix.net/DESIGN.md. -->

<!-- Interactive accents -->
<Color x:Key="PhoenixBlue">#1E5BFF</Color>
<Color x:Key="PhoenixBlueHover">#4D7DFF</Color>
<Color x:Key="PhoenixBlueDeep">#0A2BC2</Color>
<Color x:Key="SignalCyan">#06B6D4</Color>
<Color x:Key="SignalCyanDeep">#0E7490</Color>
<Color x:Key="ForgeAmber">#E08A2E</Color>
<Color x:Key="ForgeAmberHover">#D97706</Color>
<Color x:Key="ForgeAmberDeep">#B25C00</Color>

<!-- Reserved historical -->
<Color x:Key="Ember">#7F170E</Color>

<!-- Ink stack (dark surfaces, tinted toward brand hue) -->
<Color x:Key="Ink1000">#08081A</Color>
<Color x:Key="Ink950">#0F0F1F</Color>
<Color x:Key="Ink850">#1A1A2E</Color>
<Color x:Key="Ink700">#2D2D4A</Color>

<!-- Paper stack (light surfaces and foregrounds) -->
<Color x:Key="Paper100">#FFFFFF</Color>
<Color x:Key="Paper300">#E5E7EB</Color>
<Color x:Key="Paper500">#9095A4</Color>
<Color x:Key="Paper600">#6B7080</Color>

<!-- Status -->
<Color x:Key="Success">#10B981</Color>
<Color x:Key="Warning">#F59E0B</Color>
<Color x:Key="Danger">#EF4444</Color>

<!-- Scrim (single value, both themes; spec calls for rgba(0,0,0,0.55)) -->
<Color x:Key="Scrim">#8C000000</Color>

<!-- Theme-resolved divider aliases (used by the implicit Hairline style). -->
<Color x:Key="DividerDark">#2D2D4A</Color>
<Color x:Key="DividerLight">#E5E7EB</Color>

</ResourceDictionary>
Loading
Loading