Materialistic Hacker News Client

repository·master·Indexed 25 days ago

https://github.com/hidroh/materialistic

A Material Design-based Hacker News client for Android. It utilizes the official Hacker News API, Algolia for search, and the Mercury Web Parser API for readable content. The project includes implementations for managing favorites via FavoriteManager, a comprehensive HackerNewsItem data model for stories and comments, and a SessionManager for tracking viewed items.

Tokens
2K
Snippets
2
Records
14
Agent score
81%

What's inside Materialistic

  1. Build Requirements and Dependencies

    master

    Before building, ensure your environment meets the following requirements and note the external services used by the application.

    Requirements

    • JDK 11
    • Latest Android SDK tools
    • Latest Android platform tools
    • AndroidX

    External APIs and Services

    • Official Hacker News API: Used for core data. Note that user services (login, account creation, voting, commenting) rely on redirecting to the Hacker News website.
    • Algolia Hacker News Search API: Used for search functionality.
    • Mercury Web Parser API: Required if you want to connect to Mercury for web parsing. You must obtain an API key from the Mercury website.
  2. Understand the HackerNewsItem data model

    master

    The HackerNewsItem class is the primary data model representing various Hacker News entities, including stories, comments, jobs, and polls. It implements the Item interface and is Parcelable, allowing it to be passed between Android components.

    Key characteristics:

    • Types: Supports job, story, comment, poll, and pollopt.
    • Hierarchy: Supports parent-child relationships (e.g., comments belonging to a story or another comment) via parent and kids fields.
    • Stateful: Tracks view state such as favorite, viewed, collapsed, and contentExpanded.
    • Navigation: Implements Navigable, allowing traversal through the item hierarchy (up to parent, down to next sibling, etc.).
  3. Check if an item is a favorite

    master

    Use the check(itemId: String?) method to determine if a specific story is currently in the favorites list. This method returns an Observable<Boolean> and is annotated with @WorkerThread, meaning it should be called from a background thread or handled via RxJava operators to avoid blocking the UI.

    @WorkerThread
    fun check(itemId: String?) = Observable.just(if (itemId.isNullOrEmpty()) {
      false
    } else {
      cache.isFavorite(itemId)
    })!!
  4. Retrieve formatted display strings for HackerNewsItem

    master

    The class provides methods to get Spannable strings ready for UI rendering:

    • getDisplayedAuthor(Context context, boolean linkify, int color): Returns a Spannable containing the author's name. If linkify is true, the author's name is a clickable link that opens their profile.
    • getDisplayedTime(Context context): Returns a Spannable representing the abbreviated time. If the item is deleted, the time will have a strikethrough. If the item is dead, it will include a 'dead' prefix.
  5. Access HackerNewsItem properties and metadata

    master

    Use the following methods to retrieve data from a HackerNewsItem instance:

    • getId() / getLongId(): Returns the unique identifier of the item.
    • getTitle(): Returns the title of the story or poll.
    • getDisplayedTitle(): Returns the title for stories/polls, or the item's text if it is a comment.
    • getText(): Returns the raw HTML text (for comments, polls, etc.).
    • getDisplayedText(): Returns the HTML text converted into a CharSequence (processed via AppUtils.fromHtml).
    • getType(): Returns the item type (e.g., STORY_TYPE, COMMENT_TYPE).
    • getBy(): Returns the username of the author.
    • getTime(): Returns the creation time as Unix Time.
    • getScore(): Returns the item's score or poll option votes.
    • getUrl(): Returns the URL of the story or a generated web link for comments/jobs.
    • getSource(): Returns the host of the item's URL.
    • getKids(): Returns an array of IDs for child items.
    • getKidCount(): Returns the number of descendants or child IDs.
    • isStoryType(): Returns true if the item is a STORY_TYPE, POLL_TYPE, or JOB_TYPE.
  6. Navigate through HackerNewsItem hierarchy

    master

    The HackerNewsItem implements the Navigable interface, allowing you to move through the tree of items using getNeighbour(int direction).

    Supported directions:

    • Navigable.DIRECTION_UP: Returns the previous sibling.
    • Navigable.DIRECTION_DOWN: Returns the next sibling.
    • Navigable.DIRECTION_LEFT: Returns the parent (if level > 1).
    • Navigable.DIRECTION_RIGHT: Returns the first child (kids[0]).
  7. Export favorites to a file

    master

    The export(context, query) method exports all favorites (optionally filtered by a query) to a file named materialistic-export.txt located in the application's saved directory.

    The export process:

    1. Runs on a background IO thread.
    2. Displays a progress notification.
    3. Once complete, it displays a high-priority notification with a content intent that allows the user to share the exported file via a system chooser.

    The exported file format follows this pattern for each item:

    Title
    URL
    Path
    
  8. Manage favorite items with FavoriteManager

    master

    The FavoriteManager class provides an API for managing, persisting, and exporting favorite Hacker News stories. It implements LocalItemManager<Favorite>, allowing you to observe changes to the favorites list.

    Key capabilities include:

    • Adding/Removing: Add a single WebItem or remove items by ID or collection of IDs.
    • Clearing: Remove all favorites or those matching a specific query.
    • Exporting: Export favorites to a text file (materialistic-export.txt) via a background process that notifies the user through Android notifications.
    • Checking Status: Verify if a specific item is currently marked as a favorite.
    • Observing: Attach an Observer to receive updates when the favorites list changes.
  9. Manage HackerNewsItem view state

    master

    You can programmatically update the local view state of an item:

    • setFavorite(boolean favorite) / isFavorite(): Toggles the favorite status.
    • setIsViewed(boolean viewed) / isViewed(): Toggles whether the item has been viewed.
    • setCollapsed(boolean collapsed) / isCollapsed(): Toggles whether the item's content is collapsed.
    • setContentExpanded(boolean expanded) / isContentExpanded(): Toggles whether the content is expanded.
    • incrementScore(): Increments the item's score and marks it as voted and pendingVoted.
  10. Use ReadabilityClient to fetch readable web content

    master

    The ReadabilityClient interface is used to fetch and parse the readable version of a web article (using the Postlight Mercury API). It supports both asynchronous callback-based parsing and synchronous-style parsing intended for background threads.

    Asynchronous Parsing with Callback

    Use parse(String itemId, String url, Callback callback) to fetch content. The result is delivered to the onResponse(String content) method of the provided Callback on the main thread. If no content is found, the content string may be null.

    Background Parsing

    Use parse(String itemId, String url) when you are already running on a background thread (annotated with @WorkerThread). This method performs the work and handles caching internally but does not return a result via a callback.

  11. ReadabilityClient.Callback interface

    master

    The Callback interface is used to receive the result of an asynchronous parse operation.

    • onResponse(String content): Called when the parsing operation completes. The content parameter contains the HTML string of the readable article. If the content is empty or cannot be retrieved, this may return null or an empty state.
    interface Callback {
        void onResponse(String content);
    }