Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ public static class PdfReaderSetting {
public static class CbxReaderSetting {
private CbxPageSpread pageSpread;
private CbxPageViewMode pageViewMode;
private CbxPageFitMode fitMode;
private CbxPageScrollMode scrollMode;
private CbxBackgroundColor backgroundColor;
}

@Data
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.adityachandel.booklore.model.dto;

import com.adityachandel.booklore.model.enums.CbxPageSpread;
import com.adityachandel.booklore.model.enums.CbxPageViewMode;
import com.adityachandel.booklore.model.enums.*;
import lombok.Builder;
import lombok.Data;

Expand All @@ -11,4 +10,7 @@ public class CbxViewerPreferences {
private Long bookId;
private CbxPageSpread pageSpread;
private CbxPageViewMode pageViewMode;
private CbxPageFitMode fitMode;
private CbxPageScrollMode scrollMode;
private CbxBackgroundColor backgroundColor;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.adityachandel.booklore.model.entity;

import com.adityachandel.booklore.model.enums.CbxPageSpread;
import com.adityachandel.booklore.model.enums.CbxPageViewMode;
import com.adityachandel.booklore.model.enums.*;
import jakarta.persistence.*;
import lombok.*;

Expand Down Expand Up @@ -33,4 +32,16 @@ public class CbxViewerPreferencesEntity {
@Column(name = "view_mode")
@Enumerated(EnumType.STRING)
private CbxPageViewMode pageViewMode;

@Column(name = "fit_mode")
@Enumerated(EnumType.STRING)
private CbxPageFitMode fitMode;

@Column(name = "scroll_mode")
@Enumerated(EnumType.STRING)
private CbxPageScrollMode scrollMode;

@Column(name = "background_color")
@Enumerated(EnumType.STRING)
private CbxBackgroundColor backgroundColor;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.adityachandel.booklore.model.enums;

public enum CbxBackgroundColor {
GRAY,
BLACK,
WHITE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.adityachandel.booklore.model.enums;

public enum CbxPageFitMode {
ACTUAL_SIZE,
FIT_PAGE,
FIT_WIDTH,
FIT_HEIGHT,
AUTO
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.adityachandel.booklore.model.enums;

public enum CbxPageScrollMode {
PAGINATED,
INFINITE
}
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ public BookViewerSettings getBookViewerSetting(long bookId) {
.bookId(bookId)
.pageViewMode(cbxPref.getPageViewMode())
.pageSpread(cbxPref.getPageSpread())
.fitMode(cbxPref.getFitMode())
.scrollMode(cbxPref.getScrollMode())
.backgroundColor(cbxPref.getBackgroundColor())
.build()));
} else {
throw ApiError.UNSUPPORTED_BOOK_TYPE.createException();
Expand Down Expand Up @@ -295,6 +298,9 @@ public void updateBookViewerSetting(long bookId, BookViewerSettings bookViewerSe
CbxViewerPreferences cbxSettings = bookViewerSettings.getCbxSettings();
cbxPrefs.setPageSpread(cbxSettings.getPageSpread());
cbxPrefs.setPageViewMode(cbxSettings.getPageViewMode());
cbxPrefs.setFitMode(cbxSettings.getFitMode());
cbxPrefs.setScrollMode(cbxSettings.getScrollMode());
cbxPrefs.setBackgroundColor(cbxSettings.getBackgroundColor());
cbxViewerPreferencesRepository.save(cbxPrefs);

} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ private BookLoreUser.UserSettings.CbxReaderSetting buildDefaultCbxReaderSetting(
return BookLoreUser.UserSettings.CbxReaderSetting.builder()
.pageViewMode(CbxPageViewMode.SINGLE_PAGE)
.pageSpread(CbxPageSpread.ODD)
.fitMode(CbxPageFitMode.FIT_HEIGHT)
.scrollMode(CbxPageScrollMode.PAGINATED)
.backgroundColor(CbxBackgroundColor.GRAY)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,6 @@ public void updateUserSetting(Long userId, UpdateUserSettingRequest request) {
userRepository.save(user);
}

public List<BookLoreUser> getUsersWithLibraryAccess(Long libraryId) {
return userRepository.findAllByLibraries_Id(libraryId)
.stream()
.map(bookLoreUserTransformer::toDTO)
.collect(Collectors.toList());
}

private boolean meetsMinimumPasswordRequirements(String password) {
return password != null && password.length() >= 6;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE cbx_viewer_preference
ADD COLUMN fit_mode VARCHAR(16) NULL,
ADD COLUMN scroll_mode VARCHAR(16) NULL,
ADD COLUMN background_color VARCHAR(16) NULL;

138 changes: 117 additions & 21 deletions booklore-ui/src/app/book/components/cbx-reader/cbx-reader.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
[max]="pages.length"
placeholder="Page"
class="page-input"
/>
/>
<button
class="go-button"
(click)="goToPageInput !== null && goToPage(goToPageInput)"
Expand Down Expand Up @@ -40,40 +40,136 @@
</div>

<div class="spread-controls">
@if (isTwoPageView) {
<button class="view-button spread-toggle" (click)="toggleSpreadDirection()" title="Toggle Spread Direction">
<span>{{ pageSpread === 'ODD' ? '⬅️' : '➡️' }}</span>
<div class="desktop-controls">
<div class="fit-mode-dropdown">
<button class="view-button fit-mode-toggle"
(click)="toggleFitModeDropdown()"
title="Fit Mode">
<span>{{ displayLabel }}</span>
</button>
@if (showFitModeDropdown) {
<div class="fit-mode-menu">
@for (mode of fitModeOptions; track mode.value) {
<button
class="fit-mode-option"
[class.active]="fitMode === mode.value"
(click)="selectFitMode(mode.value)">
<span class="fit-mode-icon">{{ mode.icon }}</span>
<span class="fit-mode-label">{{ mode.label }}</span>
</button>
}
</div>
}
</div>
<button class="view-button scroll-toggle" (click)="toggleScrollMode()" title="Toggle Scroll Mode">
<span>{{ scrollModeIcon }}</span>
</button>
}
<button class="view-button layout-toggle" (click)="toggleView()" title="Toggle View">
<span>{{ isTwoPageView ? '📄' : '📖' }}</span>
</button>
<button class="view-button background-toggle" (click)="toggleBackground()" title="Toggle Background Color">
<span>{{ backgroundColorIcon }}</span>
</button>
@if (isTwoPageView && scrollMode === CbxScrollMode.PAGINATED) {
<button class="view-button spread-toggle" (click)="toggleSpreadDirection()" title="Toggle Spread Direction">
<span>{{ pageSpread === CbxPageSpread.ODD ? '⬅️' : '➡️' }}</span>
</button>
}
@if (scrollMode === CbxScrollMode.PAGINATED) {
<button class="view-button layout-toggle" (click)="toggleView()" title="Toggle View">
<span>{{ isTwoPageView ? '📄' : '📖' }}</span>
</button>
}
<button class="view-button background-toggle" (click)="toggleBackground()" title="Toggle Background Color">
<span>{{ backgroundColorIcon }}</span>
</button>
</div>

<div class="mobile-controls">
<button class="view-button more-options-toggle"
(click)="toggleMobileOptionsDropdown()"
title="More Options">
<span>⋮</span>
</button>
@if (showMobileOptionsDropdown) {
<div class="mobile-options-menu">
<button class="mobile-option" (click)="selectMobileOption('fitMode')">
<span class="option-icon">{{ displayLabel }}</span>
<span class="option-label">Fit Mode</span>
</button>
@if (showFitModeSubmenu) {
<div class="submenu">
@for (mode of fitModeOptions; track mode.value) {
<button
class="submenu-option"
[class.active]="fitMode === mode.value"
(click)="selectFitModeFromMobile(mode.value)">
<span class="fit-mode-icon">{{ mode.icon }}</span>
<span class="fit-mode-label">{{ mode.label }}</span>
</button>
}
</div>
}
<button class="mobile-option" (click)="toggleScrollModeFromMobile()">
<span class="option-icon">{{ scrollModeIcon }}</span>
<span class="option-label">Scroll Mode</span>
</button>
@if (isTwoPageView && scrollMode === CbxScrollMode.PAGINATED) {
<button class="mobile-option" (click)="toggleSpreadDirectionFromMobile()">
<span class="option-icon">{{ pageSpread === CbxPageSpread.ODD ? '⬅️' : '➡️' }}</span>
<span class="option-label">Spread Direction</span>
</button>
}
@if (scrollMode === CbxScrollMode.PAGINATED) {
<button class="mobile-option" (click)="toggleViewFromMobile()">
<span class="option-icon">{{ isTwoPageView ? '📄' : '📖' }}</span>
<span class="option-label">Layout</span>
</button>
}
<button class="mobile-option" (click)="toggleBackgroundFromMobile()">
<span class="option-icon">{{ backgroundColorIcon }}</span>
<span class="option-label">Background</span>
</button>
</div>
}
</div>
</div>
</div>

<div class="image-container"
[class.two-page-view]="isTwoPageView"
[class.bg-black]="backgroundColor === 'black'"
[class.bg-gray]="backgroundColor === 'gray'"
[class.bg-white]="backgroundColor === 'white'">
[class.two-page-view]="isTwoPageView && scrollMode === CbxScrollMode.PAGINATED"
[class.infinite-scroll]="scrollMode === CbxScrollMode.INFINITE"
[class.fit-actual-size]="fitMode === CbxFitMode.ACTUAL_SIZE"
[class.fit-page]="fitMode === CbxFitMode.FIT_PAGE"
[class.fit-width]="fitMode === CbxFitMode.FIT_WIDTH"
[class.fit-height]="fitMode === CbxFitMode.FIT_HEIGHT"
[class.fit-auto]="fitMode === CbxFitMode.AUTO"
[class.bg-black]="backgroundColor === CbxBackgroundColor.BLACK"
[class.bg-gray]="backgroundColor === CbxBackgroundColor.GRAY"
[class.bg-white]="backgroundColor === CbxBackgroundColor.WHITE"
(scroll)="onScroll($event)">
@if (!isLoading) {
@if (pages.length > 0) {
<div class="pages-wrapper">
@for (url of imageUrls; track url) {
<img [src]="url" alt="Page Image" class="page-image"/>
}
</div>
@if (scrollMode === CbxScrollMode.PAGINATED) {
<div class="pages-wrapper">
@for (url of imageUrls; track url) {
<img [src]="url" alt="Page Image" class="page-image"/>
}
</div>
} @else {
<div class="infinite-scroll-wrapper">
@for (url of infiniteScrollImageUrls; track url; let i = $index) {
<img [src]="url" alt="Page {{ infiniteScrollPages[i] + 1 }}" class="page-image"/>
}
@if (isLoadingMore) {
<div class="loading-more">
<p-progressSpinner class="small-spinner"></p-progressSpinner>
</div>
}
</div>
}
} @else {
<div class="no-pages">
<p>No pages available.</p>
</div>
}
} @else {
<div class="loading-container">
<p-progressSpinner styleClass="custom-spinner"></p-progressSpinner>
<p-progressSpinner class="custom-spinner"></p-progressSpinner>
<p class="loading-text">Processing pages... This may take a few seconds on first load. Future loads will be significantly faster.</p>
</div>
}
Expand Down
Loading
Loading