|
37 | 37 | IsVisible="{Binding HasError}" /> |
38 | 38 |
|
39 | 39 | <!-- The public link. Bound, never captured once: a free tunnel hands out a new |
40 | | - address on every reconnect, and a phone reconnects whenever the network does. --> |
| 40 | + address on every reconnect, and a phone reconnects whenever the network does. |
| 41 | + Tappable, like every address below it: it opens in the system browser, which |
| 42 | + is the one Handoff advertises — so the page carries over to the Mac. --> |
41 | 43 | <Label Text="Public link" TextColor="Gray" Margin="0,6,0,0" /> |
42 | 44 | <Label Text="{Binding PublicUrl, TargetNullValue='Not shared yet'}" |
43 | | - LineBreakMode="CharacterWrap" /> |
| 45 | + TextColor="{StaticResource Primary}" |
| 46 | + TextDecorations="Underline" |
| 47 | + LineBreakMode="CharacterWrap"> |
| 48 | + <Label.GestureRecognizers> |
| 49 | + <TapGestureRecognizer Command="{Binding OpenUrlCommand}" |
| 50 | + CommandParameter="{Binding PublicUrl}" /> |
| 51 | + </Label.GestureRecognizers> |
| 52 | + </Label> |
44 | 53 |
|
45 | 54 | <Label Text="On this network" TextColor="Gray" Margin="0,6,0,0" /> |
46 | 55 | <Label Text="{Binding LocalUrl, TargetNullValue='Server not started'}" |
47 | | - LineBreakMode="CharacterWrap" /> |
| 56 | + TextColor="{StaticResource Primary}" |
| 57 | + TextDecorations="Underline" |
| 58 | + LineBreakMode="CharacterWrap"> |
| 59 | + <Label.GestureRecognizers> |
| 60 | + <TapGestureRecognizer Command="{Binding OpenUrlCommand}" |
| 61 | + CommandParameter="{Binding LocalUrl}" /> |
| 62 | + </Label.GestureRecognizers> |
| 63 | + </Label> |
48 | 64 |
|
49 | 65 | <!-- The MCP endpoint, for pasting into an AI client. Same server, same password. --> |
50 | 66 | <Label Text="MCP endpoint" TextColor="Gray" Margin="0,6,0,0" /> |
51 | 67 | <Label Text="{Binding McpUrl, TargetNullValue='Server not started'}" |
52 | 68 | LineBreakMode="CharacterWrap" /> |
53 | 69 |
|
54 | | - <!-- The WebDAV mount. Finder: Go → Connect to Server. Explorer: Map network |
55 | | - drive. Same server, same password — the app's storage as a drive. --> |
56 | | - <Label Text="WebDAV mount" TextColor="Gray" Margin="0,6,0,0" /> |
57 | | - <Label Text="{Binding WebDavUrl, TargetNullValue='Server not started'}" |
58 | | - LineBreakMode="CharacterWrap" /> |
| 70 | + <!-- The WebDAV mount, both ways to reach it. Finder: Go → Connect to Server. |
| 71 | + Explorer: Map network drive. Same server, same password — the app's storage |
| 72 | + as a drive. Tapping either one browses the mount here instead: GET on a |
| 73 | + collection returns an HTML listing whose links walk the whole tree. --> |
| 74 | + <Label Text="WebDAV mount — on this network" TextColor="Gray" Margin="0,6,0,0" /> |
| 75 | + <Label Text="{Binding LocalWebDavUrl, TargetNullValue='Server not started'}" |
| 76 | + TextColor="{StaticResource Primary}" |
| 77 | + TextDecorations="Underline" |
| 78 | + LineBreakMode="CharacterWrap"> |
| 79 | + <Label.GestureRecognizers> |
| 80 | + <TapGestureRecognizer Command="{Binding OpenUrlCommand}" |
| 81 | + CommandParameter="{Binding LocalWebDavUrl}" /> |
| 82 | + </Label.GestureRecognizers> |
| 83 | + </Label> |
| 84 | + |
| 85 | + <Label Text="WebDAV mount — public" TextColor="Gray" Margin="0,6,0,0" /> |
| 86 | + <Label Text="{Binding PublicWebDavUrl, TargetNullValue='Not shared yet'}" |
| 87 | + TextColor="{StaticResource Primary}" |
| 88 | + TextDecorations="Underline" |
| 89 | + LineBreakMode="CharacterWrap"> |
| 90 | + <Label.GestureRecognizers> |
| 91 | + <TapGestureRecognizer Command="{Binding OpenUrlCommand}" |
| 92 | + CommandParameter="{Binding PublicWebDavUrl}" /> |
| 93 | + </Label.GestureRecognizers> |
| 94 | + </Label> |
| 95 | + |
| 96 | + <Label Text="Tap any link to open it here — the browser asks for the same account, and Handoff carries the page to your Mac." |
| 97 | + TextColor="Gray" |
| 98 | + FontSize="12" /> |
59 | 99 |
|
60 | 100 | <HorizontalStackLayout Spacing="8" Margin="0,6,0,0"> |
61 | 101 | <Label Text="Requests served:" /> |
|
66 | 106 | </VerticalStackLayout> |
67 | 107 | </Border> |
68 | 108 |
|
| 109 | + <!-- The account, read and written on the same screen as the links that ask for it. |
| 110 | + A change takes effect on the very next request — the validator reads these values |
| 111 | + rather than a copy taken at startup, so nothing restarts. --> |
| 112 | + <Border Stroke="{AppThemeBinding Light=#E5E5EA, Dark=#2C2C32}" |
| 113 | + StrokeThickness="1" |
| 114 | + Padding="16" |
| 115 | + StrokeShape="RoundRectangle 12"> |
| 116 | + <VerticalStackLayout Spacing="10"> |
| 117 | + |
| 118 | + <Label Text="Sign in with" FontAttributes="Bold" /> |
| 119 | + |
| 120 | + <Entry Placeholder="Username" |
| 121 | + Text="{Binding Username}" |
| 122 | + IsSpellCheckEnabled="False" |
| 123 | + IsTextPredictionEnabled="False" /> |
| 124 | + |
| 125 | + <!-- Deliberately not masked: on a device you are handing a link to, someone has |
| 126 | + to read this out. A product with real accounts would not show it. --> |
| 127 | + <Entry Placeholder="Password" |
| 128 | + Text="{Binding Password}" |
| 129 | + IsSpellCheckEnabled="False" |
| 130 | + IsTextPredictionEnabled="False" /> |
| 131 | + |
| 132 | + <Grid ColumnDefinitions="*,*" ColumnSpacing="10"> |
| 133 | + <Button Grid.Column="0" |
| 134 | + Text="Save" |
| 135 | + Command="{Binding SaveAccountCommand}" |
| 136 | + IsEnabled="{Binding NotBusy}" /> |
| 137 | + <Button Grid.Column="1" |
| 138 | + Text="New password" |
| 139 | + Command="{Binding RegeneratePasswordCommand}" |
| 140 | + IsEnabled="{Binding NotBusy}" /> |
| 141 | + </Grid> |
| 142 | + |
| 143 | + <Button Text="Copy password" |
| 144 | + Command="{Binding CopyValueCommand}" |
| 145 | + CommandParameter="{Binding Password}" /> |
| 146 | + |
| 147 | + <Label Text="{Binding StorageStatus}" |
| 148 | + TextColor="Gray" |
| 149 | + FontSize="12" /> |
| 150 | + |
| 151 | + <Label Text="The password is generated on first run and kept in the device keychain. A new one takes effect on the next request and locks out anyone holding the old one. Failed attempts still show up on the Traffic tab — the log sits in front of authentication." |
| 152 | + TextColor="Gray" |
| 153 | + FontSize="12" /> |
| 154 | + |
| 155 | + </VerticalStackLayout> |
| 156 | + </Border> |
| 157 | + |
69 | 158 | <!-- Actions --> |
70 | 159 | <VerticalStackLayout Spacing="10"> |
71 | 160 | <Button Text="Share publicly" |
|
95 | 184 | IsEnabled="{Binding CanStopSharing}" /> |
96 | 185 | </VerticalStackLayout> |
97 | 186 |
|
98 | | - <Label Text="Endpoints: / · /api/device · /api/notes · /files (browse app storage) · /mcp (4 tools, for an AI client) — all behind the password. /ping is open." |
| 187 | + <Label Text="Endpoints: / · /api/device · /api/notes · /files (browse app storage) · /dav (the same storage as a drive, or a browsable listing) · /mcp (4 tools, for an AI client) — all behind the password. /ping is open." |
99 | 188 | TextColor="Gray" |
100 | 189 | FontSize="12" /> |
101 | 190 |
|
|
0 commit comments