How I replaced GTLR with a lean REST setup—token-based Google Drive integration using URLSession, safer secrets, and fewer moving parts.
GTLR is gone from my stack. I rebuilt file list, upload, and metadata calls with token-based Google Drive integration using pure REST and URLSession
. The result: smaller binaries, clearer errors, and auth I actually understand. This post shows the moving pieces, pitfalls, and a copy-paste checklist you can apply today. For layout sanity while rebuilding screens, I leaned on Golden Scaling in Practice—pre-deciding anchors kept my UI and my head calm during refactors.
Why token-based Google Drive integration?
Libraries hide complexity—until they don’t. A direct REST approach gives you explicit control over scopes, refresh timing, and retries. With a short AuthService
, I trade magical “it works” for transparent calls I can reason about. See my earlier context in LifeOS Dev Log: Drive Tokens & List/Grid Toggle for how this started.
Core flow for token-based Google Drive integration
- Sign in & get tokens. Use Google Sign-In to obtain an access token and refresh token (on first consent).
- Store securely. Keep tokens in Keychain; never in
UserDefaults
or the document.
- Attach bearer. Each request sets
Authorization: Bearer <access_token>
.
- Auto-refresh. On 401, refresh using the OAuth token endpoint and retry once.
- Call Drive v3. Hit
/drive/v3/files
for list/search, /upload/drive/v3/files
for media.
Minimal checklist for token-based Google Drive integration
- Scopes: request the smallest set that covers your features (
drive.file
beats drive
).
- Expiry: track
expires_in
and refresh proactively at ~80% of lifetime.
- Retries: 1 refresh retry max; then sign-in flow.
- Logging: log request ids + status codes, redact tokens.
Endpoints you’ll call (REST)
- List files:
GET https://www.googleapis.com/drive/v3/files?q=name contains 'doc'&fields=files(id,name,mimeType,modifiedTime,size)
- Upload (simple):
POST https://www.googleapis.com/upload/drive/v3/files?uploadType=media
- Upload (multipart):
POST https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart
- Refresh token:
POST https://oauth2.googleapis.com/token
The official references are clear and current: Drive API (REST) Overview and Google Identity: OAuth 2.0.
UI notes (because UX still matters)
Token work is plumbing; users feel rhythm. Anchor your headline on 3/5, your primary action (Upload / Connect) on 5/8, and stick to one gutter (8/13/21). These small rules keep “settings” screens from feeling like a spreadsheet.
Common mistakes (and quick fixes)
- Using broad scopes: start with
drive.file
; escalate only if required.
- Storing tokens loosely: Keychain or secure enclave wrappers—always.
- No refresh guard: limit retries to prevent loops.
- JSON field bloat: set
fields=
to exactly what you render; faster and cheaper.
- Blocking the UI: do I/O off the main actor; stream uploads when possible.
What I cut (and didn’t miss)
- Heavy client libs, auto-generated models, opaque errors.
- I kept: typed request builders, small decoders, and a single
HTTPClient
with request/response logging (redacted).
Ship it
Start by swapping your file list screen to REST calls behind an AuthService
. If it feels good, move uploads and metadata next. When you hit the first 401 in the wild, you’ll be glad you understand the flow. Download the starter snippet for URLSession + refresh and make your Drive calls boring—in the best way.
- randomblink
Design for Focus, Not FOMO
A practical, golden-ratio system to build calm dashboards that reduce noise, guide attention, and speed decisions.
If your product feels busy, calm dashboards are the antidote. This approach uses golden-ratio anchors (3/5, 5/8), one consistent gutter, and ruthless information triage so teams scan faster and click with confidence. I borrowed the same “pre-decision” mindset I use in layouts from my Golden Scaling in Practice post and applied it to analytics screens.
Why calm dashboards beat crowded ones
Crowding fractures attention. Calm dashboards establish one dominant element (headline/KPI), one supporting action (CTA), and everything else subordinate. This creates a reliable reading path and fewer hesitations.
ϕ anchors for calm dashboards
Pin the headline to the 3/5 vertical and the primary CTA to the 5/8 horizontal. Choose one baseline gutter—8, 13, or 21—and stick to it across the screen. These rails remove most micro-decisions and give your interface a steady rhythm.
Information triage that keeps calm dashboards calm
Sort every module into: Now (decision-critical), Next (context), Nice (reference). Now goes on your anchor lines; Next aligns to parallel rails; Nice is collapsible. This simple rule cuts clutter without cutting capability.
Interaction rules for calm dashboards
Limit the screen to one primary action; demote the rest. Prefer subtle motion only on state changes. Keep focus order left→right, top→bottom along your rails. For a second opinion on layout fundamentals, review Material Design’s layout overview and map its guidance onto your φ grid.
Before → After (mini pattern)
Before: center-stacked widgets, variable paddings, CTA shouting, three competing KPI rows.
After: headline on 3/5, KPI strip aligned to the 5/8 cross-line, filters on a parallel rail, uniform 13-pt gutter. Scan time drops; decisions rise.
Ship it
Clone this recipe on one dashboard today: set φ rails, pick one gutter, triage modules, and run a squint test. Close by validating focus order with keyboard only. Download the Calm Dashboard Checklist and start removing noise on purpose.
How the ϕ Grid Made My UI Cleaner (and My Brain Calmer)
A simple golden-ratio layout system (anchors at 3/5 and 5/8) that tightened my interfaces, reduced decision fatigue, and gave me a repeatable checklist for every screen.
TL;DR
- Use a ϕ:1 canvas (width:height ≈ 1.618) or nest ϕ blocks inside standard frames.
- Place primary headlines on the 3/5 vertical; align CTAs near the 5/8 horizontal.
- Build a tiny 3-row / 5-column scaffold; snap cards and media to those rails.
- Result: fewer alignment decisions, stronger rhythm, and calmer screens.
Why Golden Scaling (ϕ) stabilizes a screen
Most “messy UI” isn’t about color or type—it's inconsistent spacing and weak anchors. The golden ratio gives you predictable anchor lines so your composition feels intentional without constant nudging. I call this Golden Scaling: a lightweight way to pre-decide where things go so your brain doesn’t rehearse the same layout argument twelve times a day.
The anchors I use (and why)
Primary rails
- 3/5 vertical (~60% from the left): natural spot for headlines / section titles.
- 5/8 horizontal (~62.5% from the top): reliable CTA / key control line.
Support rails
- Fibonacci gutters: 8, 13, 21 pt (pick one per screen and stick to it).
- Type rhythm: base size × ϕ for display, ÷ ϕ for captions.
- Card corners & shadows: keep consistent; let position, not decoration, carry hierarchy.
These ratios won’t magically design for you—they just remove 80% of dithering.
Before → After (what changed)
Before
- Headline floated; CTA fought the list for attention.
- Inconsistent padding produced micro-misalignments.
- Eyes wandered; no single “resting line.”
After (ϕ grid)
- Headline locked to 3/5 vertical; the eye lands, then scans.
- CTA chip rides the 5/8 horizontal—always discoverable, never shouting.
- List/grid toggle sits on a secondary rail; spacing uses one Fibonacci gutter across the screen.
Result: the same pieces, less noise.
The ϕ Layout Checklist (copy-paste)
Canvas
- Choose canvas: ϕ:1 or nest ϕ blocks inside your existing aspect.
- Set one baseline grid (8/13/21 pt); don’t mix within a single screen.
Anchors
- Place H1/Hero on 3/5 vertical.
- Place primary CTA on 5/8 horizontal.
- Place secondary controls (filters/toggles) on a parallel rail (same offset, smaller weight).
Hierarchy
- One dominant (headline), one supporting (CTA), everything else subordinate.
- Use spacing, not decoration, to show priority.
- Keep type: Base → Base×ϕ for display, Base/ϕ for captions.
Rhythm
- Use a single gutter size (8/13/21).
- Align media edges to rails; crop images to land a focal point near an anchor.
Review
- Zoom out to 25%: can you point to the headline in 1s? the CTA in 2s?
- Nudge only along rails; no freehand micro-moves.
👉 CTA: Try my φ layout checklist — copy this block into your design system and staple it to your next wireframe.
How to apply it in 10 minutes (mini How-To)
- Overlay rails: draw a vertical line at 60% (3/5) and a horizontal line at 62.5% (5/8).
- Pin your headline to the 3/5 line; nudge baseline to snap.
- Park your CTA where the 5/8 horizontal crosses a comfortable right-hand column.
- Choose one gutter (8, 13, or 21). Re-space everything to multiples of that unit.
- Remove decorative crutches (extra rules, random bolds). Let the grid do the work.
- Squint test + keyboard only: if focus order follows the rails, you’re good.
Accessibility & motion
- Motion: prefer tiny easing on entry; avoid parallax that breaks anchor perception.
- Focus order: follow rails left-to-right, top-to-bottom.
- Hit targets: minimum 44×44; don’t let rails talk you into tiny taps.
- Contrast: the grid sets placement; color still needs WCAG AA at minimum.
Pitfalls I hit (so you don’t)
- Too many rails: keep it to the big two plus your baseline grid.
- Mixing gutters: one screen, one unit.
- Center-bias: it’s tempting to center everything; resist. Let 3/5 lead.
- CTA drift: every revision tries to walk the CTA off its line. Lock it.
FAQ
Isn’t the golden ratio overhyped?
If you treat it like superstition—yes. As a decision framework for anchors and rhythm—useful.
What if my screen isn’t a φ aspect?
Nest ϕ blocks (cards/sections) within whatever frame you have. The anchors still work.
Does this replace design sense?
No. It just reduces choices so your taste can focus on content and flow.
Version / Update box
v1.0 (2025-09-30): First publish with checklist + anchor math.
Planned: downloadable rail overlays (SVG) and a Figma template.
Call to Action
Try my φ layout checklist. Paste it into your design system, apply it to one screen, and reply with a screenshot. I’ll give quick feedback and share a reusable overlay next.
—
Signature:
Rev. Brian Scott O’Keefe (randomblink)
“Ship simply. Then simplify the ship.”
Reanalyzing My Files
Monday’s push got the repo breathing again. Tomorrow I’m pushing more—and I’m tightening the way I scan, sort, and fix the mess.
Why today’s about reanalysis (not just fixes)
Monday’s push was triage: get the living code to the surface, tag what’s drifting, and cut the snags. That worked. But a stable repo isn’t the finish line—it’s the floor. Today I’m reanalyzing the structure so tomorrow’s push isn’t just “more,” it’s cleaner and more predictable.
What “reanalyzing my files” means here:
- Audit the scanners that enumerate Drive files and local modules.
- Normalize token flow so I’m not juggling brittle auth paths.
- Make metadata (size, modified, MIME) first-class citizens in UI and logs.
- Resolve compile errors with a single source of truth, not scattered patches.
The quick scoreboard
- ✅ Monday: Major file push, baseline builds on both platforms, rough edges listed.
- 🔧 Today: Reanalyzing file scanners, tightening token handling, annotating metadata surfaces.
- 📦 Tomorrow: Another batch push with resolved errors and UI passes on list↔grid + tags.
The scanning pass: from “what do I have?” to “what matters?”
I’m making the file scanners do real work—not just dump filenames.
What I’m enforcing:
- Deterministic ordering: stable sort (by modified desc, then name) so diffs are sane.
- Selective hydration: only fetch size/MIME/thumbnail when a row is onscreen or requested.
- Tag-aware listings: the list↔grid view respects active tags and persists the choice.
- Audit trails: each row logs
id • modified • mime
to make debugging observable.
Result: When something looks wrong in the UI, the logs already explain why.
Token flow: fewer hops, clearer states
Auth shouldn’t feel like a mini-boss fight.
Guardrails I’m adding:
- Single token source: one place to mint/refresh/use; no shadow helpers.
- State enum:
.signedOut → .signingIn → .ready(accessToken) → .expired
with clear UI fallbacks.
- Retry policy: jittered exponential backoff on 401s, then a single user prompt if needed.
- Telemetry: timestamped token events to avoid ghost bugs.
Why it matters: Build errors are loud; token bugs are quiet. I want neither.
Metadata where it belongs: in front of me
I’m making metadata visible where decisions happen.
UI touches in this pass:
- Row subtitles:
Size · Modified · MIME
under the name.
- Hover affordances: quick “Copy ID” and “Open in Drive” actions.
- Previews: lightweight thumbnails with graceful fallbacks for unknown types.
This turns “why is this file weird?” into a two-second glance instead of a rabbit hole.
Today’s punch list
- Refactor scanner to return
FileDescriptor
with stable sort + lazy hydration
- Centralize token refresh; remove duplicate helpers
- Surface ID/modified/MIME in list↔grid cells
- Add debug overlay to show active tag filters + data source
- Verify compile across iOS/macOS; note any isolation or Sendable warnings
What I’ll ship tomorrow (Oct 1)
- Batch push: refactored scanner + token flow + UI passes
- Changelog: before/after on file rows and auth behavior
- Next target: thumbnail caching + “Recents/Favorites” tabs
Links
- External: Apple HIG (layout rhythm), Google Drive REST docs (metadata fields)
Update / Version box
Version: 2025-09-30 • Status: Reanalysis in progress
- What changed: Baseline repo pushes; scanners and token flow under refactor
- What’s next: Oct 1 push with UI polish + caching hooks
- Notes: If you saw odd auth prompts yesterday, that’s expected; today’s commit removes duplicates.
FAQ (short)
Why not push everything today?
Because I’d be pushing problems, not fixes. Today I tighten the pipes so tomorrow’s batch is clean.
Will this break existing tokens?
No. Worst case: a single re-auth prompt. After that, it should be quieter than before.
Signature
— randomblink
“Build it clean, then build it fast.”
Drive Previews, Tag Chips, and Faster List↔Grid
Previews that land sooner, tags that filter smarter, and a list/grid toggle that stops jumping.
1) Drive previews: sooner, safer
- Parallel fetch with short deadline. We request preview URLs and content metadata in parallel; if a preview misses the deadline, a crisp type glyph renders instantly and the preview swaps in later.
- Cache keys that make sense.
fileId:modified:size
prevents stale thumbs and avoids over-fetch.
- Fail gracefully. If a preview URL expires or fails, we retry once with backoff; otherwise we stay on the glyph—no flicker.
Tech: Google Drive v3 via REST + URLSession
(no GTLR), tokens in Keychain, MIME + modified date for cache busting.
2) Tag chips: clearer states, fewer clicks
- Tap = add/remove, Option/Alt-tap (or long-press) = isolate.
- Three visual states (default / active ● / isolated ◎), not color-only—icons + contrast.
- Keyboard: press
t
to focus chips; use arrow keys; Space
toggles; Enter
isolates.
Why it’s calmer: you see exactly what’s filtering, and you can isolate a single tag without hunting in a sidebar.
3) List ↔ Grid: faster and steady
- Per-section persistence. Projects can default to List; Resources can default to Grid; your picks stick via
UserDefaults
.
- No layout jump. We normalize row heights and thumbnail placeholders so the header and chip row don’t jitter during toggles.
- Scroll position remembered across toggles within the same section.
Tiny wins that matter
- Progressive disclosure. Modified date and type inline; size/path appear on hover/focus.
- Focus rings you can see. Keyboard navigation is obvious and consistent.
- Touch targets. Chips and toggles are 44pt minimum.
Try it
- Toggle list↔grid in Resources; notice no header jump.
- Tap a couple of tags, then isolate one with Option/Alt.
- Open a large image folder—the first row should render fast with clean fallbacks.
What’s next
- Recents ranking v2 (boost multi-touch files over 48 hours).
- PDF inline preview (first page, cached).
- Session stacks (auto-bundle your last 60–90 minutes of files).
Internal & External Links
Update / Version Box
LifeOS — Dev Log #3
- Build:
0.1.0-dev
(Swift 6, Xcode 16)
- Shipped: faster Drive previews, clearer tag chips, steadier list↔grid
- Known limits: giant PDFs still skip preview on slow networks
- Next: Recents ranking v2 + first-page PDF preview
Signature
— Rev. Brian Scott O’Keefe
“Less friction, more flow.”
Tokens, Sync, Clean Start
Current goals
- ✅ Go REST-only with tokens (ditch legacy SDK/gRPC/GTLR; rely on clean URLSession calls).
- ✅ Harden sign-in/out across macOS/iOS with a single source of truth for auth state.
- 🔄 Design a calmer file view that shows exactly what you need (and nothing you don’t).
- 📓 Make the logs the memory: short, truthful dev notes; tight screenshots; reproducible steps.
- 🧪 Stabilize sync for Drive/Calendar basics, then layer on previews and offline cache.
Auth & tokens (the new backbone)
The old way was tangled. The new way is simple:
- Token-based REST: standard OAuth2 flow → store access + refresh tokens in the Keychain; refresh automatically before expiry; never block the UI waiting on auth.
- Single Auth service: one AuthState drives UI. If isSignedIn == false, show a safe, minimal sign-in sheet; otherwise continue seamlessly.
- Sign-out that really signs out: clear tokens, reset caches, invalidate any background tasks, bounce the app to a clean state.
- Resilience first: every network call wraps:
- Retry on transient errors (exponential backoff).
- 401 → refresh token once → retry; if it fails, drop to signed-out.
- All errors surface as human-readable toasts and machine-readable logs.
What I broke today:
A silent refresh loop when the network dropped mid-refresh. Fixed by gating concurrent refresh calls and memoizing the in-flight promise so only one refresh can run at a time.
Privacy posture: tokens never leave the device; logs redact headers; no crash reports include PII.
File view ideas (don’t fight the brain)
I’m designing for calm and orientation:
- List ↔ Grid toggle with your last choice remembered.
- At-a-glance metadata: file type, size, modified date, and Drive ID (copy-on-click).
- Thumbnails/previews where useful; text-only for dense modes.
- Recents / Favorites tabs right on top.
- Inline filters (type, tag, owner) with a compact query pill you can edit.
- Breadcrumbs you can actually use (each crumb is clickable and copyable).
- One universal action key: ⏎ opens, ⌘C copies link/ID, Space previews.
- “What changed?” ghost highlights after a sync so your eyes find fresh stuff fast.
- Gentle empty states with a single next action (import, connect, or create).
Sketch note: the content column aligns to a golden-ratio container; actions hide until hover/focus to reduce visual noise.
Known bugs (current reality, not vibes)
- Folder lists sometimes load but aren’t clickable after a slow network wake. Likely a stale SwiftUI state binding—reloading the data source fixes it; investigating a proper identity key.
- Actor isolation warnings in Swift 6 where async services touch UI state (DrivePathResolver + cache).
- Occasional duplicate types after regenerating models (invalid redeclarations). Root cause: old files not removed during refactor; adding a “regenerate and prune” step.
- Ambiguous initializers in a mock service leading to “extra arguments” compile errors—cleaning up convenience inits and adopting builders for test data.
- Token refresh race (now fixed) caused a brief signed-out flicker on resume.
I’m keeping these here until each is closed and regression-tested.
Next sprint (tight, testable, shippable)
1) Auth polish
- Add a single-flight refresh guard (done), plus unit tests for: token expiry edge, network drop, revoked refresh token.
- Implement background refresh scheduling with OS hints to avoid wake storms.
2) File view MVP
- Ship List/Grid with: name, icon, size, modified, ID (copy-on-click).
- Add Recents/Favorites tabs and persist view mode in UserDefaults.
- Wire preview (Space) for images/PDF/text.
3) Sync + cache
- Local metadata cache keyed by Drive ID; optimistic UI for move/rename.
- Debounced search with cancellable tasks to keep typing smooth.
4) Quality gates
- “No new warnings” rule on main.
- Trace logs for every network call with request ID; redaction enforced in one place.
- Screenshot + short clip of each feature before merge (so this log has pictures).
CTA: Tell me your top pain in organizing files; I’ll test it in the next build.
Drop a comment or reply with a 1–2 sentence description (bonus: a quick phone snapshot of your folder chaos). Real pain > hypothetical features.
Changelog (human-sized)
- Refactor: Removed legacy SDK hooks; REST-only networking via URLSession.
- Auth: Centralized AuthState; fixed refresh loop; clearer error surfaces.
- Design: Spec’d calmer file view; golden-ratio container; copyable IDs.
- Tooling: Added request-ID tracing; started “screenshots or it didn’t happen” rule.
- randomblink