show story progress and reset last read when resetting progress.
This commit is contained in:
@@ -595,6 +595,7 @@ public class StoryController {
|
||||
// Reading progress fields
|
||||
dto.setIsRead(story.getIsRead());
|
||||
dto.setReadingPosition(story.getReadingPosition());
|
||||
dto.setReadingProgressPercentage(calculateReadingProgressPercentage(story));
|
||||
dto.setLastReadAt(story.getLastReadAt());
|
||||
|
||||
if (story.getAuthor() != null) {
|
||||
@@ -614,6 +615,27 @@ public class StoryController {
|
||||
return dto;
|
||||
}
|
||||
|
||||
private Integer calculateReadingProgressPercentage(Story story) {
|
||||
if (story.getReadingPosition() == null || story.getReadingPosition() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Determine the total content length
|
||||
int totalLength = 0;
|
||||
if (story.getContentPlain() != null && !story.getContentPlain().isEmpty()) {
|
||||
totalLength = story.getContentPlain().length();
|
||||
} else if (story.getContentHtml() != null && !story.getContentHtml().isEmpty()) {
|
||||
totalLength = story.getContentHtml().length();
|
||||
}
|
||||
|
||||
if (totalLength == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate percentage and round to nearest integer
|
||||
return Math.round((float) story.getReadingPosition() * 100 / totalLength);
|
||||
}
|
||||
|
||||
private StoryReadingDto convertToReadingDto(Story story) {
|
||||
StoryReadingDto dto = new StoryReadingDto();
|
||||
dto.setId(story.getId());
|
||||
@@ -632,6 +654,7 @@ public class StoryController {
|
||||
// Reading progress fields
|
||||
dto.setIsRead(story.getIsRead());
|
||||
dto.setReadingPosition(story.getReadingPosition());
|
||||
dto.setReadingProgressPercentage(calculateReadingProgressPercentage(story));
|
||||
dto.setLastReadAt(story.getLastReadAt());
|
||||
|
||||
if (story.getAuthor() != null) {
|
||||
|
||||
@@ -31,6 +31,7 @@ public class StoryDto {
|
||||
// Reading progress fields
|
||||
private Boolean isRead;
|
||||
private Integer readingPosition;
|
||||
private Integer readingProgressPercentage; // Pre-calculated percentage (0-100)
|
||||
private LocalDateTime lastReadAt;
|
||||
|
||||
// Related entities as simple references
|
||||
@@ -147,6 +148,14 @@ public class StoryDto {
|
||||
this.readingPosition = readingPosition;
|
||||
}
|
||||
|
||||
public Integer getReadingProgressPercentage() {
|
||||
return readingProgressPercentage;
|
||||
}
|
||||
|
||||
public void setReadingProgressPercentage(Integer readingProgressPercentage) {
|
||||
this.readingProgressPercentage = readingProgressPercentage;
|
||||
}
|
||||
|
||||
public LocalDateTime getLastReadAt() {
|
||||
return lastReadAt;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ public class StoryReadingDto {
|
||||
// Reading progress fields
|
||||
private Boolean isRead;
|
||||
private Integer readingPosition;
|
||||
private Integer readingProgressPercentage; // Pre-calculated percentage (0-100)
|
||||
private LocalDateTime lastReadAt;
|
||||
|
||||
// Related entities as simple references
|
||||
@@ -136,6 +137,14 @@ public class StoryReadingDto {
|
||||
this.readingPosition = readingPosition;
|
||||
}
|
||||
|
||||
public Integer getReadingProgressPercentage() {
|
||||
return readingProgressPercentage;
|
||||
}
|
||||
|
||||
public void setReadingProgressPercentage(Integer readingProgressPercentage) {
|
||||
this.readingProgressPercentage = readingProgressPercentage;
|
||||
}
|
||||
|
||||
public LocalDateTime getLastReadAt() {
|
||||
return lastReadAt;
|
||||
}
|
||||
|
||||
@@ -287,10 +287,17 @@ public class Story {
|
||||
|
||||
/**
|
||||
* Updates the reading progress and timestamp
|
||||
* When position is 0 or null, resets lastReadAt to null so the story won't appear in "last read" sorting
|
||||
*/
|
||||
public void updateReadingProgress(Integer position) {
|
||||
this.readingPosition = position;
|
||||
this.lastReadAt = LocalDateTime.now();
|
||||
// Only update lastReadAt if there's actual reading progress
|
||||
// Reset to null when position is 0 or null to remove from "last read" sorting
|
||||
if (position == null || position == 0) {
|
||||
this.lastReadAt = null;
|
||||
} else {
|
||||
this.lastReadAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -85,7 +85,8 @@ class StoryServiceTest {
|
||||
Story result = storyService.updateReadingProgress(testId, position);
|
||||
|
||||
assertEquals(0, result.getReadingPosition());
|
||||
assertNotNull(result.getLastReadAt());
|
||||
// When position is 0, lastReadAt should be reset to null so the story doesn't appear in "last read" sorting
|
||||
assertNull(result.getLastReadAt());
|
||||
verify(storyRepository).save(testStory);
|
||||
}
|
||||
|
||||
@@ -111,7 +112,8 @@ class StoryServiceTest {
|
||||
Story result = storyService.updateReadingProgress(testId, position);
|
||||
|
||||
assertNull(result.getReadingPosition());
|
||||
assertNotNull(result.getLastReadAt());
|
||||
// When position is null, lastReadAt should be reset to null so the story doesn't appear in "last read" sorting
|
||||
assertNull(result.getLastReadAt());
|
||||
verify(storyRepository).save(testStory);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,16 +72,8 @@ export default function StoryCard({
|
||||
return new Date(dateString).toLocaleDateString();
|
||||
};
|
||||
|
||||
const calculateReadingPercentage = (story: Story): number => {
|
||||
if (!story.readingPosition) return 0;
|
||||
|
||||
const totalLength = story.contentPlain?.length || story.contentHtml?.length || 0;
|
||||
if (totalLength === 0) return 0;
|
||||
|
||||
return Math.round((story.readingPosition / totalLength) * 100);
|
||||
};
|
||||
|
||||
const readingPercentage = calculateReadingPercentage(story);
|
||||
// Use the pre-calculated percentage from the backend
|
||||
const readingPercentage = story.readingProgressPercentage || 0;
|
||||
|
||||
if (viewMode === 'list') {
|
||||
return (
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface Story {
|
||||
tags: Tag[];
|
||||
tagNames?: string[] | null; // Used in search results
|
||||
readingPosition?: number;
|
||||
readingProgressPercentage?: number; // Pre-calculated percentage (0-100) from backend
|
||||
lastReadAt?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user