This repository has been archived on 2026-07-21. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
cloud-reader/backend/apps/books/models.py
T
Marko (Hermes Implementer) b29ea8211c feat: customizable mobile reading experience
- Backend: Chapter, ReadingProgress, ReadingSettings models
- Backend: Chapter API (TOC + content), progress tracking, settings CRUD
- Frontend: ReadingPage with chapter navigation
- Frontend: TableOfContents drawer
- Frontend: ReadingSettingsPanel (theme, font, size, orientation)
- Frontend: Custom hooks for settings, chapters, progress tracking
- CSS: Mobile-first reading view with sepia/dark/light/paper themes
- Route: /reader/:bookId reading view from book detail page
- Docs: 001-customizable-mobile-reading-experience.md
2026-05-29 02:55:36 +00:00

88 lines
2.6 KiB
Python

from django.db import models
class Book(models.Model):
"""Represents a book in the user's library."""
title = models.CharField(max_length=512)
author = models.CharField(max_length=256, blank=True, default="")
total_pages = models.PositiveIntegerField(default=0)
cover_image = models.URLField(blank=True, default="")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "books_book"
verbose_name = "Book"
verbose_name_plural = "Books"
ordering = ["title"]
def __str__(self) -> str:
return self.title
class Chapter(models.Model):
"""A chapter within a book, containing the text/markdown content."""
book = models.ForeignKey(
Book,
on_delete=models.CASCADE,
related_name="chapters",
db_index=True,
)
title = models.CharField(max_length=512)
number = models.PositiveIntegerField()
content = models.TextField(blank=True, default="")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "books_chapter"
verbose_name = "Chapter"
verbose_name_plural = "Chapters"
ordering = ["book", "number"]
constraints = [
models.UniqueConstraint(
fields=["book", "number"],
name="uq_book_chapter_number",
)
]
def __str__(self) -> str:
return f"{self.book.title} — Ch. {self.number}: {self.title}"
class ReadingProgress(models.Model):
"""Tracks a user's reading progress within a book."""
user = models.ForeignKey(
"users.User",
on_delete=models.CASCADE,
related_name="reading_progress",
db_index=True,
)
book = models.ForeignKey(
Book,
on_delete=models.CASCADE,
related_name="reading_progress",
db_index=True,
)
current_chapter = models.PositiveIntegerField(default=1)
current_position = models.PositiveIntegerField(default=0)
percentage = models.FloatField(default=0.0)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "books_reading_progress"
verbose_name = "Reading Progress"
verbose_name_plural = "Reading Progress"
ordering = ["-updated_at"]
constraints = [
models.UniqueConstraint(
fields=["user", "book"],
name="uq_reading_progress_user_book",
)
]
def __str__(self) -> str:
return f"{self.user}{self.book.title} ({self.percentage:.0f}%)"