Refactor auto-scroll functionality in novel reader

- Removed the NovelAutoScrollState provider and its associated logic.
- Introduced autoScrollValues and setAutoScroll methods in NovelReaderController to manage auto-scroll settings.
- Updated NovelReaderView to handle auto-scroll state and page offset dynamically.
- Added UI elements in GeneralSettingsTab to control auto-scroll settings with a slider for page offset.
- Enhanced the auto-scroll feature to allow for play/pause functionality within the novel reader view.
This commit is contained in:
Moustapha Kodjo Amadou 2025-11-08 19:47:23 +01:00
parent af20e084b0
commit c28ab14e74
9 changed files with 592 additions and 571 deletions

View file

@ -254,8 +254,6 @@ class Settings {
bool? novelShowScrollPercentage;
bool? novelAutoScroll;
bool? novelRemoveExtraParagraphSpacing;
bool? novelTapToScroll;
@ -413,7 +411,6 @@ class Settings {
this.novelReaderPadding = 16,
this.novelReaderLineHeight = 1.5,
this.novelShowScrollPercentage = true,
this.novelAutoScroll = false,
this.novelRemoveExtraParagraphSpacing = false,
this.novelTapToScroll = false,
this.navigationOrder,
@ -642,7 +639,6 @@ class Settings {
novelReaderLineHeight = json['novelReaderLineHeight'];
}
novelShowScrollPercentage = json['novelShowScrollPercentage'];
novelAutoScroll = json['novelAutoScroll'];
novelRemoveExtraParagraphSpacing = json['novelRemoveExtraParagraphSpacing'];
novelTapToScroll = json['novelTapToScroll'];
if (json['navigationOrder'] != null) {
@ -828,7 +824,6 @@ class Settings {
'novelReaderPadding': novelReaderPadding,
'novelReaderLineHeight': novelReaderLineHeight,
'novelShowScrollPercentage': novelShowScrollPercentage,
'novelAutoScroll': novelAutoScroll,
'novelRemoveExtraParagraphSpacing': novelRemoveExtraParagraphSpacing,
'novelTapToScroll': novelTapToScroll,
'navigationOrder': navigationOrder,

View file

@ -529,252 +529,247 @@ const SettingsSchema = CollectionSchema(
name: r'navigationOrder',
type: IsarType.stringList,
),
r'novelAutoScroll': PropertySchema(
id: 95,
name: r'novelAutoScroll',
type: IsarType.bool,
),
r'novelDisplayType': PropertySchema(
id: 96,
id: 95,
name: r'novelDisplayType',
type: IsarType.byte,
enumMap: _SettingsnovelDisplayTypeEnumValueMap,
),
r'novelExtensionsRepo': PropertySchema(
id: 97,
id: 96,
name: r'novelExtensionsRepo',
type: IsarType.objectList,
target: r'Repo',
),
r'novelFontSize': PropertySchema(
id: 98,
id: 97,
name: r'novelFontSize',
type: IsarType.long,
),
r'novelGridSize': PropertySchema(
id: 99,
id: 98,
name: r'novelGridSize',
type: IsarType.long,
),
r'novelLibraryDownloadedChapters': PropertySchema(
id: 100,
id: 99,
name: r'novelLibraryDownloadedChapters',
type: IsarType.bool,
),
r'novelLibraryLocalSource': PropertySchema(
id: 101,
id: 100,
name: r'novelLibraryLocalSource',
type: IsarType.bool,
),
r'novelLibraryShowCategoryTabs': PropertySchema(
id: 102,
id: 101,
name: r'novelLibraryShowCategoryTabs',
type: IsarType.bool,
),
r'novelLibraryShowContinueReadingButton': PropertySchema(
id: 103,
id: 102,
name: r'novelLibraryShowContinueReadingButton',
type: IsarType.bool,
),
r'novelLibraryShowLanguage': PropertySchema(
id: 104,
id: 103,
name: r'novelLibraryShowLanguage',
type: IsarType.bool,
),
r'novelLibraryShowNumbersOfItems': PropertySchema(
id: 105,
id: 104,
name: r'novelLibraryShowNumbersOfItems',
type: IsarType.bool,
),
r'novelReaderLineHeight': PropertySchema(
id: 106,
id: 105,
name: r'novelReaderLineHeight',
type: IsarType.double,
),
r'novelReaderPadding': PropertySchema(
id: 107,
id: 106,
name: r'novelReaderPadding',
type: IsarType.long,
),
r'novelReaderTextColor': PropertySchema(
id: 108,
id: 107,
name: r'novelReaderTextColor',
type: IsarType.string,
),
r'novelReaderTheme': PropertySchema(
id: 109,
id: 108,
name: r'novelReaderTheme',
type: IsarType.string,
),
r'novelRemoveExtraParagraphSpacing': PropertySchema(
id: 110,
id: 109,
name: r'novelRemoveExtraParagraphSpacing',
type: IsarType.bool,
),
r'novelShowScrollPercentage': PropertySchema(
id: 111,
id: 110,
name: r'novelShowScrollPercentage',
type: IsarType.bool,
),
r'novelTapToScroll': PropertySchema(
id: 112,
id: 111,
name: r'novelTapToScroll',
type: IsarType.bool,
),
r'novelTextAlign': PropertySchema(
id: 113,
id: 112,
name: r'novelTextAlign',
type: IsarType.byte,
enumMap: _SettingsnovelTextAlignEnumValueMap,
),
r'onlyIncludePinnedSources': PropertySchema(
id: 114,
id: 113,
name: r'onlyIncludePinnedSources',
type: IsarType.bool,
),
r'pagePreloadAmount': PropertySchema(
id: 115,
id: 114,
name: r'pagePreloadAmount',
type: IsarType.long,
),
r'personalPageModeList': PropertySchema(
id: 116,
id: 115,
name: r'personalPageModeList',
type: IsarType.objectList,
target: r'PersonalPageMode',
),
r'personalReaderModeList': PropertySchema(
id: 117,
id: 116,
name: r'personalReaderModeList',
type: IsarType.objectList,
target: r'PersonalReaderMode',
),
r'playerSubtitleSettings': PropertySchema(
id: 118,
id: 117,
name: r'playerSubtitleSettings',
type: IsarType.object,
target: r'PlayerSubtitleSettings',
),
r'pureBlackDarkMode': PropertySchema(
id: 119,
id: 118,
name: r'pureBlackDarkMode',
type: IsarType.bool,
),
r'relativeTimesTamps': PropertySchema(
id: 120,
id: 119,
name: r'relativeTimesTamps',
type: IsarType.long,
),
r'rpcShowCoverImage': PropertySchema(
id: 121,
id: 120,
name: r'rpcShowCoverImage',
type: IsarType.bool,
),
r'rpcShowReadingWatchingProgress': PropertySchema(
id: 122,
id: 121,
name: r'rpcShowReadingWatchingProgress',
type: IsarType.bool,
),
r'rpcShowTitle': PropertySchema(
id: 123,
id: 122,
name: r'rpcShowTitle',
type: IsarType.bool,
),
r'saveAsCBZArchive': PropertySchema(
id: 124,
id: 123,
name: r'saveAsCBZArchive',
type: IsarType.bool,
),
r'scaleType': PropertySchema(
id: 125,
id: 124,
name: r'scaleType',
type: IsarType.byte,
enumMap: _SettingsscaleTypeEnumValueMap,
),
r'showPagesNumber': PropertySchema(
id: 126,
id: 125,
name: r'showPagesNumber',
type: IsarType.bool,
),
r'sortChapterList': PropertySchema(
id: 127,
id: 126,
name: r'sortChapterList',
type: IsarType.objectList,
target: r'SortChapter',
),
r'sortLibraryAnime': PropertySchema(
id: 128,
id: 127,
name: r'sortLibraryAnime',
type: IsarType.object,
target: r'SortLibraryManga',
),
r'sortLibraryManga': PropertySchema(
id: 129,
id: 128,
name: r'sortLibraryManga',
type: IsarType.object,
target: r'SortLibraryManga',
),
r'sortLibraryNovel': PropertySchema(
id: 130,
id: 129,
name: r'sortLibraryNovel',
type: IsarType.object,
target: r'SortLibraryManga',
),
r'startDatebackup': PropertySchema(
id: 131,
id: 130,
name: r'startDatebackup',
type: IsarType.long,
),
r'themeIsDark': PropertySchema(
id: 132,
id: 131,
name: r'themeIsDark',
type: IsarType.bool,
),
r'updateProgressAfterReading': PropertySchema(
id: 133,
id: 132,
name: r'updateProgressAfterReading',
type: IsarType.bool,
),
r'updatedAt': PropertySchema(
id: 134,
id: 133,
name: r'updatedAt',
type: IsarType.long,
),
r'useLibass': PropertySchema(
id: 135,
id: 134,
name: r'useLibass',
type: IsarType.bool,
),
r'useMpvConfig': PropertySchema(
id: 136,
id: 135,
name: r'useMpvConfig',
type: IsarType.bool,
),
r'usePageTapZones': PropertySchema(
id: 137,
id: 136,
name: r'usePageTapZones',
type: IsarType.bool,
),
r'useYUV420P': PropertySchema(
id: 138,
id: 137,
name: r'useYUV420P',
type: IsarType.bool,
),
r'userAgent': PropertySchema(
id: 139,
id: 138,
name: r'userAgent',
type: IsarType.string,
),
r'volumeBoostCap': PropertySchema(
id: 140,
id: 139,
name: r'volumeBoostCap',
type: IsarType.long,
),
@ -1438,92 +1433,91 @@ void _settingsSerialize(
writer.writeLong(offsets[92], object.markEpisodeAsSeenType);
writer.writeBool(offsets[93], object.mergeLibraryNavMobile);
writer.writeStringList(offsets[94], object.navigationOrder);
writer.writeBool(offsets[95], object.novelAutoScroll);
writer.writeByte(offsets[96], object.novelDisplayType.index);
writer.writeByte(offsets[95], object.novelDisplayType.index);
writer.writeObjectList<Repo>(
offsets[97],
offsets[96],
allOffsets,
RepoSchema.serialize,
object.novelExtensionsRepo,
);
writer.writeLong(offsets[98], object.novelFontSize);
writer.writeLong(offsets[99], object.novelGridSize);
writer.writeBool(offsets[100], object.novelLibraryDownloadedChapters);
writer.writeBool(offsets[101], object.novelLibraryLocalSource);
writer.writeBool(offsets[102], object.novelLibraryShowCategoryTabs);
writer.writeBool(offsets[103], object.novelLibraryShowContinueReadingButton);
writer.writeBool(offsets[104], object.novelLibraryShowLanguage);
writer.writeBool(offsets[105], object.novelLibraryShowNumbersOfItems);
writer.writeDouble(offsets[106], object.novelReaderLineHeight);
writer.writeLong(offsets[107], object.novelReaderPadding);
writer.writeString(offsets[108], object.novelReaderTextColor);
writer.writeString(offsets[109], object.novelReaderTheme);
writer.writeBool(offsets[110], object.novelRemoveExtraParagraphSpacing);
writer.writeBool(offsets[111], object.novelShowScrollPercentage);
writer.writeBool(offsets[112], object.novelTapToScroll);
writer.writeByte(offsets[113], object.novelTextAlign.index);
writer.writeBool(offsets[114], object.onlyIncludePinnedSources);
writer.writeLong(offsets[115], object.pagePreloadAmount);
writer.writeLong(offsets[97], object.novelFontSize);
writer.writeLong(offsets[98], object.novelGridSize);
writer.writeBool(offsets[99], object.novelLibraryDownloadedChapters);
writer.writeBool(offsets[100], object.novelLibraryLocalSource);
writer.writeBool(offsets[101], object.novelLibraryShowCategoryTabs);
writer.writeBool(offsets[102], object.novelLibraryShowContinueReadingButton);
writer.writeBool(offsets[103], object.novelLibraryShowLanguage);
writer.writeBool(offsets[104], object.novelLibraryShowNumbersOfItems);
writer.writeDouble(offsets[105], object.novelReaderLineHeight);
writer.writeLong(offsets[106], object.novelReaderPadding);
writer.writeString(offsets[107], object.novelReaderTextColor);
writer.writeString(offsets[108], object.novelReaderTheme);
writer.writeBool(offsets[109], object.novelRemoveExtraParagraphSpacing);
writer.writeBool(offsets[110], object.novelShowScrollPercentage);
writer.writeBool(offsets[111], object.novelTapToScroll);
writer.writeByte(offsets[112], object.novelTextAlign.index);
writer.writeBool(offsets[113], object.onlyIncludePinnedSources);
writer.writeLong(offsets[114], object.pagePreloadAmount);
writer.writeObjectList<PersonalPageMode>(
offsets[116],
offsets[115],
allOffsets,
PersonalPageModeSchema.serialize,
object.personalPageModeList,
);
writer.writeObjectList<PersonalReaderMode>(
offsets[117],
offsets[116],
allOffsets,
PersonalReaderModeSchema.serialize,
object.personalReaderModeList,
);
writer.writeObject<PlayerSubtitleSettings>(
offsets[118],
offsets[117],
allOffsets,
PlayerSubtitleSettingsSchema.serialize,
object.playerSubtitleSettings,
);
writer.writeBool(offsets[119], object.pureBlackDarkMode);
writer.writeLong(offsets[120], object.relativeTimesTamps);
writer.writeBool(offsets[121], object.rpcShowCoverImage);
writer.writeBool(offsets[122], object.rpcShowReadingWatchingProgress);
writer.writeBool(offsets[123], object.rpcShowTitle);
writer.writeBool(offsets[124], object.saveAsCBZArchive);
writer.writeByte(offsets[125], object.scaleType.index);
writer.writeBool(offsets[126], object.showPagesNumber);
writer.writeBool(offsets[118], object.pureBlackDarkMode);
writer.writeLong(offsets[119], object.relativeTimesTamps);
writer.writeBool(offsets[120], object.rpcShowCoverImage);
writer.writeBool(offsets[121], object.rpcShowReadingWatchingProgress);
writer.writeBool(offsets[122], object.rpcShowTitle);
writer.writeBool(offsets[123], object.saveAsCBZArchive);
writer.writeByte(offsets[124], object.scaleType.index);
writer.writeBool(offsets[125], object.showPagesNumber);
writer.writeObjectList<SortChapter>(
offsets[127],
offsets[126],
allOffsets,
SortChapterSchema.serialize,
object.sortChapterList,
);
writer.writeObject<SortLibraryManga>(
offsets[128],
offsets[127],
allOffsets,
SortLibraryMangaSchema.serialize,
object.sortLibraryAnime,
);
writer.writeObject<SortLibraryManga>(
offsets[129],
offsets[128],
allOffsets,
SortLibraryMangaSchema.serialize,
object.sortLibraryManga,
);
writer.writeObject<SortLibraryManga>(
offsets[130],
offsets[129],
allOffsets,
SortLibraryMangaSchema.serialize,
object.sortLibraryNovel,
);
writer.writeLong(offsets[131], object.startDatebackup);
writer.writeBool(offsets[132], object.themeIsDark);
writer.writeBool(offsets[133], object.updateProgressAfterReading);
writer.writeLong(offsets[134], object.updatedAt);
writer.writeBool(offsets[135], object.useLibass);
writer.writeBool(offsets[136], object.useMpvConfig);
writer.writeBool(offsets[137], object.usePageTapZones);
writer.writeBool(offsets[138], object.useYUV420P);
writer.writeString(offsets[139], object.userAgent);
writer.writeLong(offsets[140], object.volumeBoostCap);
writer.writeLong(offsets[130], object.startDatebackup);
writer.writeBool(offsets[131], object.themeIsDark);
writer.writeBool(offsets[132], object.updateProgressAfterReading);
writer.writeLong(offsets[133], object.updatedAt);
writer.writeBool(offsets[134], object.useLibass);
writer.writeBool(offsets[135], object.useMpvConfig);
writer.writeBool(offsets[136], object.usePageTapZones);
writer.writeBool(offsets[137], object.useYUV420P);
writer.writeString(offsets[138], object.userAgent);
writer.writeLong(offsets[139], object.volumeBoostCap);
}
Settings _settingsDeserialize(
@ -1701,97 +1695,96 @@ Settings _settingsDeserialize(
markEpisodeAsSeenType: reader.readLongOrNull(offsets[92]),
mergeLibraryNavMobile: reader.readBoolOrNull(offsets[93]),
navigationOrder: reader.readStringList(offsets[94]),
novelAutoScroll: reader.readBoolOrNull(offsets[95]),
novelDisplayType:
_SettingsnovelDisplayTypeValueEnumMap[reader.readByteOrNull(
offsets[96],
offsets[95],
)] ??
DisplayType.comfortableGrid,
novelExtensionsRepo: reader.readObjectList<Repo>(
offsets[97],
offsets[96],
RepoSchema.deserialize,
allOffsets,
Repo(),
),
novelFontSize: reader.readLongOrNull(offsets[98]),
novelLibraryDownloadedChapters: reader.readBoolOrNull(offsets[100]),
novelLibraryLocalSource: reader.readBoolOrNull(offsets[101]),
novelLibraryShowCategoryTabs: reader.readBoolOrNull(offsets[102]),
novelLibraryShowContinueReadingButton: reader.readBoolOrNull(offsets[103]),
novelLibraryShowLanguage: reader.readBoolOrNull(offsets[104]),
novelLibraryShowNumbersOfItems: reader.readBoolOrNull(offsets[105]),
novelReaderLineHeight: reader.readDoubleOrNull(offsets[106]),
novelReaderPadding: reader.readLongOrNull(offsets[107]),
novelReaderTextColor: reader.readStringOrNull(offsets[108]),
novelReaderTheme: reader.readStringOrNull(offsets[109]),
novelRemoveExtraParagraphSpacing: reader.readBoolOrNull(offsets[110]),
novelShowScrollPercentage: reader.readBoolOrNull(offsets[111]),
novelTapToScroll: reader.readBoolOrNull(offsets[112]),
novelFontSize: reader.readLongOrNull(offsets[97]),
novelLibraryDownloadedChapters: reader.readBoolOrNull(offsets[99]),
novelLibraryLocalSource: reader.readBoolOrNull(offsets[100]),
novelLibraryShowCategoryTabs: reader.readBoolOrNull(offsets[101]),
novelLibraryShowContinueReadingButton: reader.readBoolOrNull(offsets[102]),
novelLibraryShowLanguage: reader.readBoolOrNull(offsets[103]),
novelLibraryShowNumbersOfItems: reader.readBoolOrNull(offsets[104]),
novelReaderLineHeight: reader.readDoubleOrNull(offsets[105]),
novelReaderPadding: reader.readLongOrNull(offsets[106]),
novelReaderTextColor: reader.readStringOrNull(offsets[107]),
novelReaderTheme: reader.readStringOrNull(offsets[108]),
novelRemoveExtraParagraphSpacing: reader.readBoolOrNull(offsets[109]),
novelShowScrollPercentage: reader.readBoolOrNull(offsets[110]),
novelTapToScroll: reader.readBoolOrNull(offsets[111]),
novelTextAlign:
_SettingsnovelTextAlignValueEnumMap[reader.readByteOrNull(
offsets[113],
offsets[112],
)] ??
NovelTextAlign.left,
onlyIncludePinnedSources: reader.readBoolOrNull(offsets[114]),
pagePreloadAmount: reader.readLongOrNull(offsets[115]),
onlyIncludePinnedSources: reader.readBoolOrNull(offsets[113]),
pagePreloadAmount: reader.readLongOrNull(offsets[114]),
personalPageModeList: reader.readObjectList<PersonalPageMode>(
offsets[116],
offsets[115],
PersonalPageModeSchema.deserialize,
allOffsets,
PersonalPageMode(),
),
personalReaderModeList: reader.readObjectList<PersonalReaderMode>(
offsets[117],
offsets[116],
PersonalReaderModeSchema.deserialize,
allOffsets,
PersonalReaderMode(),
),
playerSubtitleSettings: reader.readObjectOrNull<PlayerSubtitleSettings>(
offsets[118],
offsets[117],
PlayerSubtitleSettingsSchema.deserialize,
allOffsets,
),
pureBlackDarkMode: reader.readBoolOrNull(offsets[119]),
relativeTimesTamps: reader.readLongOrNull(offsets[120]),
rpcShowCoverImage: reader.readBoolOrNull(offsets[121]),
rpcShowReadingWatchingProgress: reader.readBoolOrNull(offsets[122]),
rpcShowTitle: reader.readBoolOrNull(offsets[123]),
saveAsCBZArchive: reader.readBoolOrNull(offsets[124]),
pureBlackDarkMode: reader.readBoolOrNull(offsets[118]),
relativeTimesTamps: reader.readLongOrNull(offsets[119]),
rpcShowCoverImage: reader.readBoolOrNull(offsets[120]),
rpcShowReadingWatchingProgress: reader.readBoolOrNull(offsets[121]),
rpcShowTitle: reader.readBoolOrNull(offsets[122]),
saveAsCBZArchive: reader.readBoolOrNull(offsets[123]),
scaleType:
_SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offsets[125])] ??
_SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offsets[124])] ??
ScaleType.fitScreen,
showPagesNumber: reader.readBoolOrNull(offsets[126]),
showPagesNumber: reader.readBoolOrNull(offsets[125]),
sortChapterList: reader.readObjectList<SortChapter>(
offsets[127],
offsets[126],
SortChapterSchema.deserialize,
allOffsets,
SortChapter(),
),
sortLibraryAnime: reader.readObjectOrNull<SortLibraryManga>(
offsets[128],
offsets[127],
SortLibraryMangaSchema.deserialize,
allOffsets,
),
sortLibraryManga: reader.readObjectOrNull<SortLibraryManga>(
offsets[129],
offsets[128],
SortLibraryMangaSchema.deserialize,
allOffsets,
),
sortLibraryNovel: reader.readObjectOrNull<SortLibraryManga>(
offsets[130],
offsets[129],
SortLibraryMangaSchema.deserialize,
allOffsets,
),
startDatebackup: reader.readLongOrNull(offsets[131]),
themeIsDark: reader.readBoolOrNull(offsets[132]),
updateProgressAfterReading: reader.readBoolOrNull(offsets[133]),
updatedAt: reader.readLongOrNull(offsets[134]),
useLibass: reader.readBoolOrNull(offsets[135]),
useMpvConfig: reader.readBoolOrNull(offsets[136]),
usePageTapZones: reader.readBoolOrNull(offsets[137]),
useYUV420P: reader.readBoolOrNull(offsets[138]),
userAgent: reader.readStringOrNull(offsets[139]),
volumeBoostCap: reader.readLongOrNull(offsets[140]),
startDatebackup: reader.readLongOrNull(offsets[130]),
themeIsDark: reader.readBoolOrNull(offsets[131]),
updateProgressAfterReading: reader.readBoolOrNull(offsets[132]),
updatedAt: reader.readLongOrNull(offsets[133]),
useLibass: reader.readBoolOrNull(offsets[134]),
useMpvConfig: reader.readBoolOrNull(offsets[135]),
usePageTapZones: reader.readBoolOrNull(offsets[136]),
useYUV420P: reader.readBoolOrNull(offsets[137]),
userAgent: reader.readStringOrNull(offsets[138]),
volumeBoostCap: reader.readLongOrNull(offsets[139]),
);
object.chapterFilterBookmarkedList = reader
.readObjectList<ChapterFilterBookmarked>(
@ -1822,7 +1815,7 @@ Settings _settingsDeserialize(
L10nLocaleSchema.deserialize,
allOffsets,
);
object.novelGridSize = reader.readLongOrNull(offsets[99]);
object.novelGridSize = reader.readLongOrNull(offsets[98]);
return object;
}
@ -2138,14 +2131,12 @@ P _settingsDeserializeProp<P>(
case 94:
return (reader.readStringList(offset)) as P;
case 95:
return (reader.readBoolOrNull(offset)) as P;
case 96:
return (_SettingsnovelDisplayTypeValueEnumMap[reader.readByteOrNull(
offset,
)] ??
DisplayType.comfortableGrid)
as P;
case 97:
case 96:
return (reader.readObjectList<Repo>(
offset,
RepoSchema.deserialize,
@ -2153,10 +2144,12 @@ P _settingsDeserializeProp<P>(
Repo(),
))
as P;
case 97:
return (reader.readLongOrNull(offset)) as P;
case 98:
return (reader.readLongOrNull(offset)) as P;
case 99:
return (reader.readLongOrNull(offset)) as P;
return (reader.readBoolOrNull(offset)) as P;
case 100:
return (reader.readBoolOrNull(offset)) as P;
case 101:
@ -2168,32 +2161,30 @@ P _settingsDeserializeProp<P>(
case 104:
return (reader.readBoolOrNull(offset)) as P;
case 105:
return (reader.readBoolOrNull(offset)) as P;
case 106:
return (reader.readDoubleOrNull(offset)) as P;
case 107:
case 106:
return (reader.readLongOrNull(offset)) as P;
case 107:
return (reader.readStringOrNull(offset)) as P;
case 108:
return (reader.readStringOrNull(offset)) as P;
case 109:
return (reader.readStringOrNull(offset)) as P;
return (reader.readBoolOrNull(offset)) as P;
case 110:
return (reader.readBoolOrNull(offset)) as P;
case 111:
return (reader.readBoolOrNull(offset)) as P;
case 112:
return (reader.readBoolOrNull(offset)) as P;
case 113:
return (_SettingsnovelTextAlignValueEnumMap[reader.readByteOrNull(
offset,
)] ??
NovelTextAlign.left)
as P;
case 114:
case 113:
return (reader.readBoolOrNull(offset)) as P;
case 115:
case 114:
return (reader.readLongOrNull(offset)) as P;
case 116:
case 115:
return (reader.readObjectList<PersonalPageMode>(
offset,
PersonalPageModeSchema.deserialize,
@ -2201,7 +2192,7 @@ P _settingsDeserializeProp<P>(
PersonalPageMode(),
))
as P;
case 117:
case 116:
return (reader.readObjectList<PersonalReaderMode>(
offset,
PersonalReaderModeSchema.deserialize,
@ -2209,17 +2200,19 @@ P _settingsDeserializeProp<P>(
PersonalReaderMode(),
))
as P;
case 118:
case 117:
return (reader.readObjectOrNull<PlayerSubtitleSettings>(
offset,
PlayerSubtitleSettingsSchema.deserialize,
allOffsets,
))
as P;
case 119:
case 118:
return (reader.readBoolOrNull(offset)) as P;
case 120:
case 119:
return (reader.readLongOrNull(offset)) as P;
case 120:
return (reader.readBoolOrNull(offset)) as P;
case 121:
return (reader.readBoolOrNull(offset)) as P;
case 122:
@ -2227,14 +2220,12 @@ P _settingsDeserializeProp<P>(
case 123:
return (reader.readBoolOrNull(offset)) as P;
case 124:
return (reader.readBoolOrNull(offset)) as P;
case 125:
return (_SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offset)] ??
ScaleType.fitScreen)
as P;
case 126:
case 125:
return (reader.readBoolOrNull(offset)) as P;
case 127:
case 126:
return (reader.readObjectList<SortChapter>(
offset,
SortChapterSchema.deserialize,
@ -2242,6 +2233,13 @@ P _settingsDeserializeProp<P>(
SortChapter(),
))
as P;
case 127:
return (reader.readObjectOrNull<SortLibraryManga>(
offset,
SortLibraryMangaSchema.deserialize,
allOffsets,
))
as P;
case 128:
return (reader.readObjectOrNull<SortLibraryManga>(
offset,
@ -2257,20 +2255,15 @@ P _settingsDeserializeProp<P>(
))
as P;
case 130:
return (reader.readObjectOrNull<SortLibraryManga>(
offset,
SortLibraryMangaSchema.deserialize,
allOffsets,
))
as P;
case 131:
return (reader.readLongOrNull(offset)) as P;
case 131:
return (reader.readBoolOrNull(offset)) as P;
case 132:
return (reader.readBoolOrNull(offset)) as P;
case 133:
return (reader.readBoolOrNull(offset)) as P;
case 134:
return (reader.readLongOrNull(offset)) as P;
case 134:
return (reader.readBoolOrNull(offset)) as P;
case 135:
return (reader.readBoolOrNull(offset)) as P;
case 136:
@ -2278,10 +2271,8 @@ P _settingsDeserializeProp<P>(
case 137:
return (reader.readBoolOrNull(offset)) as P;
case 138:
return (reader.readBoolOrNull(offset)) as P;
case 139:
return (reader.readStringOrNull(offset)) as P;
case 140:
case 139:
return (reader.readLongOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@ -9451,33 +9442,6 @@ extension SettingsQueryFilter
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
novelAutoScrollIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(
const FilterCondition.isNull(property: r'novelAutoScroll'),
);
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
novelAutoScrollIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(
const FilterCondition.isNotNull(property: r'novelAutoScroll'),
);
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
novelAutoScrollEqualTo(bool? value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(
FilterCondition.equalTo(property: r'novelAutoScroll', value: value),
);
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
novelDisplayTypeEqualTo(DisplayType value) {
return QueryBuilder.apply(this, (query) {
@ -13131,18 +13095,6 @@ extension SettingsQuerySortBy on QueryBuilder<Settings, Settings, QSortBy> {
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByNovelAutoScroll() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'novelAutoScroll', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByNovelAutoScrollDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'novelAutoScroll', Sort.desc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByNovelDisplayType() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'novelDisplayType', Sort.asc);
@ -14651,18 +14603,6 @@ extension SettingsQuerySortThenBy
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByNovelAutoScroll() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'novelAutoScroll', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByNovelAutoScrollDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'novelAutoScroll', Sort.desc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByNovelDisplayType() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'novelDisplayType', Sort.asc);
@ -15703,12 +15643,6 @@ extension SettingsQueryWhereDistinct
});
}
QueryBuilder<Settings, Settings, QDistinct> distinctByNovelAutoScroll() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'novelAutoScroll');
});
}
QueryBuilder<Settings, Settings, QDistinct> distinctByNovelDisplayType() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'novelDisplayType');
@ -16602,12 +16536,6 @@ extension SettingsQueryProperty
});
}
QueryBuilder<Settings, bool?, QQueryOperations> novelAutoScrollProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'novelAutoScroll');
});
}
QueryBuilder<Settings, DisplayType, QQueryOperations>
novelDisplayTypeProperty() {
return QueryBuilder.apply(this, (query) {

View file

@ -403,26 +403,6 @@ class NovelShowScrollPercentageState extends _$NovelShowScrollPercentageState {
}
}
@riverpod
class NovelAutoScrollState extends _$NovelAutoScrollState {
@override
bool build() {
return isar.settings.getSync(227)!.novelAutoScroll ?? false;
}
void set(bool value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings!
..novelAutoScroll = value
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}
@riverpod
class NovelRemoveExtraParagraphSpacingState
extends _$NovelRemoveExtraParagraphSpacingState {

View file

@ -1037,60 +1037,6 @@ abstract class _$NovelShowScrollPercentageState extends $Notifier<bool> {
}
}
@ProviderFor(NovelAutoScrollState)
const novelAutoScrollStateProvider = NovelAutoScrollStateProvider._();
final class NovelAutoScrollStateProvider
extends $NotifierProvider<NovelAutoScrollState, bool> {
const NovelAutoScrollStateProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'novelAutoScrollStateProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$novelAutoScrollStateHash();
@$internal
@override
NovelAutoScrollState create() => NovelAutoScrollState();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(bool value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<bool>(value),
);
}
}
String _$novelAutoScrollStateHash() =>
r'80f717515844fa97396dffc6f45ee0b7b9e6f96d';
abstract class _$NovelAutoScrollState extends $Notifier<bool> {
bool build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<bool, bool>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<bool, bool>,
bool,
Object?,
Object?
>;
element.handleValue(ref, created);
}
}
@ProviderFor(NovelRemoveExtraParagraphSpacingState)
const novelRemoveExtraParagraphSpacingStateProvider =
NovelRemoveExtraParagraphSpacingStateProvider._();

View file

@ -27,6 +27,42 @@ class NovelReaderController extends _$NovelReaderController {
return isar.settings.getSync(227)!;
}
(bool, double) autoScrollValues() {
final autoScrollPagesList = getIsarSetting().autoScrollPages ?? [];
final autoScrollPages = autoScrollPagesList.where(
(element) => element.mangaId == getManga().id,
);
if (autoScrollPages.isNotEmpty) {
return (
autoScrollPages.first.autoScroll ?? false,
autoScrollPages.first.pageOffset ?? 10,
);
}
return (false, 10);
}
void setAutoScroll(bool value, double offset) {
List<AutoScrollPages>? autoScrollPagesList = [];
for (var autoScrollPages in getIsarSetting().autoScrollPages ?? []) {
if (autoScrollPages.mangaId != getManga().id) {
autoScrollPagesList.add(autoScrollPages);
}
}
autoScrollPagesList.add(
AutoScrollPages()
..mangaId = getManga().id
..pageOffset = offset
..autoScroll = value,
);
isar.writeTxnSync(
() => isar.settings.putSync(
getIsarSetting()
..autoScrollPages = autoScrollPagesList
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
void setMangaHistoryUpdate() {
if (incognitoMode) return;
isar.writeTxnSync(() {

View file

@ -59,7 +59,7 @@ final class NovelReaderControllerProvider
}
String _$novelReaderControllerHash() =>
r'47354aa64609d94a875d58569b5c95257b736b76';
r'6ed6441112a356af8530219a6017e640fda388f2';
final class NovelReaderControllerFamily extends $Family
with

View file

@ -136,6 +136,36 @@ class _NovelWebViewState extends ConsumerState<NovelWebView>
ref.read(fullScreenReaderStateProvider.notifier).set(!value!);
}
late final _autoScroll = ValueNotifier(
_readerController.autoScrollValues().$1,
);
late final _pageOffset = ValueNotifier(
_readerController.autoScrollValues().$2,
);
late final _autoScrollPage = ValueNotifier(_autoScroll.value);
void _autoPagescroll() async {
for (int i = 0; i < 1; i++) {
await Future.delayed(const Duration(milliseconds: 100));
if (!_autoScroll.value) {
return;
}
if (_scrollController.hasClients) {
final currentOffset = _scrollController.offset;
final maxScroll = _scrollController.position.maxScrollExtent;
if (!(currentOffset >= maxScroll)) {
final newOffset = currentOffset + _pageOffset.value;
_scrollController.animateTo(
min(newOffset, maxScroll),
duration: Duration(milliseconds: 100),
curve: Curves.linear,
);
}
}
}
_autoPagescroll();
}
@override
Widget build(BuildContext context) {
final backgroundColor = ref.watch(backgroundColorStateProvider);
@ -204,260 +234,282 @@ class _NovelWebViewState extends ConsumerState<NovelWebView>
child: SafeArea(
top: !fullScreenReader,
bottom: false,
child: Stack(
children: [
Column(
child: widget.result.when(
data: (data) {
return Stack(
children: [
Flexible(
child: widget.result.when(
data: (data) {
epubBook = data.$2;
Column(
children: [
Flexible(
child: Builder(
builder: (context) {
epubBook = data.$2;
final padding = ref.watch(
novelReaderPaddingStateProvider,
);
final lineHeight = ref.watch(
novelReaderLineHeightStateProvider,
);
final textAlign = ref.watch(
novelTextAlignStateProvider,
);
final removeExtraSpacing = ref.watch(
novelRemoveExtraParagraphSpacingStateProvider,
);
final customBackgroundColor = ref.watch(
novelReaderThemeStateProvider,
);
final customTextColor = ref.watch(
novelReaderTextColorStateProvider,
);
Color parseColor(String hex) {
final hexColor = hex.replaceAll('#', '');
return Color(int.parse('FF$hexColor', radix: 16));
}
TextAlign getTextAlign() {
switch (textAlign) {
case NovelTextAlign.left:
return TextAlign.left;
case NovelTextAlign.center:
return TextAlign.center;
case NovelTextAlign.right:
return TextAlign.right;
case NovelTextAlign.block:
return TextAlign.justify;
}
}
Future.delayed(const Duration(milliseconds: 10), () {
if (!scrolled && _scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent *
(double.tryParse(chapter.lastPageRead!) ??
0),
duration: Duration(seconds: 2),
curve: Curves.fastOutSlowIn,
final padding = ref.watch(
novelReaderPaddingStateProvider,
);
scrolled = true;
}
});
return Consumer(
builder: (context, ref, _) {
final fontSize = ref.read(
novelFontSizeStateProvider,
final lineHeight = ref.watch(
novelReaderLineHeightStateProvider,
);
return Scrollbar(
controller: _scrollController,
interactive: true,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
_isViewFunction();
},
child: CustomScrollView(
controller: _scrollController,
physics: const BouncingScrollPhysics(),
slivers: [
SliverToBoxAdapter(
child: Html(
data: data.$1,
style: {
"body": Style(
fontSize: FontSize(
fontSize.toDouble(),
),
color: parseColor(
customTextColor,
),
backgroundColor: parseColor(
customBackgroundColor,
),
margin: Margins.zero,
padding: HtmlPaddings.all(
padding.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"p": Style(
margin: removeExtraSpacing
? Margins.only(bottom: 4)
: Margins.only(bottom: 8),
fontSize: FontSize(
fontSize.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"div": Style(
fontSize: FontSize(
fontSize.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"span": Style(
fontSize: FontSize(
fontSize.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
),
"h1, h2, h3, h4, h5, h6": Style(
color: parseColor(
customTextColor,
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"a": Style(
color: Colors.blue,
textDecoration:
TextDecoration.underline,
),
"img": Style(
width: Width(100, Unit.percent),
height: Height.auto(),
),
},
extensions: [
TagExtension(
tagsToExtend: {"img"},
builder: (extensionContext) {
final element =
extensionContext.node
as dom.Element;
final customWidget =
_buildCustomWidgets(
element,
);
if (customWidget != null) {
return customWidget;
}
return const SizedBox.shrink();
},
),
],
onLinkTap:
(url, attributes, element) {
if (url != null) {
context.push(
"/mangawebview",
extra: {
'url': url,
'title': url,
},
);
}
},
),
),
],
),
),
final textAlign = ref.watch(
novelTextAlignStateProvider,
);
final removeExtraSpacing = ref.watch(
novelRemoveExtraParagraphSpacingStateProvider,
);
},
);
},
loading: () => scaffoldWith(
context,
Center(child: CircularProgressIndicator()),
),
error: (err, stack) => scaffoldWith(
context,
Center(child: Text(err.toString())),
),
),
),
if (ref.watch(novelShowScrollPercentageStateProvider))
StreamBuilder(
stream: _rebuildDetail.stream,
builder: (context, asyncSnapshot) {
return Consumer(
builder: (context, ref, child) {
final customBackgroundColor = ref.watch(
novelReaderThemeStateProvider,
);
final customTextColor = ref.watch(
novelReaderTextColorStateProvider,
);
final scrollPercentage = maxOffset > 0
? ((offset / maxOffset) * 100)
.clamp(0, 100)
.toInt()
: 0;
return Row(
children: [
Expanded(
child: Container(
color: Color(
int.parse(
'FF${customBackgroundColor.replaceAll('#', '')}',
radix: 16,
),
Color parseColor(String hex) {
final hexColor = hex.replaceAll('#', '');
return Color(
int.parse('FF$hexColor', radix: 16),
);
}
TextAlign getTextAlign() {
switch (textAlign) {
case NovelTextAlign.left:
return TextAlign.left;
case NovelTextAlign.center:
return TextAlign.center;
case NovelTextAlign.right:
return TextAlign.right;
case NovelTextAlign.block:
return TextAlign.justify;
}
}
Future.delayed(
const Duration(milliseconds: 10),
() {
if (!scrolled &&
_scrollController.hasClients) {
_scrollController
.animateTo(
_scrollController
.position
.maxScrollExtent *
(double.tryParse(
chapter.lastPageRead!,
) ??
0),
duration: Duration(seconds: 2),
curve: Curves.fastOutSlowIn,
)
.then((value) {
_autoPagescroll();
scrolled = true;
});
}
},
);
return Consumer(
builder: (context, ref, _) {
final fontSize = ref.read(
novelFontSizeStateProvider,
);
return Scrollbar(
controller: _scrollController,
interactive: true,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
_isViewFunction();
},
child: CustomScrollView(
controller: _scrollController,
physics: const BouncingScrollPhysics(),
slivers: [
SliverToBoxAdapter(
child: Html(
data: data.$1,
style: {
"body": Style(
fontSize: FontSize(
fontSize.toDouble(),
),
color: parseColor(
customTextColor,
),
backgroundColor: parseColor(
customBackgroundColor,
),
margin: Margins.zero,
padding: HtmlPaddings.all(
padding.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"p": Style(
margin: removeExtraSpacing
? Margins.only(bottom: 4)
: Margins.only(bottom: 8),
fontSize: FontSize(
fontSize.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"div": Style(
fontSize: FontSize(
fontSize.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"span": Style(
fontSize: FontSize(
fontSize.toDouble(),
),
lineHeight: LineHeight(
lineHeight,
),
),
"h1, h2, h3, h4, h5, h6": Style(
color: parseColor(
customTextColor,
),
lineHeight: LineHeight(
lineHeight,
),
textAlign: getTextAlign(),
),
"a": Style(
color: Colors.blue,
textDecoration:
TextDecoration.underline,
),
"img": Style(
width: Width(
100,
Unit.percent,
),
height: Height.auto(),
),
},
extensions: [
TagExtension(
tagsToExtend: {"img"},
builder: (extensionContext) {
final element =
extensionContext.node
as dom.Element;
final customWidget =
_buildCustomWidgets(
element,
);
if (customWidget != null) {
return customWidget;
}
return const SizedBox.shrink();
},
),
],
onLinkTap:
(url, attributes, element) {
if (url != null) {
context.push(
"/mangawebview",
extra: {
'url': url,
'title': url,
},
);
}
},
),
),
],
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
'$scrollPercentage %',
style: TextStyle(
color: Color(
int.parse(
'FF${customTextColor.replaceAll('#', '')}',
radix: 16,
),
);
},
);
},
),
),
if (ref.watch(novelShowScrollPercentageStateProvider))
StreamBuilder(
stream: _rebuildDetail.stream,
builder: (context, asyncSnapshot) {
return Consumer(
builder: (context, ref, child) {
final customBackgroundColor = ref.watch(
novelReaderThemeStateProvider,
);
final customTextColor = ref.watch(
novelReaderTextColorStateProvider,
);
final scrollPercentage = maxOffset > 0
? ((offset / maxOffset) * 100)
.clamp(0, 100)
.toInt()
: 0;
return Row(
children: [
Expanded(
child: Container(
color: Color(
int.parse(
'FF${customBackgroundColor.replaceAll('#', '')}',
radix: 16,
),
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(
4.0,
),
child: Text(
'$scrollPercentage %',
style: TextStyle(
color: Color(
int.parse(
'FF${customTextColor.replaceAll('#', '')}',
radix: 16,
),
),
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
],
],
);
},
);
},
);
},
),
),
],
),
_appBar(),
_bottomBar(backgroundColor),
_autoScrollPlayPauseBtn(),
],
),
_appBar(),
_bottomBar(backgroundColor),
],
);
},
loading: () => scaffoldWith(
context,
Center(child: CircularProgressIndicator()),
),
error: (err, stack) =>
scaffoldWith(context, Center(child: Text(err.toString()))),
),
),
),
@ -465,6 +517,32 @@ class _NovelWebViewState extends ConsumerState<NovelWebView>
);
}
Widget _autoScrollPlayPauseBtn() {
return Positioned(
bottom: 0,
right: 0,
child: !_isView
? ValueListenableBuilder(
valueListenable: _autoScrollPage,
builder: (context, valueT, child) => valueT
? ValueListenableBuilder(
valueListenable: _autoScroll,
builder: (context, value, child) => IconButton(
onPressed: () {
_autoPagescroll();
_autoScroll.value = !value;
},
icon: Icon(
value ? Icons.pause_circle : Icons.play_circle,
),
),
)
: const SizedBox.shrink(),
)
: const SizedBox.shrink(),
);
}
Widget scaffoldWith(
BuildContext context,
Widget body, {
@ -892,19 +970,29 @@ class _NovelWebViewState extends ConsumerState<NovelWebView>
),
IconButton(
onPressed: () {
customDraggableTabBar(
onPressed: () async {
_autoScroll.value = false;
await customDraggableTabBar(
tabs: [
Tab(text: context.l10n.reader),
Tab(text: context.l10n.general),
],
children: [
ReaderSettingsTab(),
GeneralSettingsTab(),
GeneralSettingsTab(
autoScrollPage: _autoScrollPage,
autoScroll: _autoScroll,
readerController: _readerController,
pageOffset: _pageOffset,
),
],
context: context,
vsync: this,
);
if (_autoScrollPage.value) {
_autoPagescroll();
_autoScroll.value = true;
}
},
icon: const Icon(Icons.settings),
),

View file

@ -1,7 +1,10 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
import 'package:mangayomi/modules/novel/novel_reader_controller_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class ReaderSettingsTab extends ConsumerWidget {
const ReaderSettingsTab({super.key});
@ -227,7 +230,17 @@ class ReaderSettingsTab extends ConsumerWidget {
}
class GeneralSettingsTab extends ConsumerWidget {
const GeneralSettingsTab({super.key});
final ValueNotifier<bool> autoScrollPage;
final ValueNotifier<bool> autoScroll;
final NovelReaderController readerController;
final ValueNotifier<double> pageOffset;
const GeneralSettingsTab({
required this.autoScrollPage,
required this.autoScroll,
required this.readerController,
required this.pageOffset,
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
@ -237,7 +250,6 @@ class GeneralSettingsTab extends ConsumerWidget {
children: [
_SwitchListTileSetting(
title: 'Show Scroll Percentage',
subtitle: 'Display reading progress percentage',
value: ref.watch(novelShowScrollPercentageStateProvider),
onChanged: (value) {
ref
@ -245,18 +257,45 @@ class GeneralSettingsTab extends ConsumerWidget {
.set(value);
},
),
// _SwitchListTileSetting(
// title: 'Auto Scroll',
// subtitle: 'Automatically scroll through pages',
// value: ref.watch(novelAutoScrollStateProvider),
// onChanged: (value) {
// ref.read(novelAutoScrollStateProvider.notifier).set(value);
// },
// ),
ValueListenableBuilder(
valueListenable: autoScrollPage,
builder: (context, valueT, child) {
return Column(
children: [
_SwitchListTileSetting(
secondary: Icon(
valueT ? Icons.timer : Icons.timer_outlined,
),
value: valueT,
title: context.l10n.auto_scroll,
onChanged: (val) {
readerController.setAutoScroll(val, pageOffset.value);
autoScrollPage.value = val;
autoScroll.value = val;
},
),
if (valueT)
ValueListenableBuilder(
valueListenable: pageOffset,
builder: (context, value, child) => Slider(
min: 2.0,
max: 30.0,
divisions: max(28, 3),
value: value,
onChanged: (val) {
pageOffset.value = val;
},
onChangeEnd: (val) {
readerController.setAutoScroll(valueT, val);
},
),
),
],
);
},
),
_SwitchListTileSetting(
title: 'Remove Extra Paragraph Spacing',
subtitle: 'Reduce spacing between paragraphs',
value: ref.watch(novelRemoveExtraParagraphSpacingStateProvider),
onChanged: (value) {
ref
@ -311,22 +350,31 @@ class _SettingSection extends StatelessWidget {
class _SwitchListTileSetting extends StatelessWidget {
final String title;
final String subtitle;
final bool value;
final Widget? secondary;
final ValueChanged<bool> onChanged;
const _SwitchListTileSetting({
required this.title,
required this.subtitle,
required this.value,
required this.onChanged,
this.secondary,
});
@override
Widget build(BuildContext context) {
return SwitchListTile(
title: Text(title),
subtitle: Text(subtitle, style: Theme.of(context).textTheme.bodySmall),
secondary: secondary,
title: Text(
title,
style: TextStyle(
color: Theme.of(
context,
).textTheme.bodyLarge!.color!.withValues(alpha: 0.9),
fontSize: 14,
),
),
value: value,
onChanged: onChanged,
);

View file

@ -66,7 +66,7 @@ final class GetHtmlContentProvider
}
}
String _$getHtmlContentHash() => r'a5763e11960bfe0dbd38ce2b2a3f4b51fefc976e';
String _$getHtmlContentHash() => r'f1f734a95f8dfcd7197712eee61609589d76de1f';
final class GetHtmlContentFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<(String, EpubBook?)>, Chapter> {