diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 355891c..3a3e1f8 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -276,5 +276,9 @@ "updateProgressAfterReading": "تحديث التقدم بعد القراءة", "no_sources_installed": "لم يتم تثبيت مصادر!", "show_extensions": "عرض الإضافات", - "default_skip_forward_skip_length": "طول التخطي الافتراضي للأمام" + "default_skip_forward_skip_length": "طول التخطي الافتراضي للأمام", + "aniskip_requires_info": "AniSkip يتطلب تتبع الأنمي باستخدام MAL أو Anilist للعمل.", + "enable_aniskip": "تمكين AniSkip", + "enable_auto_skip": "تمكين التخطي التلقائي", + "aniskip_button_timeout": "مهلة زر" } \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index f0ed43f..4261c22 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -276,5 +276,9 @@ "updateProgressAfterReading": "Fortschritt nach dem Lesen aktualisieren", "no_sources_installed": "Keine Quellen installiert!", "show_extensions": "Erweiterungen anzeigen", - "default_skip_forward_skip_length": "Standardmäßige Länge des Vorwärtsspringens" + "default_skip_forward_skip_length": "Standardmäßige Länge des Vorwärtsspringens", + "aniskip_requires_info": "AniSkip erfordert, dass der Anime mit MAL oder Anilist verfolgt wird, um zu funktionieren.", + "enable_aniskip": "AniSkip aktivieren", + "enable_auto_skip": "Automatisches Überspringen aktivieren", + "aniskip_button_timeout": "Timeout für Taste" } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 501ac58..21c12f4 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -276,5 +276,11 @@ "updateProgressAfterReading": "Update progress after reading", "no_sources_installed": "No sources installed!", "show_extensions": "Show extensions", - "default_skip_forward_skip_length": "Default skip forward skip length" + "default_skip_forward_skip_length": "Default skip forward skip length", + "aniskip_requires_info": "AniSkip requires the anime to be tracked with MAL or Anilist to work.", + "enable_aniskip": "Enable AniSkip", + "enable_auto_skip": "Enable auto skip", + "aniskip_button_timeout": "Button timeout", + "skip_opening": "Skip opening", + "skip_ending": "Skip ending" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 616d210..6cee664 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -276,5 +276,9 @@ "updateProgressAfterReading": "Actualizar el progreso después de leer", "no_sources_installed": "¡No hay fuentes instaladas!", "show_extensions": "Mostrar extensiones", - "default_skip_forward_skip_length": "Longitud de salto hacia adelante predeterminada" + "default_skip_forward_skip_length": "Longitud de salto hacia adelante predeterminada", + "aniskip_requires_info": "AniSkip requiere que el anime esté registrado en MAL o Anilist para funcionar.", + "enable_aniskip": "Habilitar AniSkip", + "enable_auto_skip": "Habilitar salto automático", + "aniskip_button_timeout": "Tiempo de espera del botón" } \ No newline at end of file diff --git a/lib/l10n/app_es_419.arb b/lib/l10n/app_es_419.arb index 1d10f8d..0fe733f 100644 --- a/lib/l10n/app_es_419.arb +++ b/lib/l10n/app_es_419.arb @@ -276,5 +276,9 @@ "updateProgressAfterReading": "Actualizar el progreso después de leer", "no_sources_installed": "¡No hay fuentes instaladas!", "show_extensions": "Mostrar extensiones", - "default_skip_forward_skip_length": "Longitud de salto hacia adelante predeterminada" + "default_skip_forward_skip_length": "Longitud de salto hacia adelante predeterminada", + "aniskip_requires_info": "AniSkip requiere que el anime esté registrado en MAL o Anilist para funcionar.", + "enable_aniskip": "Habilitar AniSkip", + "enable_auto_skip": "Habilitar salto automático", + "aniskip_button_timeout": "Tiempo de espera del botón" } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index f376cf7..a7c7aac 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -276,5 +276,11 @@ "updateProgressAfterReading": "Synchroniser la progression après lecture", "no_sources_installed": "Aucune source installée !", "show_extensions": "Afficher les extensions", - "default_skip_forward_skip_length": "Longueur de saut par défaut" + "default_skip_forward_skip_length": "Longueur de saut par défaut", + "aniskip_requires_info": "AniSkip nécessite que l'anime soit suivi sur MAL ou Anilist pour fonctionner.", + "enable_aniskip": "Activer AniSkip", + "enable_auto_skip": "Activer le saut automatique", + "aniskip_button_timeout": "Délai du bouton", + "skip_opening": "Passer l'opening", + "skip_ending": "Passer l'ending" } \ No newline at end of file diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index f3a0ebb..d6955c8 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -276,5 +276,9 @@ "updateProgressAfterReading": "Perbarui kemajuan setelah membaca", "no_sources_installed": "Tidak ada sumber yang terpasang!", "show_extensions": "Tampilkan ekstensi", - "default_skip_forward_skip_length": "Panjang lompatan maju default" + "default_skip_forward_skip_length": "Panjang lompatan maju default", + "aniskip_requires_info": "AniSkip memerlukan informasi anime dilacak dengan MAL atau Anilist untuk berfungsi.", + "enable_aniskip": "Aktifkan AniSkip", + "enable_auto_skip": "Aktifkan pengabaian otomatis", + "aniskip_button_timeout": "Timeout tombol" } \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 81c7c6d..1492c80 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -276,5 +276,9 @@ "updateProgressAfterReading": "Aggiorna il progresso dopo aver letto", "no_sources_installed": "Nessuna fonte installata!", "show_extensions": "Mostra estensioni", - "default_skip_forward_skip_length": "Lunghezza predefinita del salto in avanti" + "default_skip_forward_skip_length": "Lunghezza predefinita del salto in avanti", + "aniskip_requires_info": "AniSkip richiede che l'anime sia tracciato con MAL o Anilist per funzionare.", + "enable_aniskip": "Abilita AniSkip", + "enable_auto_skip": "Abilita l'auto-skip", + "aniskip_button_timeout": "Timeout del pulsante" } \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 65f52ab..a5015cf 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -276,5 +276,9 @@ "updateProgressAfterReading": "Atualizar progresso após a leitura", "no_sources_installed": "Nenhuma fonte instalada!", "show_extensions": "mostrar extensões", - "default_skip_forward_skip_length": "Comprimento padrão do salto para frente" + "default_skip_forward_skip_length": "Comprimento padrão do salto para frente", + "aniskip_requires_info": "AniSkip requer que o anime seja rastreado com o MAL ou Anilist para funcionar.", + "enable_aniskip": "Ativar AniSkip", + "enable_auto_skip": "Ativar auto skip", + "aniskip_button_timeout": "Tempo limite do botão" } \ No newline at end of file diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index 28ec075..a5db5ec 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -276,5 +276,9 @@ "updateProgressAfterReading": "Atualize o progresso após a leitura", "no_sources_installed": "Nenhuma fonte instalada!", "show_extensions": "Mostrar extensões", - "default_skip_forward_skip_length": "Comprimento padrão do salto para frente" + "default_skip_forward_skip_length": "Comprimento padrão do salto para frente", + "aniskip_requires_info": "AniSkip requer que o anime seja rastreado com MAL ou Anilist para funcionar.", + "enable_aniskip": "Habilitar AniSkip", + "enable_auto_skip": "Habilitar auto skip", + "aniskip_button_timeout": "Timeout do botão" } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index f516b18..a8b7676 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -276,5 +276,9 @@ "updateProgressAfterReading": "Обновить прогресс после чтения", "no_sources_installed": "Источники не установлены!", "show_extensions": "Показать расширения", - "default_skip_forward_skip_length": "Длина пропуска вперед по умолчанию" + "default_skip_forward_skip_length": "Длина пропуска вперед по умолчанию", + "aniskip_requires_info": "AniSkip требует отслеживания аниме с использованием MAL или Anilist для работы.", + "enable_aniskip": "Включить AniSkip", + "enable_auto_skip": "Включить автоматическое пропускание", + "aniskip_button_timeout": "Тайм-аут кнопки" } \ No newline at end of file diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index fa1ee98..9f830c1 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -276,5 +276,9 @@ "updateProgressAfterReading": "Okuduktan Sonra İlerlemeyi Güncelle", "no_sources_installed": "Hiçbir kaynak yüklü değil!", "show_extensions": "uzantıları göster", - "default_skip_forward_skip_length": "Varsayılan ileri atlama atlama uzunluğu" + "default_skip_forward_skip_length": "Varsayılan ileri atlama atlama uzunluğu", + "aniskip_requires_info": "AniSkip, çalışması için animenin MAL veya Anilist ile takip edilmesini gerektirir.", + "enable_aniskip": "AniSkip'i Etkinleştir", + "enable_auto_skip": "Otomatik Atla'yı Etkinleştir", + "aniskip_button_timeout": "Düğme Zaman Aşımı" } \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 97b31dd..edc0b4f 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -276,5 +276,11 @@ "updateProgressAfterReading": "阅读后更新进度", "no_sources_installed": "未安装任何来源!", "show_extensions": "显示扩展", - "default_skip_forward_skip_length": "默认向前跳过长度" + "default_skip_forward_skip_length": "默认向前跳过长度", + "aniskip_requires_info": "AniSkip需要跟踪使用MAL或Anilist进行的动漫才能工作。", + "enable_aniskip": "启用AniSkip", + "enable_auto_skip": "启用自动跳过", + "aniskip_button_timeout": "按钮超时", + "skip_opening": "跳过开头", + "skip_ending": "跳过结尾" } \ No newline at end of file diff --git a/lib/models/settings.dart b/lib/models/settings.dart index ee4c2c1..ddeb858 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -153,6 +153,12 @@ class Settings { bool? updateProgressAfterReading; + bool? enableAniSkip; + + bool? enableAutoSkip; + + int? aniSkipTimeoutLength; + Settings( {this.id = 227, this.displayType = DisplayType.compactGrid, @@ -219,7 +225,10 @@ class Settings { this.defaultSkipIntroLength = 85, this.defaultDoubleTapToSkipLength = 10, this.defaultPlayBackSpeed = 1.0, - this.updateProgressAfterReading = true}); + this.updateProgressAfterReading = true, + this.enableAniSkip, + this.enableAutoSkip, + this.aniSkipTimeoutLength}); Settings.fromJson(Map json) { animatePageTransitions = json['animatePageTransitions']; @@ -342,6 +351,9 @@ class Settings { defaultDoubleTapToSkipLength = json['defaultDoubleTapToSkipLength']; defaultPlayBackSpeed = json['defaultPlayBackSpeed']; updateProgressAfterReading = json['updateProgressAfterReading']; + enableAniSkip = json['enableAniSkip']; + enableAutoSkip = json['enableAutoSkip']; + aniSkipTimeoutLength = json['aniSkipTimeoutLength']; } Map toJson() => { @@ -432,7 +444,10 @@ class Settings { 'defaultSkipIntroLength': defaultSkipIntroLength, 'defaultDoubleTapToSkipLength': defaultDoubleTapToSkipLength, 'defaultPlayBackSpeed': defaultPlayBackSpeed, - 'updateProgressAfterReading': updateProgressAfterReading + 'updateProgressAfterReading': updateProgressAfterReading, + 'enableAniSkip': enableAniSkip, + 'enableAutoSkip': enableAutoSkip, + 'aniSkipTimeoutLength': aniSkipTimeoutLength }; } diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart index d7bea30..918f720 100644 --- a/lib/models/settings.g.dart +++ b/lib/models/settings.g.dart @@ -17,367 +17,382 @@ const SettingsSchema = CollectionSchema( name: r'Settings', id: -8656046621518759136, properties: { - r'animatePageTransitions': PropertySchema( + r'aniSkipTimeoutLength': PropertySchema( id: 0, + name: r'aniSkipTimeoutLength', + type: IsarType.long, + ), + r'animatePageTransitions': PropertySchema( + id: 1, name: r'animatePageTransitions', type: IsarType.bool, ), r'animeDisplayType': PropertySchema( - id: 1, + id: 2, name: r'animeDisplayType', type: IsarType.byte, enumMap: _SettingsanimeDisplayTypeEnumValueMap, ), r'animeLibraryDownloadedChapters': PropertySchema( - id: 2, + id: 3, name: r'animeLibraryDownloadedChapters', type: IsarType.bool, ), r'animeLibraryLocalSource': PropertySchema( - id: 3, + id: 4, name: r'animeLibraryLocalSource', type: IsarType.bool, ), r'animeLibraryShowCategoryTabs': PropertySchema( - id: 4, + id: 5, name: r'animeLibraryShowCategoryTabs', type: IsarType.bool, ), r'animeLibraryShowContinueReadingButton': PropertySchema( - id: 5, + id: 6, name: r'animeLibraryShowContinueReadingButton', type: IsarType.bool, ), r'animeLibraryShowLanguage': PropertySchema( - id: 6, + id: 7, name: r'animeLibraryShowLanguage', type: IsarType.bool, ), r'animeLibraryShowNumbersOfItems': PropertySchema( - id: 7, + id: 8, name: r'animeLibraryShowNumbersOfItems', type: IsarType.bool, ), r'autoBackupLocation': PropertySchema( - id: 8, + id: 9, name: r'autoBackupLocation', type: IsarType.string, ), r'autoExtensionsUpdates': PropertySchema( - id: 9, + id: 10, name: r'autoExtensionsUpdates', type: IsarType.bool, ), r'autoScrollPages': PropertySchema( - id: 10, + id: 11, name: r'autoScrollPages', type: IsarType.objectList, target: r'AutoScrollPages', ), r'backgroundColor': PropertySchema( - id: 11, + id: 12, name: r'backgroundColor', type: IsarType.byte, enumMap: _SettingsbackgroundColorEnumValueMap, ), r'backupFrequency': PropertySchema( - id: 12, + id: 13, name: r'backupFrequency', type: IsarType.long, ), r'backupFrequencyOptions': PropertySchema( - id: 13, + id: 14, name: r'backupFrequencyOptions', type: IsarType.longList, ), r'chapterFilterBookmarkedList': PropertySchema( - id: 14, + id: 15, name: r'chapterFilterBookmarkedList', type: IsarType.objectList, target: r'ChapterFilterBookmarked', ), r'chapterFilterDownloadedList': PropertySchema( - id: 15, + id: 16, name: r'chapterFilterDownloadedList', type: IsarType.objectList, target: r'ChapterFilterDownloaded', ), r'chapterFilterUnreadList': PropertySchema( - id: 16, + id: 17, name: r'chapterFilterUnreadList', type: IsarType.objectList, target: r'ChapterFilterUnread', ), r'chapterPageIndexList': PropertySchema( - id: 17, + id: 18, name: r'chapterPageIndexList', type: IsarType.objectList, target: r'ChapterPageIndex', ), r'chapterPageUrlsList': PropertySchema( - id: 18, + id: 19, name: r'chapterPageUrlsList', type: IsarType.objectList, target: r'ChapterPageurls', ), r'checkForExtensionUpdates': PropertySchema( - id: 19, + id: 20, name: r'checkForExtensionUpdates', type: IsarType.bool, ), r'cookiesList': PropertySchema( - id: 20, + id: 21, name: r'cookiesList', type: IsarType.objectList, target: r'Cookie', ), r'cropBorders': PropertySchema( - id: 21, + id: 22, name: r'cropBorders', type: IsarType.bool, ), r'dateFormat': PropertySchema( - id: 22, + id: 23, name: r'dateFormat', type: IsarType.string, ), r'defaultDoubleTapToSkipLength': PropertySchema( - id: 23, + id: 24, name: r'defaultDoubleTapToSkipLength', type: IsarType.long, ), r'defaultPlayBackSpeed': PropertySchema( - id: 24, + id: 25, name: r'defaultPlayBackSpeed', type: IsarType.double, ), r'defaultReaderMode': PropertySchema( - id: 25, + id: 26, name: r'defaultReaderMode', type: IsarType.byte, enumMap: _SettingsdefaultReaderModeEnumValueMap, ), r'defaultSkipIntroLength': PropertySchema( - id: 26, + id: 27, name: r'defaultSkipIntroLength', type: IsarType.long, ), r'displayType': PropertySchema( - id: 27, + id: 28, name: r'displayType', type: IsarType.byte, enumMap: _SettingsdisplayTypeEnumValueMap, ), r'doubleTapAnimationSpeed': PropertySchema( - id: 28, + id: 29, name: r'doubleTapAnimationSpeed', type: IsarType.long, ), r'downloadLocation': PropertySchema( - id: 29, + id: 30, name: r'downloadLocation', type: IsarType.string, ), r'downloadOnlyOnWifi': PropertySchema( - id: 30, + id: 31, name: r'downloadOnlyOnWifi', type: IsarType.bool, ), + r'enableAniSkip': PropertySchema( + id: 32, + name: r'enableAniSkip', + type: IsarType.bool, + ), + r'enableAutoSkip': PropertySchema( + id: 33, + name: r'enableAutoSkip', + type: IsarType.bool, + ), r'filterScanlatorList': PropertySchema( - id: 31, + id: 34, name: r'filterScanlatorList', type: IsarType.objectList, target: r'FilterScanlator', ), r'flexColorSchemeBlendLevel': PropertySchema( - id: 32, + id: 35, name: r'flexColorSchemeBlendLevel', type: IsarType.double, ), r'flexSchemeColorIndex': PropertySchema( - id: 33, + id: 36, name: r'flexSchemeColorIndex', type: IsarType.long, ), r'incognitoMode': PropertySchema( - id: 34, + id: 37, name: r'incognitoMode', type: IsarType.bool, ), r'libraryDownloadedChapters': PropertySchema( - id: 35, + id: 38, name: r'libraryDownloadedChapters', type: IsarType.bool, ), r'libraryFilterAnimeBookMarkedType': PropertySchema( - id: 36, + id: 39, name: r'libraryFilterAnimeBookMarkedType', type: IsarType.long, ), r'libraryFilterAnimeDownloadType': PropertySchema( - id: 37, + id: 40, name: r'libraryFilterAnimeDownloadType', type: IsarType.long, ), r'libraryFilterAnimeStartedType': PropertySchema( - id: 38, + id: 41, name: r'libraryFilterAnimeStartedType', type: IsarType.long, ), r'libraryFilterAnimeUnreadType': PropertySchema( - id: 39, + id: 42, name: r'libraryFilterAnimeUnreadType', type: IsarType.long, ), r'libraryFilterMangasBookMarkedType': PropertySchema( - id: 40, + id: 43, name: r'libraryFilterMangasBookMarkedType', type: IsarType.long, ), r'libraryFilterMangasDownloadType': PropertySchema( - id: 41, + id: 44, name: r'libraryFilterMangasDownloadType', type: IsarType.long, ), r'libraryFilterMangasStartedType': PropertySchema( - id: 42, + id: 45, name: r'libraryFilterMangasStartedType', type: IsarType.long, ), r'libraryFilterMangasUnreadType': PropertySchema( - id: 43, + id: 46, name: r'libraryFilterMangasUnreadType', type: IsarType.long, ), r'libraryLocalSource': PropertySchema( - id: 44, + id: 47, name: r'libraryLocalSource', type: IsarType.bool, ), r'libraryShowCategoryTabs': PropertySchema( - id: 45, + id: 48, name: r'libraryShowCategoryTabs', type: IsarType.bool, ), r'libraryShowContinueReadingButton': PropertySchema( - id: 46, + id: 49, name: r'libraryShowContinueReadingButton', type: IsarType.bool, ), r'libraryShowLanguage': PropertySchema( - id: 47, + id: 50, name: r'libraryShowLanguage', type: IsarType.bool, ), r'libraryShowNumbersOfItems': PropertySchema( - id: 48, + id: 51, name: r'libraryShowNumbersOfItems', type: IsarType.bool, ), r'locale': PropertySchema( - id: 49, + id: 52, name: r'locale', type: IsarType.object, target: r'L10nLocale', ), r'markEpisodeAsSeenType': PropertySchema( - id: 50, + id: 53, name: r'markEpisodeAsSeenType', type: IsarType.long, ), r'onlyIncludePinnedSources': PropertySchema( - id: 51, + id: 54, name: r'onlyIncludePinnedSources', type: IsarType.bool, ), r'pagePreloadAmount': PropertySchema( - id: 52, + id: 55, name: r'pagePreloadAmount', type: IsarType.long, ), r'personalPageModeList': PropertySchema( - id: 53, + id: 56, name: r'personalPageModeList', type: IsarType.objectList, target: r'PersonalPageMode', ), r'personalReaderModeList': PropertySchema( - id: 54, + id: 57, name: r'personalReaderModeList', type: IsarType.objectList, target: r'PersonalReaderMode', ), r'pureBlackDarkMode': PropertySchema( - id: 55, + id: 58, name: r'pureBlackDarkMode', type: IsarType.bool, ), r'relativeTimesTamps': PropertySchema( - id: 56, + id: 59, name: r'relativeTimesTamps', type: IsarType.long, ), r'saveAsCBZArchive': PropertySchema( - id: 57, + id: 60, name: r'saveAsCBZArchive', type: IsarType.bool, ), r'scaleType': PropertySchema( - id: 58, + id: 61, name: r'scaleType', type: IsarType.byte, enumMap: _SettingsscaleTypeEnumValueMap, ), r'showNSFW': PropertySchema( - id: 59, + id: 62, name: r'showNSFW', type: IsarType.bool, ), r'showPagesNumber': PropertySchema( - id: 60, + id: 63, name: r'showPagesNumber', type: IsarType.bool, ), r'sortChapterList': PropertySchema( - id: 61, + id: 64, name: r'sortChapterList', type: IsarType.objectList, target: r'SortChapter', ), r'sortLibraryAnime': PropertySchema( - id: 62, + id: 65, name: r'sortLibraryAnime', type: IsarType.object, target: r'SortLibraryManga', ), r'sortLibraryManga': PropertySchema( - id: 63, + id: 66, name: r'sortLibraryManga', type: IsarType.object, target: r'SortLibraryManga', ), r'startDatebackup': PropertySchema( - id: 64, + id: 67, name: r'startDatebackup', type: IsarType.long, ), r'themeIsDark': PropertySchema( - id: 65, + id: 68, name: r'themeIsDark', type: IsarType.bool, ), r'updateProgressAfterReading': PropertySchema( - id: 66, + id: 69, name: r'updateProgressAfterReading', type: IsarType.bool, ), r'usePageTapZones': PropertySchema( - id: 67, + id: 70, name: r'usePageTapZones', type: IsarType.bool, ), r'userAgent': PropertySchema( - id: 68, + id: 71, name: r'userAgent', type: IsarType.string, ) @@ -639,145 +654,148 @@ void _settingsSerialize( List offsets, Map> allOffsets, ) { - writer.writeBool(offsets[0], object.animatePageTransitions); - writer.writeByte(offsets[1], object.animeDisplayType.index); - writer.writeBool(offsets[2], object.animeLibraryDownloadedChapters); - writer.writeBool(offsets[3], object.animeLibraryLocalSource); - writer.writeBool(offsets[4], object.animeLibraryShowCategoryTabs); - writer.writeBool(offsets[5], object.animeLibraryShowContinueReadingButton); - writer.writeBool(offsets[6], object.animeLibraryShowLanguage); - writer.writeBool(offsets[7], object.animeLibraryShowNumbersOfItems); - writer.writeString(offsets[8], object.autoBackupLocation); - writer.writeBool(offsets[9], object.autoExtensionsUpdates); + writer.writeLong(offsets[0], object.aniSkipTimeoutLength); + writer.writeBool(offsets[1], object.animatePageTransitions); + writer.writeByte(offsets[2], object.animeDisplayType.index); + writer.writeBool(offsets[3], object.animeLibraryDownloadedChapters); + writer.writeBool(offsets[4], object.animeLibraryLocalSource); + writer.writeBool(offsets[5], object.animeLibraryShowCategoryTabs); + writer.writeBool(offsets[6], object.animeLibraryShowContinueReadingButton); + writer.writeBool(offsets[7], object.animeLibraryShowLanguage); + writer.writeBool(offsets[8], object.animeLibraryShowNumbersOfItems); + writer.writeString(offsets[9], object.autoBackupLocation); + writer.writeBool(offsets[10], object.autoExtensionsUpdates); writer.writeObjectList( - offsets[10], + offsets[11], allOffsets, AutoScrollPagesSchema.serialize, object.autoScrollPages, ); - writer.writeByte(offsets[11], object.backgroundColor.index); - writer.writeLong(offsets[12], object.backupFrequency); - writer.writeLongList(offsets[13], object.backupFrequencyOptions); + writer.writeByte(offsets[12], object.backgroundColor.index); + writer.writeLong(offsets[13], object.backupFrequency); + writer.writeLongList(offsets[14], object.backupFrequencyOptions); writer.writeObjectList( - offsets[14], + offsets[15], allOffsets, ChapterFilterBookmarkedSchema.serialize, object.chapterFilterBookmarkedList, ); writer.writeObjectList( - offsets[15], + offsets[16], allOffsets, ChapterFilterDownloadedSchema.serialize, object.chapterFilterDownloadedList, ); writer.writeObjectList( - offsets[16], + offsets[17], allOffsets, ChapterFilterUnreadSchema.serialize, object.chapterFilterUnreadList, ); writer.writeObjectList( - offsets[17], + offsets[18], allOffsets, ChapterPageIndexSchema.serialize, object.chapterPageIndexList, ); writer.writeObjectList( - offsets[18], + offsets[19], allOffsets, ChapterPageurlsSchema.serialize, object.chapterPageUrlsList, ); - writer.writeBool(offsets[19], object.checkForExtensionUpdates); + writer.writeBool(offsets[20], object.checkForExtensionUpdates); writer.writeObjectList( - offsets[20], + offsets[21], allOffsets, CookieSchema.serialize, object.cookiesList, ); - writer.writeBool(offsets[21], object.cropBorders); - writer.writeString(offsets[22], object.dateFormat); - writer.writeLong(offsets[23], object.defaultDoubleTapToSkipLength); - writer.writeDouble(offsets[24], object.defaultPlayBackSpeed); - writer.writeByte(offsets[25], object.defaultReaderMode.index); - writer.writeLong(offsets[26], object.defaultSkipIntroLength); - writer.writeByte(offsets[27], object.displayType.index); - writer.writeLong(offsets[28], object.doubleTapAnimationSpeed); - writer.writeString(offsets[29], object.downloadLocation); - writer.writeBool(offsets[30], object.downloadOnlyOnWifi); + writer.writeBool(offsets[22], object.cropBorders); + writer.writeString(offsets[23], object.dateFormat); + writer.writeLong(offsets[24], object.defaultDoubleTapToSkipLength); + writer.writeDouble(offsets[25], object.defaultPlayBackSpeed); + writer.writeByte(offsets[26], object.defaultReaderMode.index); + writer.writeLong(offsets[27], object.defaultSkipIntroLength); + writer.writeByte(offsets[28], object.displayType.index); + writer.writeLong(offsets[29], object.doubleTapAnimationSpeed); + writer.writeString(offsets[30], object.downloadLocation); + writer.writeBool(offsets[31], object.downloadOnlyOnWifi); + writer.writeBool(offsets[32], object.enableAniSkip); + writer.writeBool(offsets[33], object.enableAutoSkip); writer.writeObjectList( - offsets[31], + offsets[34], allOffsets, FilterScanlatorSchema.serialize, object.filterScanlatorList, ); - writer.writeDouble(offsets[32], object.flexColorSchemeBlendLevel); - writer.writeLong(offsets[33], object.flexSchemeColorIndex); - writer.writeBool(offsets[34], object.incognitoMode); - writer.writeBool(offsets[35], object.libraryDownloadedChapters); - writer.writeLong(offsets[36], object.libraryFilterAnimeBookMarkedType); - writer.writeLong(offsets[37], object.libraryFilterAnimeDownloadType); - writer.writeLong(offsets[38], object.libraryFilterAnimeStartedType); - writer.writeLong(offsets[39], object.libraryFilterAnimeUnreadType); - writer.writeLong(offsets[40], object.libraryFilterMangasBookMarkedType); - writer.writeLong(offsets[41], object.libraryFilterMangasDownloadType); - writer.writeLong(offsets[42], object.libraryFilterMangasStartedType); - writer.writeLong(offsets[43], object.libraryFilterMangasUnreadType); - writer.writeBool(offsets[44], object.libraryLocalSource); - writer.writeBool(offsets[45], object.libraryShowCategoryTabs); - writer.writeBool(offsets[46], object.libraryShowContinueReadingButton); - writer.writeBool(offsets[47], object.libraryShowLanguage); - writer.writeBool(offsets[48], object.libraryShowNumbersOfItems); + writer.writeDouble(offsets[35], object.flexColorSchemeBlendLevel); + writer.writeLong(offsets[36], object.flexSchemeColorIndex); + writer.writeBool(offsets[37], object.incognitoMode); + writer.writeBool(offsets[38], object.libraryDownloadedChapters); + writer.writeLong(offsets[39], object.libraryFilterAnimeBookMarkedType); + writer.writeLong(offsets[40], object.libraryFilterAnimeDownloadType); + writer.writeLong(offsets[41], object.libraryFilterAnimeStartedType); + writer.writeLong(offsets[42], object.libraryFilterAnimeUnreadType); + writer.writeLong(offsets[43], object.libraryFilterMangasBookMarkedType); + writer.writeLong(offsets[44], object.libraryFilterMangasDownloadType); + writer.writeLong(offsets[45], object.libraryFilterMangasStartedType); + writer.writeLong(offsets[46], object.libraryFilterMangasUnreadType); + writer.writeBool(offsets[47], object.libraryLocalSource); + writer.writeBool(offsets[48], object.libraryShowCategoryTabs); + writer.writeBool(offsets[49], object.libraryShowContinueReadingButton); + writer.writeBool(offsets[50], object.libraryShowLanguage); + writer.writeBool(offsets[51], object.libraryShowNumbersOfItems); writer.writeObject( - offsets[49], + offsets[52], allOffsets, L10nLocaleSchema.serialize, object.locale, ); - writer.writeLong(offsets[50], object.markEpisodeAsSeenType); - writer.writeBool(offsets[51], object.onlyIncludePinnedSources); - writer.writeLong(offsets[52], object.pagePreloadAmount); + writer.writeLong(offsets[53], object.markEpisodeAsSeenType); + writer.writeBool(offsets[54], object.onlyIncludePinnedSources); + writer.writeLong(offsets[55], object.pagePreloadAmount); writer.writeObjectList( - offsets[53], + offsets[56], allOffsets, PersonalPageModeSchema.serialize, object.personalPageModeList, ); writer.writeObjectList( - offsets[54], + offsets[57], allOffsets, PersonalReaderModeSchema.serialize, object.personalReaderModeList, ); - writer.writeBool(offsets[55], object.pureBlackDarkMode); - writer.writeLong(offsets[56], object.relativeTimesTamps); - writer.writeBool(offsets[57], object.saveAsCBZArchive); - writer.writeByte(offsets[58], object.scaleType.index); - writer.writeBool(offsets[59], object.showNSFW); - writer.writeBool(offsets[60], object.showPagesNumber); + writer.writeBool(offsets[58], object.pureBlackDarkMode); + writer.writeLong(offsets[59], object.relativeTimesTamps); + writer.writeBool(offsets[60], object.saveAsCBZArchive); + writer.writeByte(offsets[61], object.scaleType.index); + writer.writeBool(offsets[62], object.showNSFW); + writer.writeBool(offsets[63], object.showPagesNumber); writer.writeObjectList( - offsets[61], + offsets[64], allOffsets, SortChapterSchema.serialize, object.sortChapterList, ); writer.writeObject( - offsets[62], + offsets[65], allOffsets, SortLibraryMangaSchema.serialize, object.sortLibraryAnime, ); writer.writeObject( - offsets[63], + offsets[66], allOffsets, SortLibraryMangaSchema.serialize, object.sortLibraryManga, ); - writer.writeLong(offsets[64], object.startDatebackup); - writer.writeBool(offsets[65], object.themeIsDark); - writer.writeBool(offsets[66], object.updateProgressAfterReading); - writer.writeBool(offsets[67], object.usePageTapZones); - writer.writeString(offsets[68], object.userAgent); + writer.writeLong(offsets[67], object.startDatebackup); + writer.writeBool(offsets[68], object.themeIsDark); + writer.writeBool(offsets[69], object.updateProgressAfterReading); + writer.writeBool(offsets[70], object.usePageTapZones); + writer.writeString(offsets[71], object.userAgent); } Settings _settingsDeserialize( @@ -787,152 +805,155 @@ Settings _settingsDeserialize( Map> allOffsets, ) { final object = Settings( - animatePageTransitions: reader.readBoolOrNull(offsets[0]), + aniSkipTimeoutLength: reader.readLongOrNull(offsets[0]), + animatePageTransitions: reader.readBoolOrNull(offsets[1]), animeDisplayType: _SettingsanimeDisplayTypeValueEnumMap[ - reader.readByteOrNull(offsets[1])] ?? + reader.readByteOrNull(offsets[2])] ?? DisplayType.compactGrid, - animeLibraryDownloadedChapters: reader.readBoolOrNull(offsets[2]), - animeLibraryLocalSource: reader.readBoolOrNull(offsets[3]), - animeLibraryShowCategoryTabs: reader.readBoolOrNull(offsets[4]), - animeLibraryShowContinueReadingButton: reader.readBoolOrNull(offsets[5]), - animeLibraryShowLanguage: reader.readBoolOrNull(offsets[6]), - animeLibraryShowNumbersOfItems: reader.readBoolOrNull(offsets[7]), - autoBackupLocation: reader.readStringOrNull(offsets[8]), - autoExtensionsUpdates: reader.readBoolOrNull(offsets[9]), + animeLibraryDownloadedChapters: reader.readBoolOrNull(offsets[3]), + animeLibraryLocalSource: reader.readBoolOrNull(offsets[4]), + animeLibraryShowCategoryTabs: reader.readBoolOrNull(offsets[5]), + animeLibraryShowContinueReadingButton: reader.readBoolOrNull(offsets[6]), + animeLibraryShowLanguage: reader.readBoolOrNull(offsets[7]), + animeLibraryShowNumbersOfItems: reader.readBoolOrNull(offsets[8]), + autoBackupLocation: reader.readStringOrNull(offsets[9]), + autoExtensionsUpdates: reader.readBoolOrNull(offsets[10]), autoScrollPages: reader.readObjectList( - offsets[10], + offsets[11], AutoScrollPagesSchema.deserialize, allOffsets, AutoScrollPages(), ), backgroundColor: _SettingsbackgroundColorValueEnumMap[ - reader.readByteOrNull(offsets[11])] ?? + reader.readByteOrNull(offsets[12])] ?? BackgroundColor.black, - backupFrequency: reader.readLongOrNull(offsets[12]), - backupFrequencyOptions: reader.readLongList(offsets[13]), + backupFrequency: reader.readLongOrNull(offsets[13]), + backupFrequencyOptions: reader.readLongList(offsets[14]), chapterFilterDownloadedList: reader.readObjectList( - offsets[15], + offsets[16], ChapterFilterDownloadedSchema.deserialize, allOffsets, ChapterFilterDownloaded(), ), chapterPageIndexList: reader.readObjectList( - offsets[17], + offsets[18], ChapterPageIndexSchema.deserialize, allOffsets, ChapterPageIndex(), ), chapterPageUrlsList: reader.readObjectList( - offsets[18], + offsets[19], ChapterPageurlsSchema.deserialize, allOffsets, ChapterPageurls(), ), - checkForExtensionUpdates: reader.readBoolOrNull(offsets[19]), + checkForExtensionUpdates: reader.readBoolOrNull(offsets[20]), cookiesList: reader.readObjectList( - offsets[20], + offsets[21], CookieSchema.deserialize, allOffsets, Cookie(), ), - cropBorders: reader.readBoolOrNull(offsets[21]), - dateFormat: reader.readStringOrNull(offsets[22]), - defaultDoubleTapToSkipLength: reader.readLongOrNull(offsets[23]), - defaultPlayBackSpeed: reader.readDoubleOrNull(offsets[24]), + cropBorders: reader.readBoolOrNull(offsets[22]), + dateFormat: reader.readStringOrNull(offsets[23]), + defaultDoubleTapToSkipLength: reader.readLongOrNull(offsets[24]), + defaultPlayBackSpeed: reader.readDoubleOrNull(offsets[25]), defaultReaderMode: _SettingsdefaultReaderModeValueEnumMap[ - reader.readByteOrNull(offsets[25])] ?? + reader.readByteOrNull(offsets[26])] ?? ReaderMode.vertical, - defaultSkipIntroLength: reader.readLongOrNull(offsets[26]), + defaultSkipIntroLength: reader.readLongOrNull(offsets[27]), displayType: - _SettingsdisplayTypeValueEnumMap[reader.readByteOrNull(offsets[27])] ?? + _SettingsdisplayTypeValueEnumMap[reader.readByteOrNull(offsets[28])] ?? DisplayType.compactGrid, - doubleTapAnimationSpeed: reader.readLongOrNull(offsets[28]), - downloadLocation: reader.readStringOrNull(offsets[29]), - downloadOnlyOnWifi: reader.readBoolOrNull(offsets[30]), - flexColorSchemeBlendLevel: reader.readDoubleOrNull(offsets[32]), - flexSchemeColorIndex: reader.readLongOrNull(offsets[33]), + doubleTapAnimationSpeed: reader.readLongOrNull(offsets[29]), + downloadLocation: reader.readStringOrNull(offsets[30]), + downloadOnlyOnWifi: reader.readBoolOrNull(offsets[31]), + enableAniSkip: reader.readBoolOrNull(offsets[32]), + enableAutoSkip: reader.readBoolOrNull(offsets[33]), + flexColorSchemeBlendLevel: reader.readDoubleOrNull(offsets[35]), + flexSchemeColorIndex: reader.readLongOrNull(offsets[36]), id: id, - incognitoMode: reader.readBoolOrNull(offsets[34]), - libraryDownloadedChapters: reader.readBoolOrNull(offsets[35]), - libraryFilterAnimeBookMarkedType: reader.readLongOrNull(offsets[36]), - libraryFilterAnimeDownloadType: reader.readLongOrNull(offsets[37]), - libraryFilterAnimeStartedType: reader.readLongOrNull(offsets[38]), - libraryFilterAnimeUnreadType: reader.readLongOrNull(offsets[39]), - libraryFilterMangasBookMarkedType: reader.readLongOrNull(offsets[40]), - libraryFilterMangasDownloadType: reader.readLongOrNull(offsets[41]), - libraryFilterMangasStartedType: reader.readLongOrNull(offsets[42]), - libraryFilterMangasUnreadType: reader.readLongOrNull(offsets[43]), - libraryLocalSource: reader.readBoolOrNull(offsets[44]), - libraryShowCategoryTabs: reader.readBoolOrNull(offsets[45]), - libraryShowContinueReadingButton: reader.readBoolOrNull(offsets[46]), - libraryShowLanguage: reader.readBoolOrNull(offsets[47]), - libraryShowNumbersOfItems: reader.readBoolOrNull(offsets[48]), - markEpisodeAsSeenType: reader.readLongOrNull(offsets[50]), - onlyIncludePinnedSources: reader.readBoolOrNull(offsets[51]), - pagePreloadAmount: reader.readLongOrNull(offsets[52]), + incognitoMode: reader.readBoolOrNull(offsets[37]), + libraryDownloadedChapters: reader.readBoolOrNull(offsets[38]), + libraryFilterAnimeBookMarkedType: reader.readLongOrNull(offsets[39]), + libraryFilterAnimeDownloadType: reader.readLongOrNull(offsets[40]), + libraryFilterAnimeStartedType: reader.readLongOrNull(offsets[41]), + libraryFilterAnimeUnreadType: reader.readLongOrNull(offsets[42]), + libraryFilterMangasBookMarkedType: reader.readLongOrNull(offsets[43]), + libraryFilterMangasDownloadType: reader.readLongOrNull(offsets[44]), + libraryFilterMangasStartedType: reader.readLongOrNull(offsets[45]), + libraryFilterMangasUnreadType: reader.readLongOrNull(offsets[46]), + libraryLocalSource: reader.readBoolOrNull(offsets[47]), + libraryShowCategoryTabs: reader.readBoolOrNull(offsets[48]), + libraryShowContinueReadingButton: reader.readBoolOrNull(offsets[49]), + libraryShowLanguage: reader.readBoolOrNull(offsets[50]), + libraryShowNumbersOfItems: reader.readBoolOrNull(offsets[51]), + markEpisodeAsSeenType: reader.readLongOrNull(offsets[53]), + onlyIncludePinnedSources: reader.readBoolOrNull(offsets[54]), + pagePreloadAmount: reader.readLongOrNull(offsets[55]), personalPageModeList: reader.readObjectList( - offsets[53], + offsets[56], PersonalPageModeSchema.deserialize, allOffsets, PersonalPageMode(), ), personalReaderModeList: reader.readObjectList( - offsets[54], + offsets[57], PersonalReaderModeSchema.deserialize, allOffsets, PersonalReaderMode(), ), - pureBlackDarkMode: reader.readBoolOrNull(offsets[55]), - relativeTimesTamps: reader.readLongOrNull(offsets[56]), - saveAsCBZArchive: reader.readBoolOrNull(offsets[57]), + pureBlackDarkMode: reader.readBoolOrNull(offsets[58]), + relativeTimesTamps: reader.readLongOrNull(offsets[59]), + saveAsCBZArchive: reader.readBoolOrNull(offsets[60]), scaleType: - _SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offsets[58])] ?? + _SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offsets[61])] ?? ScaleType.fitScreen, - showNSFW: reader.readBoolOrNull(offsets[59]), - showPagesNumber: reader.readBoolOrNull(offsets[60]), + showNSFW: reader.readBoolOrNull(offsets[62]), + showPagesNumber: reader.readBoolOrNull(offsets[63]), sortChapterList: reader.readObjectList( - offsets[61], + offsets[64], SortChapterSchema.deserialize, allOffsets, SortChapter(), ), sortLibraryAnime: reader.readObjectOrNull( - offsets[62], + offsets[65], SortLibraryMangaSchema.deserialize, allOffsets, ), sortLibraryManga: reader.readObjectOrNull( - offsets[63], + offsets[66], SortLibraryMangaSchema.deserialize, allOffsets, ), - startDatebackup: reader.readLongOrNull(offsets[64]), - themeIsDark: reader.readBoolOrNull(offsets[65]), - updateProgressAfterReading: reader.readBoolOrNull(offsets[66]), - usePageTapZones: reader.readBoolOrNull(offsets[67]), - userAgent: reader.readStringOrNull(offsets[68]), + startDatebackup: reader.readLongOrNull(offsets[67]), + themeIsDark: reader.readBoolOrNull(offsets[68]), + updateProgressAfterReading: reader.readBoolOrNull(offsets[69]), + usePageTapZones: reader.readBoolOrNull(offsets[70]), + userAgent: reader.readStringOrNull(offsets[71]), ); object.chapterFilterBookmarkedList = reader.readObjectList( - offsets[14], + offsets[15], ChapterFilterBookmarkedSchema.deserialize, allOffsets, ChapterFilterBookmarked(), ); object.chapterFilterUnreadList = reader.readObjectList( - offsets[16], + offsets[17], ChapterFilterUnreadSchema.deserialize, allOffsets, ChapterFilterUnread(), ); object.filterScanlatorList = reader.readObjectList( - offsets[31], + offsets[34], FilterScanlatorSchema.deserialize, allOffsets, FilterScanlator(), ); object.locale = reader.readObjectOrNull( - offsets[49], + offsets[52], L10nLocaleSchema.deserialize, allOffsets, ); @@ -947,13 +968,13 @@ P _settingsDeserializeProp

