RepoPilotOpen in app →

zhanghai/Douya

开源的 Material Design 豆瓣客户端(A Material Design app for douban.com)

Concerns

Looks unmaintained — solo project with stale commits

weakest axis
Use as dependencyConcerns

no license — legally unclear; last commit was 5y ago…

Fork & modifyConcerns

no license — can't legally use code; no tests detected…

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isConcerns

no license — can't legally use code; last commit was 5y ago

  • CI configured
  • Stale — last commit 5y ago
  • Solo or near-solo (1 contributor active in recent commits)
Show all 5 evidence items →
  • No license — legally unclear to depend on
  • No test directory detected
What would change the summary?
  • Use as dependency ConcernsMixed if: publish a permissive license (MIT, Apache-2.0, etc.)
  • Fork & modify ConcernsMixed if: add a LICENSE file
  • Deploy as-is ConcernsMixed if: add a LICENSE file

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Great to learn from" badge

Paste into your README — live-updates from the latest cached analysis.

RepoPilot: Great to learn from
[![RepoPilot: Great to learn from](https://repopilot.app/api/badge/zhanghai/douya?axis=learn)](https://repopilot.app/r/zhanghai/douya)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/zhanghai/douya on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: zhanghai/Douya

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/zhanghai/Douya shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

AVOID — Looks unmaintained — solo project with stale commits

  • CI configured
  • ⚠ Stale — last commit 5y ago
  • ⚠ Solo or near-solo (1 contributor active in recent commits)
  • ⚠ No license — legally unclear to depend on
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live zhanghai/Douya repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/zhanghai/Douya.

What it runs against: a local clone of zhanghai/Douya — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in zhanghai/Douya | Confirms the artifact applies here, not a fork | | 2 | Default branch master exists | Catches branch renames | | 3 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 4 | Last commit ≤ 1819 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>zhanghai/Douya</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of zhanghai/Douya. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/zhanghai/Douya.git
#   cd Douya
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of zhanghai/Douya and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "zhanghai/Douya(\\.git)?\\b" \\
  && ok "origin remote is zhanghai/Douya" \\
  || miss "origin remote is not zhanghai/Douya (artifact may be from a fork)"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "app/src/main/java/me/zhanghai/android/douya/DouyaApplication.java" \\
  && ok "app/src/main/java/me/zhanghai/android/douya/DouyaApplication.java" \\
  || miss "missing critical file: app/src/main/java/me/zhanghai/android/douya/DouyaApplication.java"
test -f "app/src/main/java/me/zhanghai/android/douya/account/app/Authenticator.java" \\
  && ok "app/src/main/java/me/zhanghai/android/douya/account/app/Authenticator.java" \\
  || miss "missing critical file: app/src/main/java/me/zhanghai/android/douya/account/app/Authenticator.java"
test -f "app/src/main/java/me/zhanghai/android/douya/broadcast/content/BroadcastResource.java" \\
  && ok "app/src/main/java/me/zhanghai/android/douya/broadcast/content/BroadcastResource.java" \\
  || miss "missing critical file: app/src/main/java/me/zhanghai/android/douya/broadcast/content/BroadcastResource.java"
test -f "app/src/main/java/me/zhanghai/android/douya/broadcast/ui/BroadcastListFragment.java" \\
  && ok "app/src/main/java/me/zhanghai/android/douya/broadcast/ui/BroadcastListFragment.java" \\
  || miss "missing critical file: app/src/main/java/me/zhanghai/android/douya/broadcast/ui/BroadcastListFragment.java"
test -f "app/build.gradle" \\
  && ok "app/build.gradle" \\
  || miss "missing critical file: app/build.gradle"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1819 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1789d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/zhanghai/Douya"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Douya is a Material Design Android client for Douban (豆瓣), a Chinese social network for movies, books, music, and events. It prioritizes friend-based content discovery through broadcasts and neighbor feeds rather than algorithmic recommendations, implementing native Android patterns with custom Material Design components like ExpandedHintTextInputLayout and ThemedSwipeRefreshLayout. Monolithic Android app module (app/) with package hierarchy mirroring feature domains: account/ (authentication via AccountManager), broadcast/ (friend feeds), and custom widgets in androidx/ namespace overrides (NightModeAccessor, FriendlySwipeRefreshLayout). Core app state via Resources and AccountPreferences; networking through Douban API v2 REST calls.

👥Who it's for

Chinese Android developers and Douban power users who want a Material Design-first mobile experience focused on friend networks and broadcasts rather than the official Douban app's item-centric approach. Contributors interested in Android architecture patterns, Material Design implementation, and internationalization (English and Chinese).

🌱Maturity & risk

Actively maintained but approaching stability: last version tagged 1.0.0-beta.12 (versionCode 15), Travis CI configured for automated builds, ProGuard minification enabled for release builds, but no visible test suite in the file structure. The codebase is production-ready for Douban's Chinese user base but still in beta versioning.

Moderate dependency risk: relies on Crashlytics/Fabric (Firebase) for crash reporting, Douban's V2 API (not versioned in build.gradle visible snippet), and custom Material Design components that may diverge from library updates. Single maintainer (zhanghai) with infrequent but stable commits; no visible open issue backlog in provided data; compileSdkVersion 29 and targetSdkVersion 29 are dated (current is 34+).

Active areas of work

No active development visible in provided data; repo appears stable post-beta with focus on maintenance. Last observable state: Travis CI passing, Gradle build configured with Crashlytics integration, but no evidence of recent commits or open PRs in file snapshot.

🚀Get running

Clone and build via Gradle: git clone https://github.com/zhanghai/Douya.git && cd Douya && ./gradlew assembleDebug. Requires Java 8 (sourceCompatibility/targetCompatibility set to VERSION_1_8), Android SDK 21-29, and setup of signing.gradle for release builds. API keys must be configured separately per DouyaApiKey guide in README.

Daily commands: ./gradlew assembleDebug && adb install -r app/build/outputs/apk/debug/app-debug.apk to build and install on connected device. Dev build has Crashlytics disabled (ext.enableCrashlytics = false in debug buildType).

🗺️Map of the codebase

  • app/src/main/java/me/zhanghai/android/douya/DouyaApplication.java — Application entry point and global initialization; all contributors must understand the app lifecycle and dependency setup here.
  • app/src/main/java/me/zhanghai/android/douya/account/app/Authenticator.java — Core authentication logic for Douban API; essential for understanding how credentials are managed and API requests are authenticated.
  • app/src/main/java/me/zhanghai/android/douya/broadcast/content/BroadcastResource.java — Base resource class for broadcast data management; establishes the pattern for all content fetching and caching in the app.
  • app/src/main/java/me/zhanghai/android/douya/broadcast/ui/BroadcastListFragment.java — Primary UI fragment for displaying broadcasts; demonstrates the fragment architecture and UI state management used throughout.
  • app/build.gradle — Project build configuration with SDK versions, dependencies, and app settings; critical for build reproducibility and dependency management.
  • app/src/main/AndroidManifest.xml — Android manifest declaring all activities, services, permissions, and providers; foundational for understanding app capabilities and entry points.
  • app/src/main/java/me/zhanghai/android/douya/app/RetainedFragment.java — Base retained fragment for data persistence across configuration changes; core pattern used throughout for lifecycle management.

🛠️How to make changes

Add a new broadcast list screen (e.g., User broadcasts)

  1. Create a new Resource class extending BaseBroadcastListResource in broadcast/content/ (app/src/main/java/me/zhanghai/android/douya/broadcast/content/)
  2. Create a new Fragment extending BaseTimelineBroadcastListFragment in broadcast/ui/ (app/src/main/java/me/zhanghai/android/douya/broadcast/ui/BaseTimelineBroadcastListFragment.java)
  3. Register the new fragment in the navigation and create an Activity if needed (app/src/main/java/me/zhanghai/android/douya/broadcast/ui/BroadcastListActivity.java)
  4. Add manifest entries for the new Activity (app/src/main/AndroidManifest.xml)

Add a new write action (create/update/delete) for broadcasts

  1. Create a Manager class extending the pattern of SendBroadcastManager (app/src/main/java/me/zhanghai/android/douya/broadcast/content/SendBroadcastManager.java)
  2. Create a Writer class handling the actual API call (app/src/main/java/me/zhanghai/android/douya/broadcast/content/SendBroadcastWriter.java)
  3. Create dialog fragments for confirmation if needed (see ConfirmDeleteBroadcastDialogFragment) (app/src/main/java/me/zhanghai/android/douya/broadcast/ui/ConfirmDeleteBroadcastDialogFragment.java)
  4. Integrate Manager into UI layer via Activity/Fragment (app/src/main/java/me/zhanghai/android/douya/broadcast/ui/SendBroadcastActivity.java)

Add authentication or account management features

  1. Modify the Authenticator class to handle new authentication requirements (app/src/main/java/me/zhanghai/android/douya/account/app/Authenticator.java)
  2. Update AuthenticatorActivity UI to match Material Design theme (app/src/main/java/me/zhanghai/android/douya/account/ui/AuthenticatorActivity.java)
  3. Update AccountUtils with any new account-related utility methods (app/src/main/java/me/zhanghai/android/douya/account/util/AccountUtils.java)
  4. Update manifest with new account-related permissions (app/src/main/AndroidManifest.xml)

Extend the caching strategy for better performance

  1. Study the existing HomeBroadcastListCache pattern (app/src/main/java/me/zhanghai/android/douya/broadcast/content/HomeBroadcastListCache.java)
  2. Create a similar cache class for your new data type (app/src/main/java/me/zhanghai/android/douya/broadcast/content/)
  3. Integrate the cache into the corresponding Resource class (app/src/main/java/me/zhanghai/android/douya/broadcast/content/HomeBroadcastListResource.java)
  4. Clear cache on relevant write operations in Manager classes (app/src/main/java/me/zhanghai/android/douya/broadcast/content/SendBroadcastManager.java)

🪤Traps & gotchas

signing.gradle is not included in file list but required for release builds (apply from: '../signing.gradle'); will cause build failure if missing. Douban API keys must be obtained separately and configured (see DouyaApiKey repo in README). ProGuard minification enabled in release; local.properties required for signing configuration. AccountManager API requires ACCOUNT permissions and device account setup. Custom androidx overrides may conflict with updated androidx library versions.

🏗️Architecture

💡Concepts to learn

  • Android AccountManager Authentication — Douya uses AccountManager (Authenticator.java, AuthenticatorService.java) to handle Douban OAuth without storing credentials directly; essential for secure multi-account support and Android account sync integration
  • Material Design System & Custom Components — Douya's core philosophy is pixel-perfect Material Design; files like ExpandedHintTextInputLayout and ThemedSwipeRefreshLayout show how to extend Material library components for app-specific theming
  • ProGuard Code Obfuscation & Minification — Release builds use ProGuard (minifyEnabled true in build.gradle) with custom rules (proguard-rules.pro) to shrink APK size and protect proprietary code; requires careful configuration to avoid breaking Douban API serialization
  • Fragment-based Navigation Architecture — Douya structures UI around Fragments (AuthenticatorFragment, TargetedRetainedFragment, RetainedFragment) for tablet multi-pane layouts and screen rotation handling; critical for flexible navigation across device sizes
  • Android FileProvider for Content Sharing — ImageTypeFileProvider (app/src/main/java/me/zhanghai/android/douya/app/ImageTypeFileProvider.java) uses FileProvider to safely share images across apps without exposing raw file paths; required for Android 7.0+ security scoping
  • REST API Resource Pattern — ApiV2BroadcastListResource exemplifies Douya's network layer: each entity type (broadcasts, users, comments) has a Resource class that encapsulates API calls, caching, and error handling; abstraction that decouples UI from HTTP details
  • Retained Fragments for State Persistence — RetainedFragment and TargetedRetainedFragment classes survive configuration changes (screen rotation); Douya uses these to persist network requests and UI state across lifecycle events without data loss

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Migrate from Fabric Crashlytics to Firebase Crashlytics

The build.gradle file shows the project uses deprecated Fabric Crashlytics (io.fabric.tools:gradle and com.crashlytics.sdk.android:answers:1.4.6). Fabric was sunset and migrated to Firebase. This is a concrete, valuable modernization that improves dependency maintenance and future compatibility. The migration involves updating build.gradle, AndroidManifest.xml, and any crash reporting initialization code in DouyaApplication.java.

  • [ ] Update build.gradle: replace io.fabric plugin with com.google.gms:google-services plugin
  • [ ] Add Firebase Crashlytics dependency to build.gradle (com.google.firebase:firebase-crashlytics)
  • [ ] Create google-services.json file for Firebase configuration
  • [ ] Update DouyaApplication.java to initialize Firebase Crashlytics instead of Fabric Answers
  • [ ] Remove legacy Fabric maven repository and classpath dependencies from build.gradle
  • [ ] Test crash reporting functionality in debug and release builds

Add missing unit tests for account authentication flow

The codebase has multiple authentication-related classes (AuthenticatorActivity.java, AuthenticateRequest.java, AccountPreferences.java, AuthenticatorUtils.java) but there is no visible test directory structure. Adding unit tests for the account module would improve reliability of sensitive authentication logic. This is critical for a login-required app like a Douban client.

  • [ ] Create app/src/test/java/me/zhanghai/android/douya/account directory structure
  • [ ] Add unit tests for AccountPreferences.java covering preference read/write operations
  • [ ] Add unit tests for AuthenticatorUtils.java covering token validation and credential handling
  • [ ] Add unit tests for AuthenticateRequest.java covering request building and response parsing
  • [ ] Configure build.gradle with testImplementation for JUnit and Mockito
  • [ ] Ensure tests can run via gradle test command

Add GitHub Actions CI/CD workflow to replace Travis CI

The project uses Travis CI (.travis.yml) which has become less favorable compared to GitHub Actions. GitHub Actions is free, integrated with GitHub, and more flexible. Creating a GitHub Actions workflow would modernize the CI/CD pipeline while maintaining the existing build verification that Travis currently provides.

  • [ ] Create .github/workflows/android-build.yml with steps to checkout code, setup Java/Android SDK
  • [ ] Configure gradle build task for debug APK and run lint/unit tests
  • [ ] Add caching for gradle dependencies to speed up builds
  • [ ] Optional: Add step to upload build artifacts or APKs to workflow artifacts
  • [ ] Test the workflow triggers properly on push and pull requests
  • [ ] Update README.md to replace Travis CI badge with GitHub Actions badge
  • [ ] Keep .travis.yml during transition period or remove after verification

🌿Good first issues

  • Add unit tests for ApiV2BroadcastListResource.java and other Resource classes under broadcast/content/ to verify API response parsing and error handling (no test/ directory visible in file structure)
  • Update compileSdkVersion and targetSdkVersion from 29 to 34 and test against Android 14 APIs, fixing any deprecation warnings in deprecated Account class usage (Authenticator.java)
  • Document the Douban API v2 endpoint contracts used by each *Resource class (e.g., ApiV2BroadcastListResource) in a CONTRIBUTING.md guide with example requests/responses to ease onboarding

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 14d2f3e — [Fix] Fix ViewUtils.getColorStateListFromAttrRes(). (zhanghai)
  • e9916a9 — [Feature] Target API 29. (zhanghai)
  • cd35eda — [Feature] Update preference dependencies. (zhanghai)
  • 6ef58ac — [Feature] Update dependencies. (zhanghai)
  • c395bcc — [Feature] Make API keys built in. (zhanghai)
  • d795e3f — [Refactor] Sync code. (zhanghai)
  • 4c4ddab — [Refactor] Remove pre-21 resources. (zhanghai)
  • 1f7e07e — [Feature] Bump minSdkVersion to 21. (zhanghai)
  • 748b9b6 — [Feature] Update dependencies. (zhanghai)
  • 205d40a — [Feature] Update dependency. (zhanghai)

🔒Security observations

The Douya codebase has significant security concerns primarily related to outdated and deprecated dependencies. The most critical issues are: (1) use of obsolete Crashlytics SDK that is no longer maintained, (2) open-ended Fabric Gradle plugin version that can auto-update to insecure versions, (3) outdated build tools and target SDK version not meeting current standards. The project also shows

  • High · Outdated Build Tools and Deprecated Gradle Plugin — app/build.gradle. The project uses buildToolsVersion '28.0.3' (deprecated) and compileSdkVersion 29 (outdated). More critically, it uses 'io.fabric:gradle:1.+' with an open-ended version specification, which can introduce breaking changes and security issues automatically. Fix: Update to latest stable buildToolsVersion (e.g., 34.0.0+), compileSdkVersion 34+, and pin Fabric Gradle plugin to a specific secure version or migrate to Firebase Crashlytics.
  • High · Insecure Dependency Version Management — app/build.gradle (buildscript dependencies). The Fabric Gradle plugin uses an open-ended version constraint 'classpath 'io.fabric.tools:gradle:1.+'' which bypasses security controls and can auto-update to potentially compromised versions without developer awareness. Fix: Replace 'io.fabric.tools:gradle:1.+' with a pinned version like 'io.fabric.tools:gradle:1.31.2' or migrate to Firebase Crashlytics which is the recommended replacement.
  • High · Outdated Crashlytics SDK — app/build.gradle (dependencies). The project uses 'com.crashlytics.sdk.android:answers:1.4.6' which is obsolete. Crashlytics SDK was deprecated and merged into Firebase. This version has known vulnerabilities and is no longer maintained. Fix: Migrate to Firebase Crashlytics SDK (com.google.firebase:firebase-crashlytics). The legacy Crashlytics SDK is no longer supported.
  • Medium · Incomplete Dependency Declaration — app/build.gradle (line ending with 'implementation' only). The build.gradle file has an incomplete dependency declaration: 'implementation' with no artifact specified. This indicates potential build issues and incomplete migration. Fix: Complete the dependency declaration by specifying the artifact name and version. Remove the orphaned line if not needed.
  • Medium · Missing ProGuard/R8 Configuration for Third-Party Libraries — app/build.gradle and app/proguard-rules.pro. While proguard-rules.pro exists, there's no evidence of specific rules for external dependencies like PhotoView, LunarCalendar, and Crashlytics which may have reflection-heavy code. Fix: Ensure proguard-rules.pro includes proper keep rules for all third-party libraries, especially those using reflection or serialization.
  • Medium · Outdated Target SDK Version — app/build.gradle (defaultConfig). targetSdkVersion is set to 29 (released in 2019). Modern Android requires targeting recent API levels to access Google Play Store and ensure compatibility with security patches. Fix: Update targetSdkVersion to 34 or higher to meet current Google Play Store requirements and benefit from latest security features.
  • Low · Potential Signing Configuration Exposure — app/build.gradle (apply from: '../signing.gradle'). The build script references '../signing.gradle' for release signing configuration. If this file contains credentials or keystore passwords, they could be exposed in version control. Fix: Ensure signing.gradle uses environment variables or secure credential management. Never commit keystore passwords or signing keys to version control.
  • Low · Insecure Maven Repository Configuration — app/build.gradle (repositories section). The project uses JitPack (https://jitpack.io) which builds and hosts GitHub repositories on-the-fly. While convenient, this introduces supply chain risk if upstream repositories are compromised. Fix: Verify JitPack dependencies are from trusted sources. Consider using Maven Central or official repositories when available. Implement dependency verification.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Concerning signals · zhanghai/Douya — RepoPilot