Skip to content

Merge - #222

Closed
fharenheit wants to merge 13 commits into
Renakoni:mainfrom
fharenheit:main
Closed

Merge#222
fharenheit wants to merge 13 commits into
Renakoni:mainfrom
fharenheit:main

Conversation

@fharenheit

@fharenheit fharenheit commented Oct 27, 2026 •

Copy link
Copy Markdown

Closes #

Summary

Type of change

  • Bug fix
  • New feature
  • UI/UX change
  • Android native integration
  • CI/build/documentation

Test plan

  • pnpm build
  • pnpm android:sync
  • Android debug build
  • MuMu/emulator install and launch, if UI or native Android behavior changed
  • Screenshot or screen recording attached, if UI changed

Android notes

Reviewer notes

claude added 13 commits October 27, 2026 00:45
Adds GitHub as a cloud provider next to OneDrive and Google Drive:

- Sign-in uses the OAuth device flow (code entered on github.com, polled
  by the plugin on its own scheduler), so no client secret ships in the
  app. The client id is a build-time resource (-PgithubClientId or
  MARKTEXT_GITHUB_CLIENT_ID); empty reads as provider-unavailable.
- GitHubClient (pure JVM over HttpTransport) lists repositories,
  branches (default first) and folder contents filtered to Markdown, and
  reads files via metadata (blob sha, size cap) then the raw media type.
  Browser ids encode owner/repo/ref/path with ref and path as single
  percent-encoded segments.
- CloudTokenStore accepts never-expiring tokens without a refresh token.
- The in-app cloud browser now serves OneDrive and GitHub; the Open page
  gains a GitHub row and the browser shows the device code with a
  copy-and-open action and cancel.
- GitHub documents open read-only for now; writes and creates reject
  with CLOUD_OPERATION_UNSUPPORTED until committing lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
GitHub documents become writable when the signed-in account can push,
and saving them is always an explicit commit:

- GitHubClient.writeFile commits through the contents API with the blob
  sha the document was read at; a moved-on file maps to
  CLOUD_DOCUMENT_CONFLICT, protected branches/rulesets to
  CLOUD_WRITE_REJECTED and missing access to CLOUD_WRITE_FORBIDDEN.
  Base64 is hand-rolled since java.util.Base64 needs API 26.
- readFile reports canWrite from the repository's push permission.
- Autosave and lifecycle flushes never commit: for commit-only sources
  they keep the edits as a recovery draft and show "Not committed".
  Only a save carrying a commit message reaches GitHub, through the new
  commitCurrentDocument and the commitMessage write option.
- The editor menu gains "Commit to GitHub" (shown while there are
  uncommitted edits), which opens a commit-message sheet; leaving the
  editor with uncommitted edits offers the commit first in the exit
  prompt. Back cancels the sheet.
- Save-as to GitHub stays unsupported for now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
Relative images in GitHub documents:
- The web layer maps relative (and repo-rooted) image paths of the open
  GitHub document to /_marktext_github_/<location> on the app origin.