( ) { switch (propertyId) { case 0: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 1: + return (reader.readBoolOrNull(offset)) as P; + case 2: return (_SettingsanimeDisplayTypeValueEnumMap[ reader.readByteOrNull(offset)] ?? DisplayType.compactGrid) as P; - case 2: - return (reader.readBoolOrNull(offset)) as P; case 3: return (reader.readBoolOrNull(offset)) as P; case 4: @@ -965,112 +986,112 @@ P _settingsDeserializeProp

( case 7: return (reader.readBoolOrNull(offset)) as P; case 8: - return (reader.readStringOrNull(offset)) as P; - case 9: return (reader.readBoolOrNull(offset)) as P; + case 9: + return (reader.readStringOrNull(offset)) as P; case 10: + return (reader.readBoolOrNull(offset)) as P; + case 11: return (reader.readObjectList( offset, AutoScrollPagesSchema.deserialize, allOffsets, AutoScrollPages(), )) as P; - case 11: + case 12: return (_SettingsbackgroundColorValueEnumMap[ reader.readByteOrNull(offset)] ?? BackgroundColor.black) as P; - case 12: - return (reader.readLongOrNull(offset)) as P; case 13: - return (reader.readLongList(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 14: + return (reader.readLongList(offset)) as P; + case 15: return (reader.readObjectList( offset, ChapterFilterBookmarkedSchema.deserialize, allOffsets, ChapterFilterBookmarked(), )) as P; - case 15: + case 16: return (reader.readObjectList( offset, ChapterFilterDownloadedSchema.deserialize, allOffsets, ChapterFilterDownloaded(), )) as P; - case 16: + case 17: return (reader.readObjectList( offset, ChapterFilterUnreadSchema.deserialize, allOffsets, ChapterFilterUnread(), )) as P; - case 17: + case 18: return (reader.readObjectList( offset, ChapterPageIndexSchema.deserialize, allOffsets, ChapterPageIndex(), )) as P; - case 18: + case 19: return (reader.readObjectList( offset, ChapterPageurlsSchema.deserialize, allOffsets, ChapterPageurls(), )) as P; - case 19: - return (reader.readBoolOrNull(offset)) as P; case 20: + return (reader.readBoolOrNull(offset)) as P; + case 21: return (reader.readObjectList( offset, CookieSchema.deserialize, allOffsets, Cookie(), )) as P; - case 21: - return (reader.readBoolOrNull(offset)) as P; case 22: - return (reader.readStringOrNull(offset)) as P; + return (reader.readBoolOrNull(offset)) as P; case 23: - return (reader.readLongOrNull(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 24: - return (reader.readDoubleOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 25: + return (reader.readDoubleOrNull(offset)) as P; + case 26: return (_SettingsdefaultReaderModeValueEnumMap[ reader.readByteOrNull(offset)] ?? ReaderMode.vertical) as P; - case 26: - return (reader.readLongOrNull(offset)) as P; case 27: + return (reader.readLongOrNull(offset)) as P; + case 28: return (_SettingsdisplayTypeValueEnumMap[reader.readByteOrNull(offset)] ?? DisplayType.compactGrid) as P; - case 28: - return (reader.readLongOrNull(offset)) as P; case 29: - return (reader.readStringOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 30: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readStringOrNull(offset)) as P; case 31: + return (reader.readBoolOrNull(offset)) as P; + case 32: + return (reader.readBoolOrNull(offset)) as P; + case 33: + return (reader.readBoolOrNull(offset)) as P; + case 34: return (reader.readObjectList( offset, FilterScanlatorSchema.deserialize, allOffsets, FilterScanlator(), )) as P; - case 32: - return (reader.readDoubleOrNull(offset)) as P; - case 33: - return (reader.readLongOrNull(offset)) as P; - case 34: - return (reader.readBoolOrNull(offset)) as P; case 35: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readDoubleOrNull(offset)) as P; case 36: return (reader.readLongOrNull(offset)) as P; case 37: - return (reader.readLongOrNull(offset)) as P; + return (reader.readBoolOrNull(offset)) as P; case 38: - return (reader.readLongOrNull(offset)) as P; + return (reader.readBoolOrNull(offset)) as P; case 39: return (reader.readLongOrNull(offset)) as P; case 40: @@ -1082,82 +1103,88 @@ P _settingsDeserializeProp

( case 43: return (reader.readLongOrNull(offset)) as P; case 44: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 45: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 46: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 47: return (reader.readBoolOrNull(offset)) as P; case 48: return (reader.readBoolOrNull(offset)) as P; case 49: + return (reader.readBoolOrNull(offset)) as P; + case 50: + return (reader.readBoolOrNull(offset)) as P; + case 51: + return (reader.readBoolOrNull(offset)) as P; + case 52: return (reader.readObjectOrNull( offset, L10nLocaleSchema.deserialize, allOffsets, )) as P; - case 50: - return (reader.readLongOrNull(offset)) as P; - case 51: - return (reader.readBoolOrNull(offset)) as P; - case 52: - return (reader.readLongOrNull(offset)) as P; case 53: + return (reader.readLongOrNull(offset)) as P; + case 54: + return (reader.readBoolOrNull(offset)) as P; + case 55: + return (reader.readLongOrNull(offset)) as P; + case 56: return (reader.readObjectList( offset, PersonalPageModeSchema.deserialize, allOffsets, PersonalPageMode(), )) as P; - case 54: + case 57: return (reader.readObjectList( offset, PersonalReaderModeSchema.deserialize, allOffsets, PersonalReaderMode(), )) as P; - case 55: - return (reader.readBoolOrNull(offset)) as P; - case 56: - return (reader.readLongOrNull(offset)) as P; - case 57: - return (reader.readBoolOrNull(offset)) as P; case 58: - return (_SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offset)] ?? - ScaleType.fitScreen) as P; - case 59: return (reader.readBoolOrNull(offset)) as P; + case 59: + return (reader.readLongOrNull(offset)) as P; case 60: return (reader.readBoolOrNull(offset)) as P; case 61: + return (_SettingsscaleTypeValueEnumMap[reader.readByteOrNull(offset)] ?? + ScaleType.fitScreen) as P; + case 62: + return (reader.readBoolOrNull(offset)) as P; + case 63: + return (reader.readBoolOrNull(offset)) as P; + case 64: return (reader.readObjectList( offset, SortChapterSchema.deserialize, allOffsets, SortChapter(), )) as P; - case 62: - return (reader.readObjectOrNull( - offset, - SortLibraryMangaSchema.deserialize, - allOffsets, - )) as P; - case 63: - return (reader.readObjectOrNull( - offset, - SortLibraryMangaSchema.deserialize, - allOffsets, - )) as P; - case 64: - return (reader.readLongOrNull(offset)) as P; case 65: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readObjectOrNull( + offset, + SortLibraryMangaSchema.deserialize, + allOffsets, + )) as P; case 66: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readObjectOrNull( + offset, + SortLibraryMangaSchema.deserialize, + allOffsets, + )) as P; case 67: - return (reader.readBoolOrNull(offset)) as P; + return (reader.readLongOrNull(offset)) as P; case 68: + return (reader.readBoolOrNull(offset)) as P; + case 69: + return (reader.readBoolOrNull(offset)) as P; + case 70: + return (reader.readBoolOrNull(offset)) as P; + case 71: return (reader.readStringOrNull(offset)) as P; default: throw IsarError('Unknown property with id $propertyId'); @@ -1321,6 +1348,80 @@ extension SettingsQueryWhere on QueryBuilder { extension SettingsQueryFilter on QueryBuilder { + QueryBuilder + aniSkipTimeoutLengthIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'aniSkipTimeoutLength', + )); + }); + } + + QueryBuilder + aniSkipTimeoutLengthIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'aniSkipTimeoutLength', + )); + }); + } + + QueryBuilder + aniSkipTimeoutLengthEqualTo(int? value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'aniSkipTimeoutLength', + value: value, + )); + }); + } + + QueryBuilder + aniSkipTimeoutLengthGreaterThan( + int? value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'aniSkipTimeoutLength', + value: value, + )); + }); + } + + QueryBuilder + aniSkipTimeoutLengthLessThan( + int? value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'aniSkipTimeoutLength', + value: value, + )); + }); + } + + QueryBuilder + aniSkipTimeoutLengthBetween( + int? lower, + int? upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'aniSkipTimeoutLength', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + QueryBuilder animatePageTransitionsIsNull() { return QueryBuilder.apply(this, (query) { @@ -3596,6 +3697,62 @@ extension SettingsQueryFilter }); } + QueryBuilder + enableAniSkipIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'enableAniSkip', + )); + }); + } + + QueryBuilder + enableAniSkipIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'enableAniSkip', + )); + }); + } + + QueryBuilder enableAniSkipEqualTo( + bool? value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'enableAniSkip', + value: value, + )); + }); + } + + QueryBuilder + enableAutoSkipIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'enableAutoSkip', + )); + }); + } + + QueryBuilder + enableAutoSkipIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'enableAutoSkip', + )); + }); + } + + QueryBuilder enableAutoSkipEqualTo( + bool? value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'enableAutoSkip', + value: value, + )); + }); + } + QueryBuilder filterScanlatorListIsNull() { return QueryBuilder.apply(this, (query) { @@ -5972,6 +6129,19 @@ extension SettingsQueryLinks } extension SettingsQuerySortBy on QueryBuilder { + QueryBuilder sortByAniSkipTimeoutLength() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'aniSkipTimeoutLength', Sort.asc); + }); + } + + QueryBuilder + sortByAniSkipTimeoutLengthDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'aniSkipTimeoutLength', Sort.desc); + }); + } + QueryBuilder sortByAnimatePageTransitions() { return QueryBuilder.apply(this, (query) { @@ -6276,6 +6446,30 @@ extension SettingsQuerySortBy on QueryBuilder { }); } + QueryBuilder sortByEnableAniSkip() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'enableAniSkip', Sort.asc); + }); + } + + QueryBuilder sortByEnableAniSkipDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'enableAniSkip', Sort.desc); + }); + } + + QueryBuilder sortByEnableAutoSkip() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'enableAutoSkip', Sort.asc); + }); + } + + QueryBuilder sortByEnableAutoSkipDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'enableAutoSkip', Sort.desc); + }); + } + QueryBuilder sortByFlexColorSchemeBlendLevel() { return QueryBuilder.apply(this, (query) { @@ -6686,6 +6880,19 @@ extension SettingsQuerySortBy on QueryBuilder { extension SettingsQuerySortThenBy on QueryBuilder { + QueryBuilder thenByAniSkipTimeoutLength() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'aniSkipTimeoutLength', Sort.asc); + }); + } + + QueryBuilder + thenByAniSkipTimeoutLengthDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'aniSkipTimeoutLength', Sort.desc); + }); + } + QueryBuilder thenByAnimatePageTransitions() { return QueryBuilder.apply(this, (query) { @@ -6990,6 +7197,30 @@ extension SettingsQuerySortThenBy }); } + QueryBuilder thenByEnableAniSkip() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'enableAniSkip', Sort.asc); + }); + } + + QueryBuilder thenByEnableAniSkipDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'enableAniSkip', Sort.desc); + }); + } + + QueryBuilder thenByEnableAutoSkip() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'enableAutoSkip', Sort.asc); + }); + } + + QueryBuilder thenByEnableAutoSkipDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'enableAutoSkip', Sort.desc); + }); + } + QueryBuilder thenByFlexColorSchemeBlendLevel() { return QueryBuilder.apply(this, (query) { @@ -7412,6 +7643,12 @@ extension SettingsQuerySortThenBy extension SettingsQueryWhereDistinct on QueryBuilder { + QueryBuilder distinctByAniSkipTimeoutLength() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'aniSkipTimeoutLength'); + }); + } + QueryBuilder distinctByAnimatePageTransitions() { return QueryBuilder.apply(this, (query) { @@ -7574,6 +7811,18 @@ extension SettingsQueryWhereDistinct }); } + QueryBuilder distinctByEnableAniSkip() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'enableAniSkip'); + }); + } + + QueryBuilder distinctByEnableAutoSkip() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'enableAutoSkip'); + }); + } + QueryBuilder distinctByFlexColorSchemeBlendLevel() { return QueryBuilder.apply(this, (query) { @@ -7786,6 +8035,13 @@ extension SettingsQueryProperty }); } + QueryBuilder + aniSkipTimeoutLengthProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'aniSkipTimeoutLength'); + }); + } + QueryBuilder animatePageTransitionsProperty() { return QueryBuilder.apply(this, (query) { @@ -7997,6 +8253,18 @@ extension SettingsQueryProperty }); } + QueryBuilder enableAniSkipProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'enableAniSkip'); + }); + } + + QueryBuilder enableAutoSkipProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'enableAutoSkip'); + }); + } + QueryBuilder?, QQueryOperations> filterScanlatorListProperty() { return QueryBuilder.apply(this, (query) { diff --git a/lib/modules/anime/anime_player_view.dart b/lib/modules/anime/anime_player_view.dart index 00e2632..47695ce 100644 --- a/lib/modules/anime/anime_player_view.dart +++ b/lib/modules/anime/anime_player_view.dart @@ -9,12 +9,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart' as riv; import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/video.dart' as vid; import 'package:mangayomi/modules/anime/providers/anime_player_controller_provider.dart'; +import 'package:mangayomi/modules/anime/widgets/aniskip_countdown_btn.dart'; import 'package:mangayomi/modules/anime/widgets/desktop.dart'; import 'package:mangayomi/modules/anime/widgets/mobile.dart'; import 'package:mangayomi/modules/manga/reader/providers/push_router.dart'; import 'package:mangayomi/modules/more/settings/player/providers/player_state_provider.dart'; import 'package:mangayomi/modules/widgets/progress_center.dart'; import 'package:mangayomi/providers/l10n_providers.dart'; +import 'package:mangayomi/services/aniskip.dart'; import 'package:mangayomi/services/get_video_list.dart'; import 'package:mangayomi/utils/extensions/build_context_extensions.dart'; import 'package:media_kit/media_kit.dart'; @@ -211,7 +213,12 @@ class _AnimeStreamPageState extends riv.ConsumerState { _currentTotalDuration.value = duration; }, ); - + Results? _openingResult; + Results? _endingResult; + bool _hasOpeningSkip = false; + bool _hasEndingSkip = false; + final ValueNotifier _showAniSkipOpeningButton = ValueNotifier(false); + final ValueNotifier _showAniSkipEndingButton = ValueNotifier(false); @override void initState() { _setCurrentPosition(true); @@ -220,9 +227,31 @@ class _AnimeStreamPageState extends riv.ConsumerState { _player.open(Media(_video.value!.videoTrack!.id, httpHeaders: _video.value!.headers)); _setPlaybackSpeed(ref.read(defaultPlayBackSpeedStateProvider)); + _initAniSkip(); super.initState(); } + void _initAniSkip() async { + await _player.stream.buffer.first; + _streamController.getAniSkipResults((result) { + final openingRes = + result.where((element) => element.skipType == "op").toList(); + _hasOpeningSkip = openingRes.isNotEmpty; + if (_hasOpeningSkip) { + _openingResult = openingRes.first; + } + final endingRes = + result.where((element) => element.skipType == "ed").toList(); + _hasEndingSkip = endingRes.isNotEmpty; + if (_hasEndingSkip) { + _endingResult = endingRes.first; + } + if (mounted) { + setState(() {}); + } + }); + } + @override void dispose() { _setCurrentPosition(true); @@ -838,7 +867,8 @@ class _AnimeStreamPageState extends riv.ConsumerState { padding: const EdgeInsets.only(top: 2), child: Text( skipDuration.toString(), - style: const TextStyle(fontSize: 9), + style: const TextStyle( + fontSize: 9, color: Colors.white), ), )), ), @@ -874,7 +904,8 @@ class _AnimeStreamPageState extends riv.ConsumerState { padding: const EdgeInsets.only(top: 2), child: Text( skipDuration.toString(), - style: const TextStyle(fontSize: 9), + style: const TextStyle( + fontSize: 9, color: Colors.white), ), )), ), @@ -1017,48 +1048,126 @@ class _AnimeStreamPageState extends riv.ConsumerState { Widget _videoPlayer(BuildContext context) { final fit = _fit.value; _resize(fit); - return Video( - subtitleViewConfiguration: const SubtitleViewConfiguration( - style: TextStyle( - fontSize: 50, - fontWeight: FontWeight.bold, - color: Colors.white, - fontFamily: "", - shadows: [Shadow(offset: Offset(0.2, 0.0), blurRadius: 7.0)], - backgroundColor: Colors.transparent), - ), - fit: fit, - key: _key, - controls: (state) => _isDesktop - ? DesktopControllerWidget( - videoController: _controller, - topButtonBarWidget: _topButtonBar(context), - videoStatekey: _key, - bottomButtonBarWidget: _desktopBottomButtonBar(context), - streamController: _streamController, - seekToWidget: Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: Row( - children: [ - _seekToWidget(), - ], + return Stack( + children: [ + Video( + subtitleViewConfiguration: const SubtitleViewConfiguration( + style: TextStyle( + fontSize: 50, + fontWeight: FontWeight.bold, + color: Colors.white, + fontFamily: "", + shadows: [Shadow(offset: Offset(0.2, 0.0), blurRadius: 7.0)], + backgroundColor: Colors.transparent), + ), + fit: fit, + key: _key, + controls: (state) => _isDesktop + ? DesktopControllerWidget( + videoController: _controller, + topButtonBarWidget: _topButtonBar(context), + videoStatekey: _key, + bottomButtonBarWidget: _desktopBottomButtonBar(context), + streamController: _streamController, + seekToWidget: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: Row( + children: [ + _seekToWidget(), + ], + ), + ), + tempDuration: (value) { + _tempPosition.value = value; + }, + ) + : MobileControllerWidget( + videoController: _controller, + topButtonBarWidget: _topButtonBar(context), + videoStatekey: _key, + bottomButtonBarWidget: _mobileBottomButtonBar(context), + streamController: _streamController, ), - ), - tempDuration: (value) { - _tempPosition.value = value; - }, - ) - : MobileControllerWidget( - videoController: _controller, - topButtonBarWidget: _topButtonBar(context), - videoStatekey: _key, - bottomButtonBarWidget: _mobileBottomButtonBar(context), - streamController: _streamController, - ), - controller: _controller, - width: context.mediaWidth(1), - height: context.mediaHeight(1), - resumeUponEnteringForegroundMode: true, + controller: _controller, + width: context.mediaWidth(1), + height: context.mediaHeight(1), + resumeUponEnteringForegroundMode: true, + ), + Positioned( + right: 0, + bottom: 80, + child: ValueListenableBuilder( + valueListenable: _currentPosition, + builder: (context, value, child) { + if (_hasOpeningSkip || _hasEndingSkip) { + if (_hasOpeningSkip) { + if (_openingResult!.interval!.startTime!.ceil() <= + value.inSeconds && + _openingResult!.interval!.endTime!.toInt() > + value.inSeconds) { + _showAniSkipOpeningButton.value = true; + _showAniSkipEndingButton.value = false; + } else { + _showAniSkipOpeningButton.value = false; + } + } + if (_hasEndingSkip) { + if (_endingResult!.interval!.startTime!.ceil() <= + value.inSeconds && + _endingResult!.interval!.endTime!.toInt() > + value.inSeconds) { + _showAniSkipEndingButton.value = true; + _showAniSkipOpeningButton.value = false; + } + } else { + _showAniSkipEndingButton.value = false; + } + } + return Consumer(builder: (context, ref, _) { + late final enableAniSkip = + ref.watch(enableAniSkipStateProvider); + late final enableAutoSkip = + ref.watch(enableAutoSkipStateProvider); + late final aniSkipTimeoutLength = + ref.watch(aniSkipTimeoutLengthStateProvider); + return ValueListenableBuilder( + valueListenable: _showAniSkipOpeningButton, + builder: (context, showAniSkipOpENINGButton, child) { + return ValueListenableBuilder( + valueListenable: _showAniSkipEndingButton, + builder: (context, showAniSkipENDINGButton, child) { + return showAniSkipOpENINGButton + ? Container( + key: const Key('skip_opening'), + child: AniSkipCountDownButton( + active: enableAniSkip, + autoSkip: enableAutoSkip, + timeoutLength: aniSkipTimeoutLength, + skipTypeText: context.l10n.skip_opening, + player: _player, + aniSkipResult: _openingResult, + )) + : showAniSkipENDINGButton + ? Container( + key: const Key('skip_ending'), + child: AniSkipCountDownButton( + active: enableAniSkip, + autoSkip: enableAutoSkip, + timeoutLength: aniSkipTimeoutLength, + skipTypeText: context.l10n.skip_ending, + player: _player, + aniSkipResult: _endingResult, + )) + : const SizedBox.shrink(); + }, + ); + }, + ); + }); + }, + ), + ), + ], ); } diff --git a/lib/modules/anime/providers/anime_player_controller_provider.dart b/lib/modules/anime/providers/anime_player_controller_provider.dart index ffb7b6b..059366a 100644 --- a/lib/modules/anime/providers/anime_player_controller_provider.dart +++ b/lib/modules/anime/providers/anime_player_controller_provider.dart @@ -4,8 +4,11 @@ import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/history.dart'; import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/models/settings.dart'; +import 'package:mangayomi/models/track.dart'; import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart'; import 'package:mangayomi/modules/more/settings/player/providers/player_state_provider.dart'; +import 'package:mangayomi/services/aniskip.dart'; +import 'package:mangayomi/utils/chapter_recognition.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'anime_player_controller_provider.g.dart'; @@ -168,5 +171,42 @@ class AnimeStreamController extends _$AnimeStreamController { } } } - + + (int, int)? _getTrackId() { + final malId = isar.tracks + .filter() + .syncIdEqualTo(1) + .mangaIdEqualTo(episode.manga.value!.id!) + .findFirstSync() + ?.mediaId; + final aniId = isar.tracks + .filter() + .syncIdEqualTo(2) + .mangaIdEqualTo(episode.manga.value!.id!) + .findFirstSync() + ?.mediaId; + return switch (malId) { + != null => (malId, 1), + == null => switch (aniId) { != null => (aniId, 2), _ => null }, + _ => null + }; + } + + Future?> getAniSkipResults( + Function(List) result) async { + await Future.delayed(const Duration(milliseconds: 300)); + if (ref.watch(enableAniSkipStateProvider)) { + final id = _getTrackId(); + if (id != null) { + final res = await ref.read(aniSkipProvider.notifier).getResult( + id, + ChapterRecognition() + .parseChapterNumber(episode.manga.value!.name!, episode.name!), + 0); + result.call(res ?? []); + return res; + } + } + return null; + } } diff --git a/lib/modules/anime/providers/anime_player_controller_provider.g.dart b/lib/modules/anime/providers/anime_player_controller_provider.g.dart index fce6aaa..7954940 100644 --- a/lib/modules/anime/providers/anime_player_controller_provider.g.dart +++ b/lib/modules/anime/providers/anime_player_controller_provider.g.dart @@ -7,7 +7,7 @@ part of 'anime_player_controller_provider.dart'; // ************************************************************************** String _$animeStreamControllerHash() => - r'bf0730758333f74352257fb6afd2d0d0a319044f'; + r'7fc848faf2b337f34561ec4ff519b516ab9954a3'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/modules/anime/widgets/aniskip_countdown_btn.dart b/lib/modules/anime/widgets/aniskip_countdown_btn.dart new file mode 100644 index 0000000..7ecdfd6 --- /dev/null +++ b/lib/modules/anime/widgets/aniskip_countdown_btn.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:mangayomi/services/aniskip.dart'; +import 'package:media_kit/media_kit.dart'; + +class AniSkipCountDownButton extends ConsumerStatefulWidget { + final bool active; + final bool autoSkip; + final int timeoutLength; + final String skipTypeText; + final Results? aniSkipResult; + final Player player; + const AniSkipCountDownButton( + {super.key, + required this.skipTypeText, + required this.aniSkipResult, + required this.player, + required this.active, + required this.autoSkip, + required this.timeoutLength}); + + @override + ConsumerState createState() => + _AniSkipCountDownButtonState(); +} + +class _AniSkipCountDownButtonState extends ConsumerState + with TickerProviderStateMixin { + late AnimationController _controller; + @override + void initState() { + _controller = AnimationController( + vsync: this, duration: Duration(seconds: widget.timeoutLength)) + ..forward(); + super.initState(); + if (widget.active) { + if (widget.autoSkip) { + _seekTo(); + } else { + _controller.addListener(() { + if (_controller.isCompleted) { + setState(() { + _isCompleted = true; + }); + _controller.reset(); + } + }); + } + } + } + + void _seekTo() { + setState(() { + _isCompleted = true; + }); + _controller.reset(); + widget.player.seek( + Duration(seconds: widget.aniSkipResult!.interval!.endTime!.ceil())); + } + + bool _isCompleted = false; + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.active && !widget.autoSkip + ? _isCompleted + ? const SizedBox.shrink() + : AnimatedBuilder( + animation: _controller, + builder: (context, child) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 40), + child: MaterialButton( + padding: const EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5)), + onPressed: () { + _seekTo(); + }, + child: Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: Colors.black54, + borderRadius: BorderRadius.circular(5), + ), + width: 200, + child: Stack( + children: [ + RotatedBox( + quarterTurns: 0, + child: Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(5), + ), + child: SizedBox.fromSize( + size: const Size(200, 40), + child: LinearProgressIndicator( + color: Colors.red, + value: 1 - _controller.value, + backgroundColor: Colors.transparent)), + ), + ), + Positioned.fill( + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 10), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceAround, + children: [ + Text( + widget.skipTypeText.toUpperCase(), + style: const TextStyle( + fontWeight: FontWeight.bold), + ), + Text((widget.timeoutLength - + (_controller.duration! * + _controller.value) + .inSeconds) + .toString()), + ], + ), + )) + ], + ), + ), + ), + ); + }) + : const SizedBox.shrink(); + } +} diff --git a/lib/modules/manga/detail/providers/update_manga_detail_providers.g.dart b/lib/modules/manga/detail/providers/update_manga_detail_providers.g.dart index e98211d..8021530 100644 --- a/lib/modules/manga/detail/providers/update_manga_detail_providers.g.dart +++ b/lib/modules/manga/detail/providers/update_manga_detail_providers.g.dart @@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart'; // RiverpodGenerator // ************************************************************************** -String _$updateMangaDetailHash() => r'753f7db14ba8284ede82e9c8baec4344b28acedb'; +String _$updateMangaDetailHash() => r'fae71a657e084879e6bbef7b343291a1f014f790'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/modules/more/settings/player/player_screen.dart b/lib/modules/more/settings/player/player_screen.dart index c987dea..b4031fe 100644 --- a/lib/modules/more/settings/player/player_screen.dart +++ b/lib/modules/more/settings/player/player_screen.dart @@ -18,6 +18,10 @@ class PlayerScreen extends ConsumerWidget { ref.watch(defaultDoubleTapToSkipLengthStateProvider); final defaultPlayBackSpeed = ref.watch(defaultPlayBackSpeedStateProvider); + final enableAniSkip = ref.watch(enableAniSkipStateProvider); + final enableAutoSkip = ref.watch(enableAutoSkipStateProvider); + final aniSkipTimeoutLength = ref.watch(aniSkipTimeoutLengthStateProvider); + return Scaffold( appBar: AppBar( title: Text(context.l10n.player), @@ -265,6 +269,103 @@ class PlayerScreen extends ConsumerWidget { style: TextStyle(fontSize: 11, color: context.secondaryColor), ), ), + ListTile( + title: Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Row( + children: [ + Icon( + Icons.info_outline_rounded, + color: context.secondaryColor, + ), + ], + ), + ), + subtitle: Text(context.l10n.aniskip_requires_info, + style: + TextStyle(fontSize: 11, color: context.secondaryColor)), + ), + ExpansionTile( + title: Text(context.l10n.enable_aniskip), + shape: const StarBorder(), + initiallyExpanded: enableAniSkip, + trailing: IgnorePointer( + child: Switch( + value: enableAniSkip, + onChanged: (_) {}, + ), + ), + onExpansionChanged: (value) => + ref.read(enableAniSkipStateProvider.notifier).set(value), + children: [ + SwitchListTile( + value: enableAutoSkip, + title: Text(context.l10n.enable_auto_skip), + onChanged: (value) { + ref.read(enableAutoSkipStateProvider.notifier).set(value); + }), + ListTile( + onTap: () { + final values = [5, 6, 7, 8, 9, 10]; + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text( + context.l10n.default_playback_speed_length), + content: SizedBox( + width: context.mediaWidth(0.8), + child: ListView.builder( + shrinkWrap: true, + itemCount: values.length, + itemBuilder: (context, index) { + return RadioListTile( + dense: true, + contentPadding: const EdgeInsets.all(0), + value: values[index], + groupValue: aniSkipTimeoutLength, + onChanged: (value) { + ref + .read( + aniSkipTimeoutLengthStateProvider + .notifier) + .set(value!); + Navigator.pop(context); + }, + title: Row( + children: [Text("${values[index]}s")], + ), + ); + }, + )), + actions: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () async { + Navigator.pop(context); + }, + child: Text( + context.l10n.cancel, + style: TextStyle( + color: context.primaryColor), + )), + ], + ) + ], + ); + }); + }, + title: Text(context.l10n.aniskip_button_timeout), + subtitle: Text( + "${aniSkipTimeoutLength}s", + style: + TextStyle(fontSize: 11, color: context.secondaryColor), + ), + ), + ], + ), ], ), ), diff --git a/lib/modules/more/settings/player/providers/player_state_provider.dart b/lib/modules/more/settings/player/providers/player_state_provider.dart index 7658331..da1f0a9 100644 --- a/lib/modules/more/settings/player/providers/player_state_provider.dart +++ b/lib/modules/more/settings/player/providers/player_state_provider.dart @@ -63,3 +63,48 @@ class DefaultPlayBackSpeedState extends _$DefaultPlayBackSpeedState { () => isar.settings.putSync(settings!..defaultPlayBackSpeed = value)); } } + +@riverpod +class EnableAniSkipState extends _$EnableAniSkipState { + @override + bool build() { + return isar.settings.getSync(227)!.enableAniSkip ?? false; + } + + void set(bool value) { + final settings = isar.settings.getSync(227); + state = value; + isar.writeTxnSync( + () => isar.settings.putSync(settings!..enableAniSkip = value)); + } +} + +@riverpod +class EnableAutoSkipState extends _$EnableAutoSkipState { + @override + bool build() { + return isar.settings.getSync(227)!.enableAutoSkip ?? false; + } + + void set(bool value) { + final settings = isar.settings.getSync(227); + state = value; + isar.writeTxnSync( + () => isar.settings.putSync(settings!..enableAutoSkip = value)); + } +} + +@riverpod +class AniSkipTimeoutLengthState extends _$AniSkipTimeoutLengthState { + @override + int build() { + return isar.settings.getSync(227)!.aniSkipTimeoutLength ?? 5; + } + + void set(int value) { + final settings = isar.settings.getSync(227); + state = value; + isar.writeTxnSync( + () => isar.settings.putSync(settings!..aniSkipTimeoutLength = value)); + } +} diff --git a/lib/modules/more/settings/player/providers/player_state_provider.g.dart b/lib/modules/more/settings/player/providers/player_state_provider.g.dart index 75d9f03..fc724d7 100644 --- a/lib/modules/more/settings/player/providers/player_state_provider.g.dart +++ b/lib/modules/more/settings/player/providers/player_state_provider.g.dart @@ -74,5 +74,56 @@ final defaultPlayBackSpeedStateProvider = ); typedef _$DefaultPlayBackSpeedState = AutoDisposeNotifier; +String _$enableAniSkipStateHash() => + r'1b448453e54f2a261820d40ca2d82971d165372a'; + +/// See also [EnableAniSkipState]. +@ProviderFor(EnableAniSkipState) +final enableAniSkipStateProvider = + AutoDisposeNotifierProvider.internal( + EnableAniSkipState.new, + name: r'enableAniSkipStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$enableAniSkipStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$EnableAniSkipState = AutoDisposeNotifier; +String _$enableAutoSkipStateHash() => + r'5f4d5e669cadf98396afe52635e2ec5f2ee7ff2f'; + +/// See also [EnableAutoSkipState]. +@ProviderFor(EnableAutoSkipState) +final enableAutoSkipStateProvider = + AutoDisposeNotifierProvider.internal( + EnableAutoSkipState.new, + name: r'enableAutoSkipStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$enableAutoSkipStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$EnableAutoSkipState = AutoDisposeNotifier; +String _$aniSkipTimeoutLengthStateHash() => + r'fc1c16c22fb129e1a2ea5434282baf2dcfa79c82'; + +/// See also [AniSkipTimeoutLengthState]. +@ProviderFor(AniSkipTimeoutLengthState) +final aniSkipTimeoutLengthStateProvider = + AutoDisposeNotifierProvider.internal( + AniSkipTimeoutLengthState.new, + name: r'aniSkipTimeoutLengthStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$aniSkipTimeoutLengthStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$AniSkipTimeoutLengthState = AutoDisposeNotifier; // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/services/aniskip.dart b/lib/services/aniskip.dart new file mode 100644 index 0000000..0faeff3 --- /dev/null +++ b/lib/services/aniskip.dart @@ -0,0 +1,98 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +part 'aniskip.g.dart'; + +// credits: https://github.com/aniyomiorg/aniyomi/blob/master/app/src/main/java/eu/kanade/tachiyomi/util/AniSkipApi.kt +@riverpod +class AniSkip extends _$AniSkip { + final _client = http.Client(); + @override + void build() {} + + Future?> getResult( + (int, int) id, int episodeNumber, double episodeLength) async { + try { + final malId = await _getMalId(id); + + final url = + "https://api.aniskip.com/v2/skip-times/$malId/$episodeNumber?types[]=ed&types[]=mixed-ed&types[]=mixed-op&types[]=op&types[]=recap&episodeLength=$episodeLength"; + final response = await _client.get(Uri.parse(url)); + final res = AniSkipResponse.fromJson(json.decode(response.body)); + + return (res.found ?? false) ? res.results : null; + } catch (_) { + return null; + } + } + + Future _getMalId((int, int) id) async { + if (id.$2 == 1) return id.$1; + if (id.$2 != 2) throw ""; + + final query = """ + query{ + Media(id:${id.$1}){idMal} + } + """; + + final response = await _client.post( + Uri.parse("https://graphql.anilist.co"), + body: json.encode({"query": query}), + headers: {"Content-Type": "application/json"}, + ); + + return jsonDecode(response.body)["data"]["Media"]["idMal"] ?? 0; + } +} + +class AniSkipResponse { + bool? found; + List? results; + String? message; + int? statusCode; + + AniSkipResponse({this.found, this.results, this.message, this.statusCode}); + + factory AniSkipResponse.fromJson(Map json) { + return AniSkipResponse( + found: json['found'], + results: + (json['results'] as List?)?.map((e) => Results.fromJson(e)).toList(), + message: json['message'], + statusCode: json['statusCode'], + ); + } +} + +class Results { + Interval? interval; + String? skipType; + String? skipId; + double? episodeLength; + + Results({this.interval, this.skipType, this.skipId, this.episodeLength}); + + factory Results.fromJson(Map json) { + return Results( + interval: Interval.fromJson(json['interval']), + skipType: json['skipType'], + skipId: json['skipId'], + episodeLength: json['episodeLength'], + ); + } +} + +class Interval { + double? startTime; + double? endTime; + + Interval({this.startTime, this.endTime}); + + factory Interval.fromJson(Map json) { + return Interval( + startTime: json['startTime'], + endTime: json['endTime'], + ); + } +} diff --git a/lib/services/aniskip.g.dart b/lib/services/aniskip.g.dart new file mode 100644 index 0000000..843d5c5 --- /dev/null +++ b/lib/services/aniskip.g.dart @@ -0,0 +1,24 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'aniskip.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$aniSkipHash() => r'58cfba5bb87e0a5f34009391a204d99bf773c858'; + +/// See also [AniSkip]. +@ProviderFor(AniSkip) +final aniSkipProvider = AutoDisposeNotifierProvider.internal( + AniSkip.new, + name: r'aniSkipProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$aniSkipHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$AniSkip = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member