- GitHubImageWebViewClient (wrapping Capacitor's client) answers those
  requests through GitHubImageServer, which fetches the raw file with the
  signed-in token, so private repositories work and the token never
  reaches web content. Only image types of the open document's
  repository and branch are served (403 otherwise), responses carry a
  script-free CSP, and a small byte-bounded LRU avoids refetching.
- The read of a GitHub document scopes the endpoint natively before the
  editor renders; a sync watcher on the source URI keeps it in step.

Shared GitHub links:
- A share that is just a github.com blob/raw or raw.githubusercontent.com
  file link (optionally after a title line) opens the repository
  document instead of importing the URL as a draft. The ref/path split
  is resolved against GitHub, since branch names may contain slashes.
  The link is loaded before the current document is preserved, so a
  failure leaves it untouched.

Location.parse now also rejects empty and dot path segments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
…mages in the same commit, and render inline SVG

Branches and pull requests:
- The commit sheet can commit to a new branch (created from the
  document's branch, name suggested and validated on both sides) and open
  a pull request back. It reuses the save-copy flow, so the branch copy
  becomes the open document and later commits continue there. A commit
  that fails after the branch was created removes the branch again; a
  pull request that fails after the commit landed is reported without
  losing the commit.

Multi-file commits:
- Images inserted on the device (marktext-image://local/...) are added
  next to the document under images/ in the SAME commit through the Git
  Data API (blobs, tree, commit, non-forced ref update), and the
  committed Markdown links them relatively. The document's blob at the
  branch head must still match, and a branch that moved meanwhile fails
  the ref update; both surface as conflicts.
- The transport falls back to setting PATCH reflectively where
  java.net rejects it (Android's OkHttp-backed connection accepts it).

Rendering:
- Mermaid (flowchart, sequence, class, state, gantt, pie, ER, mindmap)
  and SVG as images, data URLs, <img> and HTML blocks already rendered.
  A single-line <svg>…</svg> inside a paragraph rendered an empty <svg>:
  its child shapes went through the inline renderer as plain HTML. Muya
  now renders inline <svg> as a sanitized preview beside its source,
  like <ruby>. E2E coverage added for SVG forms and Mermaid types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
…it, push, pull with conflicts, branches and history

Native (JGit 5.13, the last Java-8 line; java.nio.file on API 24/25 via
core-library desugaring with desugar_jdk_libs_nio):
- LocalGitRepository wraps the Git semantics as pure JVM code: clone,
  status, commit, push (non-fast-forward reported), pull/merge with
  conflicts left in MERGING, per-file resolution (ours / theirs / edited),
  complete or abort the merge, discarding uncommitted edits per file or
  all, branch list/switch/create (remote-only branches tracked on
  switch), history, commit diffs (renames, binary and oversized sides
  flagged) and reverting a commit (conflicts resolved like a merge).
  Paths are confined to the working tree and out of .git. Committing
  refuses while conflicts remain, rather than staging conflict markers.
- SandboxedGitSystemReader keeps JGit's user/system config and HOME in
  an app-private directory.
- LocalRepositoriesPlugin stores working copies under
  files/repositories/<id>, authenticates github.com remotes with the
  GitHub sign-in token, authors commits as the GitHub account's no-reply
  identity, runs one Git operation at a time, reports progress, and
  returns error codes with the affected paths.
- 16 JGit round-trip tests against local bare remotes (two clones per
  test standing in for phone and collaborator), plus id/slug tests.

Web:
- repo:<id>:<path> documents ride the existing document pipeline:
  autosave writes the working tree (device-inserted images are copied
  next to the document and linked relatively), relative images display
  from disk, recents reopen them, and they hold no SAF grant.
- lineDiff: Myers line diff with unified hunks (randomized round-trip
  tests), shared by every diff view.
- Open page -> "Repositories on this device": list, clone (with the
  signed-in account's GitHub repositories as quick picks), remove; a
  repository screen with Files, Changes (diff per file, revert per file
  or all, commit), Branches (switch, create), History (commit diff,
  revert commit), Pull/Push, and a merge banner for conflicts.
- Editor menu: "Show changes" (repository documents against the last
  commit, cloud documents against the last read or save) and "Revert
  changes" (repository documents to their last commit; GitHub documents
  back to the version on GitHub).
- Android Back unwinds the repository views; strings in all 10 locales.
- E2E coverage with an in-page plugin mock for edit/diff/commit/push,
  revert from the editor, conflicted pulls, per-file revert, branches,
  history/commit revert and Back handling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
- Bundle D2Coding Ligature 1.3.2 (SIL OFL 1.1, WOFF2) and make it the
  default editor and code font; existing choices stay selectable.
- GitHub no longer reads "not configured" in builds without an OAuth
  client id: a personal access token can be pasted instead. The token
  is checked against GET /user before it is stored; the device flow is
  still offered when a client id is built in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
- The clone form picks a source, GitHub by default. With a signed-in
  GitHub account it lists the account's repositories with a search box
  to filter and pick one.
- "Git repository" takes an HTTPS address plus a username and password
  or token. Credentials that clone successfully are kept per host in
  app-private storage and reused for push and pull; the form remembers
  the source, address and username, and an empty password field reuses
  the saved one (it never returns to the WebView). Saved passwords can
  be forgotten from the form.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
…onts

- Rendered Markdown defaults to the system font again.
- The code font setting becomes the monospace font and now covers every
  monospace span: code blocks, inline code, math/HTML source, raw
  <code>/<kbd>/<pre>, plus the app's diff view. Default D2Coding Ligature.
- New "Source editor font" setting for the raw Markdown editor, default
  D2Coding Ligature. Both reach non-Muya UI through --mt-mono-font and
  --mt-source-font.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
A "Source + preview" entry in the document menu shows the raw Markdown
editor together with a read-only rendered preview: stacked on a phone,
side by side in wide landscape. The preview goes through Muya's export
renderer (sanitized, highlighted, math and diagrams), resolves images
like the editor, follows the appearance font settings and the source
editor's scroll position, and re-renders shortly after each edit. The
textarea stays the only editable document, so leaving the split hands
the text back to the WYSIWYG editor exactly like source mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
- <br> in paragraphs and table cells renders as a line break and hides its
  raw tag unless the caret touches it, like other inline syntax.
- Block conversions (lists, headings, quote, code/math blocks, ...) are
  no-ops with the caret in a table cell, and the toolbar disables them
  there: they used to build the block beside the table and break its
  cells.
- Native line breaks (Enter while an IME composes, keyboards without a
  usable keydown) go through the block's Enter handling instead of
  splitting Muya's DOM, which left stray lines and lost the syllable.
- A tap on an empty table cell puts the caret in that cell.
- Monospace size is a percentage of the editor text size (default 90%)
  and applies to code blocks, inline code, math/HTML source, the source
  editor and the preview; it replaces the fixed code font size in px.
- Split view goes side by side from 600px wide, with equal panes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
- Settings > About shows "MarkText for Data Dynamics Inc" and the version
  as "version · short commit hash · yyyyMMddHHmmss", stamped by Vite at
  build time (update checks still compare the plain version).
- Repository, releases and update-check URLs (web and the native
  releases/latest checker), README release links/badges and issue
  templates point at fharenheit/marktext-android.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
With all four signing secrets the workflow builds the release-signed APK
as before; with none it publishes a debug-signed APK (named -debug.apk
and flagged in the notes) so this repository can release before it has
its own keystore; a partial set still fails. The certificate pin comes
from the ANDROID_RELEASE_CERT_SHA256 repository variable instead of the
upstream fingerprint, and the release is published rather than drafted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
A workflow_dispatch run with publish=true creates the v<package version>
tag at the dispatched commit along with the release, for pushers who
cannot push tags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdvWTvFJBufEV4VgFBkoxK
@fharenheit

Copy link
Copy Markdown
Author

각종 기능 추가, 버그 수정

@fharenheit fharenheit closed this Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants