added multi language support

This commit is contained in:
kodjomoustapha 2023-07-11 17:40:18 +01:00
parent c652fc4cc1
commit 648efe00f5
68 changed files with 1672 additions and 692 deletions

25
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,25 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "mangayomi",
"request": "launch",
"type": "dart"
},
{
"name": "mangayomi (profile mode)",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "mangayomi (release mode)",
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
]
}

3
l10n.yaml Normal file
View file

@ -0,0 +1,3 @@
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart

169
lib/l10n/app_en.arb Normal file
View file

@ -0,0 +1,169 @@
{
"@@locale": "en",
"library": "Library",
"updates":"Updates",
"history": "History",
"browse":"Browse",
"more":"More",
"open_random_entry":"Open random entry",
"import":"Import",
"filter":"Filter",
"downloaded":"Downloaded",
"unread":"Unread",
"started":"Started",
"bookmarked":"Bookmarked",
"sort":"Sort",
"alphabetically":"Alphabetically",
"last_read":"Last read",
"last_update_check":"Last update check",
"unread_count":"Unread count",
"latest_chapter":"Latest chapter",
"date_added":"Date added",
"display":"Display",
"display_mode":"Display mode",
"compact_grid":"Compact grid",
"comfortable_grid":"Comfortable grid",
"cover_only_grid":"Cover-only grid",
"list":"List",
"badges":"Badges",
"downloaded_chapters":"Downloaded chapters",
"language":"Language",
"local_source":"Local source",
"tabs":"Tabs",
"show_category_tabs":"Show category tabs",
"show_numbers_of_items":"Show numbers of items",
"other":"Other",
"show_continue_reading_buttons":"Show continue reading buttons",
"empty_library":"Empty library",
"search":"Search...",
"no_recent_updates":"No recent updates",
"remove_everything":"Remove everything",
"remove_everything_msg":"Are you sure? All history will be lost",
"ok":"Ok",
"cancel":"Cancel",
"remove":"Remove",
"remove_history_msg":"This will remove the read date of this chapter. Are you sure?",
"last_used":"Last Used",
"pinned":"Pinned",
"sources":"Sources",
"install":"Install",
"update":"Update",
"latest":"Latest",
"extensions":"Extensions",
"migrate":"Migrate",
"incognito_mode":"Incognito Mode",
"incognito_mode_description":"Pauses reading history",
"download_queue":"Download Queue",
"categories":"Categories",
"settings":"Settings",
"about":"About",
"help":"Help",
"no_downloads":"No Downloads",
"edit_categories":"Edit Categories",
"edit_categories_description":"You have no categories. Tap the plus button to create one for organizing your library",
"add":"Add",
"add_category":"Add Category",
"name":"Name",
"category_name_required":"*Required",
"add_category_error_exist":"A category with this name already exist!",
"delete_category":"Delete Category",
"delete_category_msg":"Do you wish to delete the category {name}?",
"rename_category":"Rename Category",
"general":"General",
"general_subtitle":"App language",
"app_language":"App language",
"appearance":"Appearance",
"appearance_subtitle":"Theme, date & time format",
"theme":"Theme",
"dark_mode":"Dark mode",
"on":"On",
"off":"Off",
"pure_black_dark_mode":"Pure black dark mode",
"timestamp":"Timestamp",
"relative_timestamp":"Relative timestamp",
"relative_timestamp_short":"Short (Today, Yesterday)",
"relative_timestamp_long":"Long (Short+, n days ago)",
"date_format":"Date format",
"reader":"Reader",
"refresh":"refresh",
"reader_subtitle":"Reading mode, display, navigation",
"default_reading_mode":"Default reading mode",
"reading_mode_vertical":"Vertical",
"reading_mode_horizontal":"Horizontal",
"reading_mode_left_to_right":"Left to Right",
"reading_mode_right_to_left":"Right to Left",
"reading_mode_vertical_continuous":"Vertical continuous",
"reading_mode_webtoon":"Webtoon",
"double_tap_animation_speed":"Double tap animation speed",
"normal":"Normal",
"fast":"Fast",
"no_animation":"No animation",
"animate_page_transitions":"Animate page transitions",
"crop_borders":"Crop borders",
"downloads":"Downloads",
"downloads_subtitle":"Downloads settings",
"download_location":"Download location",
"custom_location":"Custom location",
"only_on_wifi":"Only on wifi",
"save_as_cbz_archive":"Save as CBZ archive",
"browse_subtitle":"Sources, global search",
"only_include_pinned_sources":"Only include pinned sources",
"nsfw_sources":"NSFW (+18) sources",
"nsfw_sources_show":"Show in sources and extensions lists",
"nsfw_sources_info":"This does not prevent unofficial or potentially incorrectly flagged extensions from surfacing NSFW (18+) content within the app",
"version":"Version",
"check_for_update":"Check for update",
"n_days_ago":"{days} ago",
"today":"Today",
"yesterday":"Yesterday",
"a_week_ago":"A week ago",
"add_to_library":"Add to library",
"completed":"Completed",
"ongoing":"Ongoing",
"on_hiatus":"On Hiatus",
"canceled":"Canceled",
"publishing_finished":"Publishing finished",
"unknown":"Unknown",
"set_categories":"Set categories",
"edit":"Edit",
"in_library":"In library",
"filter_scanlator_groups":"Filter scanlator groups",
"reset":"Reset",
"by_source":"By source",
"by_chapter_number":"By chapter number",
"by_upload_date":"By upload date",
"source_title":"Source title",
"chapter_number":"Chapter number",
"share":"Share",
"n_chapters":"{number} chapters",
"no_description":"No description",
"resume":"Resume",
"read":"Read",
"popular":"Popular",
"open_in_browser":"Open in browser",
"clear_cookie":"Clear cookie",
"show_page_number":"Show page number",
"from_library":"From library",
"downloaded_chapter":"Downloaded chapter",
"page":"Page {page}",
"global_search":"Global search",
"color_blend_level":"Color blend level",
"current":"Current {char}",
"finished":"Finished {char}",
"next":"Next {char}",
"previous":"Previous {char}",
"no_more_chapter":"There's no more chapter",
"no_result":"No result",
"send":"Send",
"delete":"Delete",
"start_downloading":"Start downloading now",
"retry":"Retry",
"add_chapters":"Add Chapters",
"delete_chapters":"Delete Chapter?",
"default0":"Default",
"total_chapters":"Total Chapters",
"import_archive_bd":"Import Comic Archive",
"import_archive_from_file":".cbz or .zip files",
"import_archive_from_folder":"From folder (which contains .cbz or .zip files)",
"nothing_read_recently":"Nothing read recently"
}

169
lib/l10n/app_fr.arb Normal file
View file

@ -0,0 +1,169 @@
{
"@@locale": "fr",
"library": "Bibliothèque",
"updates":"Nouveautés",
"history": "Historique",
"browse":"Explorer",
"more":"Plus",
"open_random_entry":"Ouvrir une entrée au hasard",
"import":"Importer",
"filter":"Filtre",
"downloaded":"Téléchargé",
"unread":"Non lus",
"started":"Commencé",
"bookmarked":"Signets",
"sort":"Trier",
"alphabetically":"Alphabétiquement",
"last_read":"Dernier lu",
"last_update_check":"Dernière mise à jour",
"unread_count":"Nombre de non-lus",
"latest_chapter":"Dernier chapitre",
"date_added":"Date ajoutée",
"display":"Affichage",
"display_mode":"Mode d'affichage",
"compact_grid":"Grille compacte",
"comfortable_grid":"Grille espacée",
"cover_only_grid":"Grille avec seulement la couverture",
"list":"Liste",
"badges":"Badges",
"downloaded_chapters":"Chapitres téléchargés",
"language":"Langue",
"local_source":"Source locale",
"tabs":"Onglets",
"show_category_tabs":"Afficher les onglets des catégories",
"show_numbers_of_items":"Afficher le nombre dentrées",
"other":"Autre",
"show_continue_reading_buttons":"Afficher le bouton Continuer la lecture",
"empty_library":"Votre bibliothèque est vide",
"search":"Rechercher...",
"no_recent_updates":"Aucune mise à jour disponible",
"remove_everything":"Tout retirer",
"remove_everything_msg":"Êtes-vous sûr(e) ? Tout l'historique sera effacé.",
"ok":"Ok",
"cancel":"Annuler",
"remove":"Supprimer",
"remove_history_msg":"Ceci enlèvera la date de lecture de ce chapitre. Êtes-vous sûr(e) ?",
"last_used":"Dernière utilisée",
"pinned":"Épinglé",
"sources":"Sources",
"install":"Installer",
"update":"Mettre à jour",
"latest":"Récents",
"extensions":"Extensions",
"migrate":"Migrer",
"incognito_mode":"Mode navigation privée",
"incognito_mode_description":"Suspend l'historique de lecture",
"download_queue":"File de téléchargement",
"categories":"Catégories",
"settings":"Paramètres",
"about":"À propos",
"help":"Aide",
"no_downloads":"Aucun téléchargement en cours",
"edit_categories":"Modifier les catégories",
"edit_categories_description":"Vous n'avez aucune catégorie. Appuyez sur le bouton « + » pour en créer une afin d'organiser votre bibliothèque.",
"add":"Ajouter",
"add_category":"Ajouter une catégorie",
"name":"Nom",
"category_name_required":"*obligatoire",
"add_category_error_exist":"Une catégorie avec ce nom existe déjà !",
"delete_category":"Effacer catégorie",
"delete_category_msg":"Souhaitez-vous supprimer la catégorie {name}?",
"rename_category":"Renommer la catégorie",
"general":"Général",
"general_subtitle":"Langue de l'application",
"app_language":"Langue de l'application",
"appearance":"Apparence",
"appearance_subtitle":"Thème, format de la date et de l'heure",
"theme":"Thème",
"dark_mode":"Mode sombre",
"on":"Activé",
"off":"Desactivé",
"pure_black_dark_mode":"Mode noir pur",
"timestamp":"Horodatage",
"relative_timestamp":"Horodatages relatifs",
"relative_timestamp_short":"Court (Aujourd'hui, Hier)",
"relative_timestamp_long":"Long (Court+, il y a n jours)",
"date_format":"Format de date",
"reader":"Lecteur",
"reader_subtitle":"Mode de lecture, affichage, navigation",
"default_reading_mode":"Mode de lecture par défaut",
"reading_mode_vertical":"Vertical",
"reading_mode_horizontal":"Horizontal",
"reading_mode_left_to_right":"De gauche à droite",
"reading_mode_right_to_left":"De droite à gauche",
"reading_mode_vertical_continuous":"Vertical continu",
"reading_mode_webtoon":"Webtoon",
"double_tap_animation_speed":"Vitesse d'animation du double-clic",
"normal":"Normale",
"fast":"Rapide",
"no_animation":"Sans animation",
"animate_page_transitions":"Toujours afficher la transition entre les chapitres",
"crop_borders":"Rogner les bordures",
"downloads":"Téléchargements",
"downloads_subtitle":"Paramètres de téléchargement",
"download_location":"Répertoire de téléchargement",
"custom_location":"Répertoire personnalisé",
"only_on_wifi":"Uniquement en Wi-Fi",
"save_as_cbz_archive":"Enregistrer comme archive CBZ",
"browse_subtitle":"Sources, extensions, recherche globale",
"only_include_pinned_sources":"Rechercher uniquement les sources épinglées dans la recherche globale",
"nsfw_sources":"Contenu +18",
"nsfw_sources_show":"Afficher dans les listes de sources et d'extensions",
"nsfw_sources_info":"Ceci n'empêche pas les extensions non officielles ou potentiellement mal signalées de diffuser du contenu +18 dans l'application.",
"version":"Version",
"check_for_update":"Rechercher des mises à jour",
"n_days_ago":"Il y a {days} jours",
"today":"Aujourd'hui",
"yesterday":"Hier",
"a_week_ago":"Il y a une semaine",
"add_to_library":"Ajouter à la bibliothèque",
"completed":"Terminé",
"ongoing":"En cours",
"on_hiatus":"En pause",
"canceled":"Annulé",
"publishing_finished":"Publication terminée",
"unknown":"Inconnue",
"set_categories":"Ajouter une catégorie",
"edit":"Modifier",
"in_library":"Dans la bibliothèque",
"filter_scanlator_groups":"Filtrer les groupes des traducteurs",
"reset":"Réinitialiser",
"by_source":"Par source",
"by_chapter_number":"Par numéro de chapitre",
"by_upload_date":"Par date de téléversement",
"source_title":"Titre de la source",
"chapter_number":"Numéro de chapitre",
"share":"Partager",
"n_chapters":"{number} chapitres",
"no_description":"Aucune description",
"resume":"Peprendre",
"read":"Coomencer",
"popular":"Populaire",
"refresh":"Actualiser",
"open_in_browser":"Ouvrir dans le navigateur",
"clear_cookie":"Effacer les cookies",
"show_page_number":"Afficher le numéro des pages",
"from_library":"De la bibliothèque",
"downloaded_chapter":"Chapitres téléchargés",
"page":"Page {page}",
"global_search":"Recherche globale",
"color_blend_level":"Niveau de mélange des couleurs",
"current":"En cours {char}",
"finished":"Terminé {char}",
"next":"Suivant {char}",
"previous":"Précédent {char}",
"no_more_chapter":"C'était le dernier chapitre",
"no_result":"Aucun résultat",
"send":"Envoyer",
"delete":"Supprimer",
"start_downloading":"Commencer à télécharger",
"retry":"Réessayer",
"add_chapters":"Ajouter des chapitres",
"delete_chapters":"Supprimer le chapitre ?",
"default0":"défaut",
"total_chapters":"Nombre de chapitres",
"import_archive_bd":"Importer des archives BD",
"import_archive_from_file":"fichier .cbz ou .zip",
"import_archive_from_folder":"à partir d'un dossier (comprenant fichier .cbz ou .zip)",
"nothing_read_recently":"Rien de lu recemment"
}

View file

@ -8,12 +8,14 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:intl/intl.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/providers/storage_provider.dart';
import 'package:mangayomi/router/router.dart';
import 'package:mangayomi/modules/more/settings/appearance/providers/blend_level_state_provider.dart';
import 'package:mangayomi/modules/more/settings/appearance/providers/flex_scheme_color_state_provider.dart';
import 'package:mangayomi/modules/more/settings/appearance/providers/pure_black_dark_mode_state_provider.dart';
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
late Isar isar;
@ -68,6 +70,7 @@ class _MyAppState extends ConsumerState<MyApp> {
final isDarkTheme = ref.watch(themeModeStateProvider);
final blendLevel = ref.watch(blendLevelStateProvider);
final pureBlackDarkMode = ref.watch(pureBlackDarkModeStateProvider);
final locale = ref.watch(l10nLocaleStateProvider);
ThemeData themeLight = FlexThemeData.light(
colors: ref.watch(flexSchemeColorStateProvider),
surfaceMode: FlexSurfaceMode.highScaffoldLevelSurface,
@ -111,6 +114,9 @@ class _MyAppState extends ConsumerState<MyApp> {
themeMode: isDarkTheme ? ThemeMode.dark : ThemeMode.light,
theme: themeLight,
debugShowCheckedModeBanner: false,
locale: locale,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
builder: BotToastInit(),
routeInformationParser: router.routeInformationParser,
routerDelegate: router.routerDelegate,
@ -119,3 +125,4 @@ class _MyAppState extends ConsumerState<MyApp> {
);
}
}

View file

@ -92,6 +92,8 @@ class Settings {
bool? cropBorders;
L10nLocale? locale;
Settings(
{this.id = 227,
this.displayType = DisplayType.compactGrid,
@ -209,3 +211,10 @@ class FilterScanlator {
int? mangaId;
List<String>? scanlators;
}
@embedded
class L10nLocale {
String? languageCode;
String? countryCode;
L10nLocale({this.languageCode,this.countryCode});
}

View file

@ -171,61 +171,67 @@ const SettingsSchema = CollectionSchema(
name: r'libraryShowNumbersOfItems',
type: IsarType.bool,
),
r'onlyIncludePinnedSources': PropertySchema(
r'locale': PropertySchema(
id: 29,
name: r'locale',
type: IsarType.object,
target: r'L10nLocale',
),
r'onlyIncludePinnedSources': PropertySchema(
id: 30,
name: r'onlyIncludePinnedSources',
type: IsarType.bool,
),
r'personalReaderModeList': PropertySchema(
id: 30,
id: 31,
name: r'personalReaderModeList',
type: IsarType.objectList,
target: r'PersonalReaderMode',
),
r'pureBlackDarkMode': PropertySchema(
id: 31,
id: 32,
name: r'pureBlackDarkMode',
type: IsarType.bool,
),
r'relativeTimesTamps': PropertySchema(
id: 32,
id: 33,
name: r'relativeTimesTamps',
type: IsarType.long,
),
r'saveAsCBZArchive': PropertySchema(
id: 33,
id: 34,
name: r'saveAsCBZArchive',
type: IsarType.bool,
),
r'showNSFW': PropertySchema(
id: 34,
id: 35,
name: r'showNSFW',
type: IsarType.bool,
),
r'showPagesNumber': PropertySchema(
id: 35,
id: 36,
name: r'showPagesNumber',
type: IsarType.bool,
),
r'sortChapterList': PropertySchema(
id: 36,
id: 37,
name: r'sortChapterList',
type: IsarType.objectList,
target: r'SortChapter',
),
r'sortLibraryManga': PropertySchema(
id: 37,
id: 38,
name: r'sortLibraryManga',
type: IsarType.object,
target: r'SortLibraryManga',
),
r'themeIsDark': PropertySchema(
id: 38,
id: 39,
name: r'themeIsDark',
type: IsarType.bool,
),
r'userAgent': PropertySchema(
id: 39,
id: 40,
name: r'userAgent',
type: IsarType.string,
)
@ -254,7 +260,8 @@ const SettingsSchema = CollectionSchema(
r'ChapterPageIndex': ChapterPageIndexSchema,
r'Cookie': CookieSchema,
r'PersonalReaderMode': PersonalReaderModeSchema,
r'FilterScanlator': FilterScanlatorSchema
r'FilterScanlator': FilterScanlatorSchema,
r'L10nLocale': L10nLocaleSchema
},
getId: _settingsGetId,
getLinks: _settingsGetLinks,
@ -377,6 +384,14 @@ int _settingsEstimateSize(
}
}
}
{
final value = object.locale;
if (value != null) {
bytesCount += 3 +
L10nLocaleSchema.estimateSize(
value, allOffsets[L10nLocale]!, allOffsets);
}
}
{
final list = object.personalReaderModeList;
if (list != null) {
@ -492,32 +507,38 @@ void _settingsSerialize(
writer.writeBool(offsets[26], object.libraryShowContinueReadingButton);
writer.writeBool(offsets[27], object.libraryShowLanguage);
writer.writeBool(offsets[28], object.libraryShowNumbersOfItems);
writer.writeBool(offsets[29], object.onlyIncludePinnedSources);
writer.writeObject<L10nLocale>(
offsets[29],
allOffsets,
L10nLocaleSchema.serialize,
object.locale,
);
writer.writeBool(offsets[30], object.onlyIncludePinnedSources);
writer.writeObjectList<PersonalReaderMode>(
offsets[30],
offsets[31],
allOffsets,
PersonalReaderModeSchema.serialize,
object.personalReaderModeList,
);
writer.writeBool(offsets[31], object.pureBlackDarkMode);
writer.writeLong(offsets[32], object.relativeTimesTamps);
writer.writeBool(offsets[33], object.saveAsCBZArchive);
writer.writeBool(offsets[34], object.showNSFW);
writer.writeBool(offsets[35], object.showPagesNumber);
writer.writeBool(offsets[32], object.pureBlackDarkMode);
writer.writeLong(offsets[33], object.relativeTimesTamps);
writer.writeBool(offsets[34], object.saveAsCBZArchive);
writer.writeBool(offsets[35], object.showNSFW);
writer.writeBool(offsets[36], object.showPagesNumber);
writer.writeObjectList<SortChapter>(
offsets[36],
offsets[37],
allOffsets,
SortChapterSchema.serialize,
object.sortChapterList,
);
writer.writeObject<SortLibraryManga>(
offsets[37],
offsets[38],
allOffsets,
SortLibraryMangaSchema.serialize,
object.sortLibraryManga,
);
writer.writeBool(offsets[38], object.themeIsDark);
writer.writeString(offsets[39], object.userAgent);
writer.writeBool(offsets[39], object.themeIsDark);
writer.writeString(offsets[40], object.userAgent);
}
Settings _settingsDeserialize(
@ -578,31 +599,31 @@ Settings _settingsDeserialize(
libraryShowContinueReadingButton: reader.readBoolOrNull(offsets[26]),
libraryShowLanguage: reader.readBoolOrNull(offsets[27]),
libraryShowNumbersOfItems: reader.readBoolOrNull(offsets[28]),
onlyIncludePinnedSources: reader.readBoolOrNull(offsets[29]),
onlyIncludePinnedSources: reader.readBoolOrNull(offsets[30]),
personalReaderModeList: reader.readObjectList<PersonalReaderMode>(
offsets[30],
offsets[31],
PersonalReaderModeSchema.deserialize,
allOffsets,
PersonalReaderMode(),
),
pureBlackDarkMode: reader.readBoolOrNull(offsets[31]),
relativeTimesTamps: reader.readLongOrNull(offsets[32]),
saveAsCBZArchive: reader.readBoolOrNull(offsets[33]),
showNSFW: reader.readBoolOrNull(offsets[34]),
showPagesNumber: reader.readBoolOrNull(offsets[35]),
pureBlackDarkMode: reader.readBoolOrNull(offsets[32]),
relativeTimesTamps: reader.readLongOrNull(offsets[33]),
saveAsCBZArchive: reader.readBoolOrNull(offsets[34]),
showNSFW: reader.readBoolOrNull(offsets[35]),
showPagesNumber: reader.readBoolOrNull(offsets[36]),
sortChapterList: reader.readObjectList<SortChapter>(
offsets[36],
offsets[37],
SortChapterSchema.deserialize,
allOffsets,
SortChapter(),
),
sortLibraryManga: reader.readObjectOrNull<SortLibraryManga>(
offsets[37],
offsets[38],
SortLibraryMangaSchema.deserialize,
allOffsets,
),
themeIsDark: reader.readBoolOrNull(offsets[38]),
userAgent: reader.readStringOrNull(offsets[39]),
themeIsDark: reader.readBoolOrNull(offsets[39]),
userAgent: reader.readStringOrNull(offsets[40]),
);
object.chapterFilterBookmarkedList =
reader.readObjectList<ChapterFilterBookmarked>(
@ -623,6 +644,11 @@ Settings _settingsDeserialize(
allOffsets,
FilterScanlator(),
);
object.locale = reader.readObjectOrNull<L10nLocale>(
offsets[29],
L10nLocaleSchema.deserialize,
allOffsets,
);
return object;
}
@ -730,40 +756,46 @@ P _settingsDeserializeProp<P>(
case 28:
return (reader.readBoolOrNull(offset)) as P;
case 29:
return (reader.readBoolOrNull(offset)) as P;
return (reader.readObjectOrNull<L10nLocale>(
offset,
L10nLocaleSchema.deserialize,
allOffsets,
)) as P;
case 30:
return (reader.readBoolOrNull(offset)) as P;
case 31:
return (reader.readObjectList<PersonalReaderMode>(
offset,
PersonalReaderModeSchema.deserialize,
allOffsets,
PersonalReaderMode(),
)) as P;
case 31:
return (reader.readBoolOrNull(offset)) as P;
case 32:
return (reader.readLongOrNull(offset)) as P;
case 33:
return (reader.readBoolOrNull(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;
case 36:
return (reader.readBoolOrNull(offset)) as P;
case 37:
return (reader.readObjectList<SortChapter>(
offset,
SortChapterSchema.deserialize,
allOffsets,
SortChapter(),
)) as P;
case 37:
case 38:
return (reader.readObjectOrNull<SortLibraryManga>(
offset,
SortLibraryMangaSchema.deserialize,
allOffsets,
)) as P;
case 38:
return (reader.readBoolOrNull(offset)) as P;
case 39:
return (reader.readBoolOrNull(offset)) as P;
case 40:
return (reader.readStringOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@ -2949,6 +2981,22 @@ extension SettingsQueryFilter
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> localeIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'locale',
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> localeIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'locale',
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
onlyIncludePinnedSourcesIsNull() {
return QueryBuilder.apply(this, (query) {
@ -3621,6 +3669,13 @@ extension SettingsQueryObject
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> locale(
FilterQuery<L10nLocale> q) {
return QueryBuilder.apply(this, (query) {
return query.object(q, r'locale');
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
personalReaderModeListElement(FilterQuery<PersonalReaderMode> q) {
return QueryBuilder.apply(this, (query) {
@ -4903,6 +4958,12 @@ extension SettingsQueryProperty
});
}
QueryBuilder<Settings, L10nLocale?, QQueryOperations> localeProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'locale');
});
}
QueryBuilder<Settings, bool?, QQueryOperations>
onlyIncludePinnedSourcesProperty() {
return QueryBuilder.apply(this, (query) {
@ -7736,3 +7797,401 @@ extension FilterScanlatorQueryFilter
extension FilterScanlatorQueryObject
on QueryBuilder<FilterScanlator, FilterScanlator, QFilterCondition> {}
// coverage:ignore-file
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
const L10nLocaleSchema = Schema(
name: r'L10nLocale',
id: -880412678425487799,
properties: {
r'countryCode': PropertySchema(
id: 0,
name: r'countryCode',
type: IsarType.string,
),
r'languageCode': PropertySchema(
id: 1,
name: r'languageCode',
type: IsarType.string,
)
},
estimateSize: _l10nLocaleEstimateSize,
serialize: _l10nLocaleSerialize,
deserialize: _l10nLocaleDeserialize,
deserializeProp: _l10nLocaleDeserializeProp,
);
int _l10nLocaleEstimateSize(
L10nLocale object,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
var bytesCount = offsets.last;
{
final value = object.countryCode;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
{
final value = object.languageCode;
if (value != null) {
bytesCount += 3 + value.length * 3;
}
}
return bytesCount;
}
void _l10nLocaleSerialize(
L10nLocale object,
IsarWriter writer,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
writer.writeString(offsets[0], object.countryCode);
writer.writeString(offsets[1], object.languageCode);
}
L10nLocale _l10nLocaleDeserialize(
Id id,
IsarReader reader,
List<int> offsets,
Map<Type, List<int>> allOffsets,
) {
final object = L10nLocale(
countryCode: reader.readStringOrNull(offsets[0]),
languageCode: reader.readStringOrNull(offsets[1]),
);
return object;
}
P _l10nLocaleDeserializeProp<P>(
IsarReader reader,
int propertyId,
int offset,
Map<Type, List<int>> allOffsets,
) {
switch (propertyId) {
case 0:
return (reader.readStringOrNull(offset)) as P;
case 1:
return (reader.readStringOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
}
}
extension L10nLocaleQueryFilter
on QueryBuilder<L10nLocale, L10nLocale, QFilterCondition> {
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'countryCode',
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'countryCode',
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeEqualTo(
String? value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'countryCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeGreaterThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'countryCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeLessThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'countryCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeBetween(
String? lower,
String? upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'countryCode',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'countryCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'countryCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeContains(String value, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'countryCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeMatches(String pattern, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'countryCode',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'countryCode',
value: '',
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
countryCodeIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'countryCode',
value: '',
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'languageCode',
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'languageCode',
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeEqualTo(
String? value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'languageCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeGreaterThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'languageCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeLessThan(
String? value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'languageCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeBetween(
String? lower,
String? upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'languageCode',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'languageCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'languageCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeContains(String value, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'languageCode',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeMatches(String pattern, {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'languageCode',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'languageCode',
value: '',
));
});
}
QueryBuilder<L10nLocale, L10nLocale, QAfterFilterCondition>
languageCodeIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'languageCode',
value: '',
));
});
}
}
extension L10nLocaleQueryObject
on QueryBuilder<L10nLocale, L10nLocale, QFilterCondition> {}

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/providers/storage_provider.dart';
import 'package:mangayomi/modules/browse/extension/extension_screen.dart';
import 'package:mangayomi/modules/browse/migrate_screen.dart';
@ -40,6 +41,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
bool _isSearch = false;
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
return DefaultTabController(
animationDuration: Duration.zero,
length: 3,
@ -48,7 +50,7 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
elevation: 0,
backgroundColor: Colors.transparent,
title: Text(
'Browse',
l10n.browse,
style: TextStyle(color: Theme.of(context).hintColor),
),
actions: [
@ -109,10 +111,10 @@ class _BrowseScreenState extends ConsumerState<BrowseScreen>
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
controller: _tabBarController,
tabs: const [
Tab(text: "Sources"),
Tab(text: "Extension"),
Tab(text: "Migrate"),
tabs: [
Tab(text: l10n.sources),
Tab(text: l10n.extensions),
Tab(text: l10n.migrate),
],
),
),

View file

@ -3,7 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/utils/lang.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/modules/browse/extension/widgets/extension_lang_list_tile_widget.dart';
class ExtensionsLang extends ConsumerWidget {
@ -11,11 +12,12 @@ class ExtensionsLang extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context)!;
final languages = languagesMap.entries.map((e) => e.value).toList();
languages.sort((a, b) => a.compareTo(b));
return Scaffold(
appBar: AppBar(
title: const Text("Extensions"),
title: Text(l10n.extensions),
),
body: StreamBuilder(
stream:
@ -31,14 +33,14 @@ class ExtensionsLang extends ConsumerWidget {
onChanged: (val) {
isar.writeTxnSync(() {
for (var source in entries) {
if (source.lang == lang) {
if (source.lang!.toLowerCase() == lang) {
isar.sources.putSync(source..isActive = val == true);
}
}
});
},
value: entries!
.where((element) => element.lang == lang)
.where((element) => element.lang!.toLowerCase() == lang)
.where((element) => element.isActive!)
.isNotEmpty,
);

View file

@ -5,7 +5,7 @@ import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/browse/extension/providers/fetch_sources.dart';
import 'package:mangayomi/utils/lang.dart';
import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/modules/browse/extension/widgets/extension_list_tile_widget.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
@ -45,7 +45,7 @@ class ExtensionScreen extends ConsumerWidget {
return GroupedListView<Source, String>(
elements: entries,
groupBy: (element) =>
completeLang(element.lang!.toLowerCase()),
completeLanguageName(element.lang!.toLowerCase()),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(left: 12),
child: Row(

View file

@ -6,7 +6,7 @@ part of 'fetch_sources.dart';
// RiverpodGenerator
// **************************************************************************
String _$fetchSourcesListHash() => r'5cb7bececf304fc891319051c39cbf4566127a14';
String _$fetchSourcesListHash() => r'151bfddc9daf2cde079bf0f98f523d92b7e6ab00';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -1,36 +0,0 @@
// import 'package:isar/isar.dart';
// import 'package:mangayomi/main.dart';
// import 'package:mangayomi/models/source.dart';
// import 'package:mangayomi/sources/source_list.dart';
// import 'package:riverpod_annotation/riverpod_annotation.dart';
// part 'refresh_source_list_data.g.dart';
// @riverpod
// refreshSourceListData(RefreshSourceListDataRef ref) {
// isar.writeTxnSync(() {
// for (var source in sourcesList) {
// final sourceF = isar.sources
// .filter()
// .nameEqualTo(source.name)
// .and()
// .langEqualTo(source.lang)
// .findAllSync();
// if (sourceF.isEmpty) {
// isar.sources.putSync(source);
// } else {
// isar.sources.putSync(sourceF.first
// ..apiUrl = source.apiUrl
// ..baseUrl = source.baseUrl
// ..dateFormat = source.dateFormat
// ..dateFormatLocale = source.dateFormatLocale
// ..hasCloudflare = source.hasCloudflare
// ..logoUrl = source.logoUrl
// ..typeSource = source.typeSource
// ..isFullData = source.isFullData
// ..lang = source.lang
// ..isNsfw = source.isNsfw
// ..name = source.name);
// }
// }
// });
// }

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:mangayomi/utils/lang.dart';
import 'package:mangayomi/utils/language.dart';
class ExtensionLangListTileWidget extends StatelessWidget {
final String lang;
@ -17,7 +17,7 @@ class ExtensionLangListTileWidget extends StatelessWidget {
onTap: () {
onChanged(!value);
},
title: Text(completeLang(lang.toLowerCase())),
title: Text(completeLanguageName(lang.toLowerCase())),
trailing: Switch(
value: value,
onChanged: (value) {

View file

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/browse/extension/providers/fetch_sources.dart';
import 'package:mangayomi/utils/lang.dart';
import 'package:mangayomi/utils/language.dart';
class ExtensionListTileWidget extends ConsumerStatefulWidget {
final Source source;
@ -63,7 +63,7 @@ class _ExtensionListTileWidgetState
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
completeLang(widget.source.lang!.toLowerCase()),
completeLanguageName(widget.source.lang!.toLowerCase()),
style: const TextStyle(fontWeight: FontWeight.w300, fontSize: 12),
),
if (widget.source.isNsfw!)

View file

@ -1,3 +1,5 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
@ -5,13 +7,14 @@ import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/eval/bridge_class/model.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/get_manga_detail.dart';
import 'package:mangayomi/services/search_manga.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/utils/cached_network.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/headers.dart';
import 'package:mangayomi/utils/lang.dart';
import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/modules/library/search_text_form_field.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
import 'package:mangayomi/modules/widgets/bottom_text_widget.dart';
@ -93,6 +96,7 @@ class SourceSearchScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context)!;
final search = ref.watch(searchMangaProvider(
source: source,
page: 1,
@ -115,7 +119,7 @@ class SourceSearchScreen extends ConsumerWidget {
},
title: Text(source.name!),
subtitle: Text(
completeLang(source.lang!),
completeLanguageName(source.lang!),
style: const TextStyle(fontSize: 10),
),
trailing: const Icon(Icons.arrow_forward_sharp),
@ -140,8 +144,8 @@ class SourceSearchScreen extends ConsumerWidget {
},
);
}
return const Center(
child: Text("No result"),
return Center(
child: Text(l10n.no_result),
);
}),
),
@ -176,7 +180,7 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
..lang = widget.source.lang
..source = widget.source.name,
source: widget.source));
final l10n = l10nLocalizations(context)!;
return getMangaDetail.when(
data: (data) {
return GestureDetector(
@ -190,7 +194,6 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
.langEqualTo(widget.source.lang)
.nameEqualTo(data.name)
.sourceEqualTo(data.source)
.favoriteEqualTo(true)
.watch(fireImmediately: true),
builder: (context, snapshot) {
return Padding(
@ -200,16 +203,27 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
SizedBox(
width: 100,
child: Column(children: [
ClipRRect(
borderRadius: BorderRadius.circular(2),
child: cachedNetworkImage(
headers: ref.watch(headersProvider(
source: data.source!, lang: data.lang!)),
imageUrl: data.imageUrl!,
width: 100,
height: 140,
fit: BoxFit.fill),
),
snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.customCoverImage != null
? Image.memory(snapshot
.data!.first.customCoverImage as Uint8List)
: ClipRRect(
borderRadius: BorderRadius.circular(2),
child: cachedNetworkImage(
headers: ref.watch(headersProvider(
source: data.source!,
lang: data.lang!)),
imageUrl: snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.imageUrl !=
null
? snapshot.data!.first.imageUrl!
: data.imageUrl!,
width: 100,
height: 140,
fit: BoxFit.fill),
),
BottomTextWidget(
fontSize: 12.0,
text: widget.manga.name!,
@ -221,11 +235,15 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
Container(
width: 100,
height: 140,
color: snapshot.hasData && snapshot.data!.isNotEmpty
color: snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.favorite
? Colors.black.withOpacity(0.7)
: null,
),
if (snapshot.hasData && snapshot.data!.isNotEmpty)
if (snapshot.hasData &&
snapshot.data!.isNotEmpty &&
snapshot.data!.first.favorite)
Positioned(
top: 0,
left: 0,
@ -235,11 +253,11 @@ class _MangaGlobalImageCardState extends ConsumerState<MangaGlobalImageCard>
decoration: BoxDecoration(
color: primaryColor(context),
borderRadius: BorderRadius.circular(5)),
child: const Padding(
padding: EdgeInsets.all(2),
child: Padding(
padding: const EdgeInsets.all(2),
child: Text(
"In library",
style: TextStyle(fontSize: 10),
l10n.in_library,
style: const TextStyle(fontSize: 10),
),
),
),

View file

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class MigrateScreen extends StatefulWidget {
const MigrateScreen({super.key});
@ -10,8 +11,9 @@ class MigrateScreen extends StatefulWidget {
class _MigrateScreenState extends State<MigrateScreen> {
@override
Widget build(BuildContext context) {
return const Center(
child: Text('Migrate'),
final l10n = l10nLocalizations(context)!;
return Center(
child: Text(l10n.migrate),
);
}
}

View file

@ -5,16 +5,18 @@ import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
import 'package:mangayomi/utils/lang.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/language.dart';
class SourcesFilterScreen extends ConsumerWidget {
const SourcesFilterScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context)!;
return Scaffold(
appBar: AppBar(
title: const Text("Sources"),
title: Text(l10n.sources),
),
body: Padding(
padding: const EdgeInsets.only(top: 10),
@ -40,12 +42,13 @@ class SourcesFilterScreen extends ConsumerWidget {
SwitchListTile(
value: entries
.where((element) =>
element.lang == groupByValue && element.isActive!)
element.lang!.toLowerCase() == groupByValue &&
element.isActive!)
.isNotEmpty,
onChanged: (val) {
isar.writeTxnSync(() {
for (var source in entries) {
if (source.lang == groupByValue) {
if (source.lang!.toLowerCase() == groupByValue) {
isar.sources
.putSync(source..isActive = val == true);
}
@ -53,15 +56,16 @@ class SourcesFilterScreen extends ConsumerWidget {
});
},
title: Text(
completeLang(groupByValue),
completeLanguageName(groupByValue),
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
),
),
itemBuilder: (context, Source element) {
if (entries
.where(
(ele) => ele.lang == element.lang && ele.isActive!)
.where((s) =>
s.lang!.toLowerCase() == element.lang &&
s.isActive!)
.isEmpty) {
return Container();
}

View file

@ -5,7 +5,8 @@ import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/browse/sources/widgets/source_list_tile.dart';
import 'package:mangayomi/utils/lang.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
class SourcesScreen extends ConsumerWidget {
@ -13,6 +14,7 @@ class SourcesScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context)!;
return Padding(
padding: const EdgeInsets.only(top: 10),
child: SingleChildScrollView(
@ -40,14 +42,13 @@ class SourcesScreen extends ConsumerWidget {
return GroupedListView<Source, String>(
elements: entries,
groupBy: (element) => "",
groupSeparatorBuilder: (String groupByValue) =>
const Padding(
padding: EdgeInsets.only(left: 12),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(left: 12),
child: Row(
children: [
Text(
"Last used",
style: TextStyle(
l10n.last_used,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
),
],
@ -88,14 +89,13 @@ class SourcesScreen extends ConsumerWidget {
return GroupedListView<Source, String>(
elements: entries,
groupBy: (element) => "",
groupSeparatorBuilder: (String groupByValue) =>
const Padding(
padding: EdgeInsets.only(left: 12),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(left: 12),
child: Row(
children: [
Text(
"Pinned",
style: TextStyle(
l10n.pinned,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13),
),
],
@ -126,7 +126,7 @@ class SourcesScreen extends ConsumerWidget {
.watch(fireImmediately: true),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(child: Text("Empty"));
return Center(child: Text(l10n.no_result));
}
final entries = snapshot.data!
.where((element) => ref.watch(showNSFWStateProvider)
@ -136,7 +136,7 @@ class SourcesScreen extends ConsumerWidget {
return GroupedListView<Source, String>(
elements: entries,
groupBy: (element) =>
completeLang(element.lang!.toLowerCase()),
completeLanguageName(element.lang!.toLowerCase()),
groupSeparatorBuilder: (String groupByValue) => Padding(
padding: const EdgeInsets.only(left: 12),
child: Row(

View file

@ -4,7 +4,7 @@ import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/lang.dart';
import 'package:mangayomi/utils/language.dart';
class SourceListTile extends StatelessWidget {
final Source source;
@ -55,7 +55,7 @@ class SourceListTile extends StatelessWidget {
subtitle: Row(
children: [
Text(
completeLang(source.lang!.toLowerCase()),
completeLanguageName(source.lang!.toLowerCase()),
style: const TextStyle(fontWeight: FontWeight.w300, fontSize: 12),
),
if (source.isNsfw!)

View file

@ -7,6 +7,7 @@ import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/history.dart';
import 'package:mangayomi/modules/history/providers/isar_providers.dart';
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/cached_network.dart';
import 'package:mangayomi/utils/date.dart';
import 'package:mangayomi/utils/headers.dart';
@ -27,6 +28,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
List<History> entriesData = [];
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
final history = ref.watch(getAllHistoryStreamProvider);
return Scaffold(
appBar: AppBar(
@ -35,7 +37,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
title: _isSearch
? null
: Text(
'History',
l10n.history,
style: TextStyle(color: Theme.of(context).hintColor),
),
actions: [
@ -72,11 +74,10 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"Remove everything",
title: Text(
l10n.remove_everything,
),
content: const Text(
'Are you sure? All history will be lost.'),
content: Text(l10n.remove_everything_msg),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
@ -85,7 +86,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
onPressed: () {
Navigator.pop(context);
},
child: const Text("Cancel")),
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
@ -98,7 +99,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
Navigator.pop(context);
}
},
child: const Text("Ok")),
child: Text(l10n.ok)),
],
)
],
@ -123,6 +124,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
return GroupedListView<History, String>(
elements: entries,
groupBy: (element) => dateFormat(element.date!,
context: context,
ref: ref,
forHistoryValue: true,
useRelativeTimesTamps: false),
@ -132,6 +134,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
children: [
Text(dateFormat(
null,
context: context,
stringDate: groupByValue,
ref: ref,
)),
@ -228,7 +231,7 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
),
),
Text(
" - ${dateFormatHour(element.date!)}",
" - ${dateFormatHour(element.date!, context)}",
style: TextStyle(
fontSize: 11,
color: Theme.of(context)
@ -251,11 +254,11 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"Remove",
title: Text(
l10n.remove,
),
content: const Text(
'This will remove the read date of this chapter. Are you sure?'),
content: Text(
l10n.remove_history_msg),
actions: [
Row(
mainAxisAlignment:
@ -266,8 +269,8 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
Navigator.pop(
context);
},
child: const Text(
"Cancel")),
child: Text(
l10n.cancel)),
const SizedBox(
width: 15,
),
@ -286,8 +289,8 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
context);
}
},
child: const Text(
"Remove")),
child: Text(
l10n.remove)),
],
)
],
@ -316,8 +319,8 @@ class _HistoryScreenState extends ConsumerState<HistoryScreen> {
order: GroupedListOrder.DESC,
);
}
return const Center(
child: Text('Nothing read recently'),
return Center(
child: Text(l10n.nothing_read_recently),
);
},
error: (Object error, StackTrace stackTrace) {

View file

@ -15,6 +15,7 @@ import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/modules/library/providers/local_archive.dart';
import 'package:mangayomi/modules/widgets/manga_image_card_widget.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/providers/storage_provider.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/media_query.dart';
@ -51,7 +52,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
ref.watch(getAllMangaWithoutCategoriesStreamProvider);
final showCategoryTabs = ref.watch(libraryShowCategoryTabsStateProvider);
final mangaAll = ref.watch(getAllMangaStreamProvider(categoryId: null));
final l10n = l10nLocalizations(context)!;
return Scaffold(
body: mangaAll.when(
data: (man) {
@ -107,7 +108,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
final sortType = ref
.watch(sortLibraryMangaStateProvider)
.index as int;
final numberOfItemsList = _filterAndSortMangas(
final numberOfItemsList = _filterAndSortManga(
data: man,
downloadFilterType: downloadFilterType,
unreadFilterType: unreadFilterType,
@ -115,7 +116,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
bookmarkedFilterType: bookmarkedFilterType,
sortType: sortType);
final withoutCategoryNumberOfItemsList =
_filterAndSortMangas(
_filterAndSortManga(
data: withoutCategory,
downloadFilterType: downloadFilterType,
unreadFilterType: unreadFilterType,
@ -154,7 +155,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
children: [
Tab(
text: i == 0
? "Default"
? l10n.default0
: entr[i - 1].name),
const SizedBox(
width: 4,
@ -329,7 +330,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
mangaList: _entries));
final sortType =
ref.watch(sortLibraryMangaStateProvider).index;
final numberOfItemsList = _filterAndSortMangas(
final numberOfItemsList = _filterAndSortManga(
data: man,
downloadFilterType: downloadFilterType,
unreadFilterType: unreadFilterType,
@ -513,7 +514,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
final sortType = ref.watch(sortLibraryMangaStateProvider).index;
return mangas.when(
data: (data) {
final categoriNumberOfItemsList = _filterAndSortMangas(
final categoriNumberOfItemsList = _filterAndSortManga(
data: data,
downloadFilterType: downloadFilterType,
unreadFilterType: unreadFilterType,
@ -553,13 +554,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required bool language,
required WidgetRef ref,
required DisplayType displayType}) {
final l10n = l10nLocalizations(context)!;
final mangas = ref.watch(getAllMangaStreamProvider(categoryId: categoryId));
final sortType = ref.watch(sortLibraryMangaStateProvider).index;
final mangaIdsList = ref.watch(mangasListStateProvider);
return Scaffold(
body: mangas.when(
data: (data) {
final entries = _filterAndSortMangas(
final entries = _filterAndSortManga(
data: data,
downloadFilterType: downloadFilterType,
unreadFilterType: unreadFilterType,
@ -590,7 +592,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
localSource: localSource,
);
}
return const Center(child: Text("Empty Library"));
return Center(child: Text(l10n.empty_library));
},
error: (Object error, StackTrace stackTrace) {
return ErrorText(error);
@ -619,9 +621,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
? ref.watch(getAllMangaWithoutCategoriesStreamProvider)
: ref.watch(getAllMangaStreamProvider(categoryId: null));
final mangaIdsList = ref.watch(mangasListStateProvider);
final l10n = l10nLocalizations(context)!;
return manga.when(
data: (data) {
final entries = _filterAndSortMangas(
final entries = _filterAndSortManga(
data: data,
downloadFilterType: downloadFilterType,
unreadFilterType: unreadFilterType,
@ -652,7 +655,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
localSource: localSource,
);
}
return const Center(child: Text("Empty Library"));
return Center(child: Text(l10n.empty_library));
},
error: (Object error, StackTrace stackTrace) {
return ErrorText(error);
@ -663,7 +666,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
);
}
List<Manga> _filterAndSortMangas(
List<Manga> _filterAndSortManga(
{required List<Manga> data,
required int downloadFilterType,
required int unreadFilterType,
@ -812,6 +815,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
builder: (context) {
return Consumer(builder: (context, ref, child) {
final mangaIdsList = ref.watch(mangasListStateProvider);
final l10n = l10nLocalizations(context)!;
final List<Manga> mangasList = [];
for (var id in mangaIdsList) {
mangasList.add(isar.mangas.getSync(id)!);
@ -819,8 +823,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: const Text(
"Set categories",
title: Text(
l10n.set_categories,
),
content: SizedBox(
width: mediaWidth(context, 0.8),
@ -871,14 +875,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
context.push("/categories");
Navigator.pop(context);
},
child: const Text("Edit")),
child: Text(l10n.edit)),
Row(
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("Cancel")),
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
@ -902,8 +906,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
Navigator.pop(context);
}
},
child: const Text(
"OK",
child: Text(
l10n.ok,
)),
],
),
@ -925,6 +929,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
builder: (context) {
return Consumer(builder: (context, ref, child) {
final mangaIdsList = ref.watch(mangasListStateProvider);
final l10n = l10nLocalizations(context)!;
final List<Manga> mangasList = [];
for (var id in mangaIdsList) {
mangasList.add(isar.mangas.getSync(id)!);
@ -932,8 +937,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: const Text(
"Remove",
title: Text(
l10n.remove,
),
content: SizedBox(
height: 100,
@ -941,7 +946,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
child: Column(
children: [
ListTileChapterFilter(
label: "From library",
label: l10n.from_library,
onTap: () {
setState(() {
if (fromLibList == mangaIdsList) {
@ -954,7 +959,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
type: fromLibList.isNotEmpty ? 1 : 0,
),
ListTileChapterFilter(
label: "Downloaded chapters",
label: l10n.downloaded_chapters,
onTap: () {
setState(() {
if (downloadedChapsList == mangaIdsList) {
@ -976,7 +981,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
onPressed: () {
Navigator.pop(context);
},
child: const Text("Cancel")),
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
@ -1055,8 +1060,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
Navigator.pop(context);
}
},
child: const Text(
"OK",
child: Text(
l10n.ok,
)),
],
),
@ -1071,6 +1076,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
_showDraggableMenu() {
late TabController tabBarController;
tabBarController = TabController(length: 3, vsync: this);
final l10n = l10nLocalizations(context)!;
DraggableMenu.open(
context,
DraggableMenu(
@ -1091,10 +1097,10 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
children: [
TabBar(
controller: tabBarController,
tabs: const [
Tab(text: "Filter"),
Tab(text: "Sort"),
Tab(text: "Display"),
tabs: [
Tab(text: l10n.filter),
Tab(text: l10n.sort),
Tab(text: l10n.display),
],
),
Flexible(
@ -1105,7 +1111,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
return Column(
children: [
ListTileChapterFilter(
label: "Downloaded",
label: l10n.downloaded,
type: ref.watch(
mangaFilterDownloadedStateProvider(
mangaList: _entries)),
@ -1118,7 +1124,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.update();
}),
ListTileChapterFilter(
label: "Unread",
label: l10n.unread,
type: ref.watch(
mangaFilterUnreadStateProvider(
mangaList: _entries)),
@ -1131,7 +1137,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.update();
}),
ListTileChapterFilter(
label: "Started",
label: l10n.started,
type: ref.watch(
mangaFilterStartedStateProvider(
mangaList: _entries)),
@ -1144,7 +1150,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.update();
}),
ListTileChapterFilter(
label: "Bookmarked",
label: l10n.bookmarked,
type: ref.watch(
mangaFilterBookmarkedStateProvider(
mangaList: _entries)),
@ -1173,7 +1179,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
children: [
for (var i = 0; i < 7; i++)
ListTileChapterSort(
label: _getSortNameByIndex(i),
label:
_getSortNameByIndex(i, context),
reverse: reverse,
onTap: () {
ref
@ -1210,12 +1217,12 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
const NeverScrollableScrollPhysics(),
child: Column(
children: [
const Padding(
padding: EdgeInsets.only(
Padding(
padding: const EdgeInsets.only(
left: 20, top: 10),
child: Row(
children: [
Text("Display mode"),
Text(l10n.display_mode),
],
),
),
@ -1227,7 +1234,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
title: Text(
displayV
.getLibraryDisplayTypeName(
e.name),
e.name, context),
style: TextStyle(
color:
Theme.of(context)
@ -1249,12 +1256,12 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
),
)
.toList()),
const Padding(
padding: EdgeInsets.only(
Padding(
padding: const EdgeInsets.only(
left: 20, top: 10),
child: Row(
children: [
Text("Badges"),
Text(l10n.badges),
],
),
),
@ -1264,7 +1271,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
child: Column(
children: [
ListTileChapterFilter(
label: "Downloaded chapters",
label:
l10n.downloaded_chapters,
type:
downloadedChapter ? 1 : 0,
onTap: () {
@ -1276,7 +1284,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
!downloadedChapter);
}),
ListTileChapterFilter(
label: "Language",
label: l10n.language,
type: language ? 1 : 0,
onTap: () {
ref
@ -1286,7 +1294,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.set(!language);
}),
ListTileChapterFilter(
label: "Local source",
label: l10n.local_source,
type: localSource ? 1 : 0,
onTap: () {
ref
@ -1298,12 +1306,12 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
],
),
),
const Padding(
padding: EdgeInsets.only(
Padding(
padding: const EdgeInsets.only(
left: 20, top: 10),
child: Row(
children: [
Text("Tabs"),
Text(l10n.tabs),
],
),
),
@ -1313,7 +1321,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
child: Column(
children: [
ListTileChapterFilter(
label: "Show category tabs",
label:
l10n.show_category_tabs,
type:
showCategoryTabs ? 1 : 0,
onTap: () {
@ -1324,8 +1333,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.set(!showCategoryTabs);
}),
ListTileChapterFilter(
label:
"Show numbers of items",
label: l10n
.show_numbers_of_items,
type: showNumbersOfItems
? 1
: 0,
@ -1340,12 +1349,12 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
],
),
),
const Padding(
padding: EdgeInsets.only(
Padding(
padding: const EdgeInsets.only(
left: 20, top: 10),
child: Row(
children: [
Text("Others"),
Text(l10n.other),
],
),
),
@ -1355,8 +1364,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
child: Column(
children: [
ListTileChapterFilter(
label:
"Show continue reading button",
label: l10n
.show_continue_reading_buttons,
type:
continueReaderBtn ? 1 : 0,
onTap: () {
@ -1382,21 +1391,22 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
))));
}
String _getSortNameByIndex(int index) {
String _getSortNameByIndex(int index, BuildContext context) {
final l10n = l10nLocalizations(context)!;
if (index == 0) {
return "AlphabeticalLy";
return l10n.alphabetically;
} else if (index == 1) {
return "Last read";
return l10n.last_read;
} else if (index == 2) {
return "Last update check";
return l10n.last_update_check;
} else if (index == 3) {
return "Unread count";
return l10n.unread_count;
} else if (index == 4) {
return "Total chapters";
return l10n.total_chapters;
} else if (index == 5) {
return "Latest chapter";
return l10n.latest_chapter;
}
return "Date added";
return l10n.date_added;
}
PreferredSize _appBar(
@ -1412,7 +1422,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
final manga = categoryId == null
? ref.watch(getAllMangaWithoutCategoriesStreamProvider)
: ref.watch(getAllMangaStreamProvider(categoryId: categoryId));
final l10n = l10nLocalizations(context)!;
return PreferredSize(
preferredSize: Size.fromHeight(AppBar().preferredSize.height),
child: isLongPressed
@ -1480,7 +1490,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
: Row(
children: [
Text(
'Library',
l10n.library,
style:
TextStyle(color: Theme.of(context).hintColor),
),
@ -1546,9 +1556,9 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
)),
PopupMenuButton(itemBuilder: (context) {
return [
const PopupMenuItem<int>(
value: 0, child: Text("Open random entry")),
const PopupMenuItem<int>(value: 1, child: Text("Import")),
PopupMenuItem<int>(
value: 0, child: Text(l10n.open_random_entry)),
PopupMenuItem<int>(value: 1, child: Text(l10n.import)),
];
}, onSelected: (value) {
if (value == 0) {
@ -1572,13 +1582,14 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
}
_importArchiveBD(BuildContext context) {
final l10n = l10nLocalizations(context)!;
bool isLoading = false;
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"Import Archive BD",
title: Text(
l10n.import_archive_bd,
),
content: StatefulBuilder(
builder: (context, setState) {
@ -1614,7 +1625,7 @@ _importArchiveBD(BuildContext context) {
MainAxisAlignment.spaceEvenly,
children: [
const Icon(Icons.archive_outlined),
Text(".cbz or .zip files",
Text(l10n.import_archive_from_file,
style: TextStyle(
color: Theme.of(context)
.textTheme
@ -1645,7 +1656,7 @@ _importArchiveBD(BuildContext context) {
children: [
const Icon(Icons.folder),
Text(
"From folder (.cbz or .zip files) ",
l10n.import_archive_from_folder,
style: TextStyle(
color: Theme.of(context)
.textTheme
@ -1692,7 +1703,7 @@ _importArchiveBD(BuildContext context) {
onPressed: () {
Navigator.pop(context);
},
child: const Text("Cancel")),
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),

View file

@ -1,7 +1,9 @@
import 'package:flutter/material.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'library_state_provider.g.dart';
@ -22,14 +24,15 @@ class LibraryDisplayTypeState extends _$LibraryDisplayTypeState {
: DisplayType.coverOnlyGrid;
}
String getLibraryDisplayTypeName(String displayType) {
String getLibraryDisplayTypeName(String displayType, BuildContext context) {
final l10n = l10nLocalizations(context)!;
return displayType == DisplayType.compactGrid.name
? 'Compact grid'
? l10n.compact_grid
: displayType == DisplayType.list.name
? 'List'
? l10n.list
: displayType == DisplayType.comfortableGrid.name
? 'Comfortable grid'
: 'Cover-only grid';
? l10n.comfortable_grid
: l10n.cover_only_grid;
}
void setLibraryDisplayType(DisplayType displayType) {

View file

@ -7,7 +7,7 @@ part of 'library_state_provider.dart';
// **************************************************************************
String _$libraryDisplayTypeStateHash() =>
r'7686533c6ece9f6aa5fbcbc70854ffeae16c33f8';
r'fae6a2a9b18910c9d8843e74b5fe7e7e2fbec6f1';
/// See also [LibraryDisplayTypeState].
@ProviderFor(LibraryDisplayTypeState)

View file

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class SeachFormTextField extends StatelessWidget {
final Function(String)? onChanged;
@ -16,6 +17,7 @@ class SeachFormTextField extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
return Flexible(
child: TextFormField(
autofocus: true,
@ -25,7 +27,7 @@ class SeachFormTextField extends StatelessWidget {
onFieldSubmitted: onFieldSubmitted,
decoration: InputDecoration(
isDense: true,
hintText: 'Search...',
hintText: l10n.search,
filled: true,
fillColor: Colors.transparent,
prefixIcon: IconButton(

View file

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/media_query.dart';
import 'package:mangayomi/modules/library/providers/library_state_provider.dart';
@ -21,6 +22,7 @@ class MainScreen extends StatefulWidget {
class _MainScreenState extends State<MainScreen> {
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
final route = GoRouter.of(context);
int currentIndex = route.location == '/library'
? 0
@ -54,7 +56,7 @@ class _MainScreenState extends State<MainScreen> {
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Incognito mode',
l10n.incognito_mode,
style: TextStyle(
color: Colors.white,
fontFamily: GoogleFonts.aBeeZee().fontFamily,
@ -93,59 +95,59 @@ class _MainScreenState extends State<MainScreen> {
child: NavigationRail(
labelType: NavigationRailLabelType.all,
useIndicator: true,
destinations: const [
destinations: [
NavigationRailDestination(
selectedIcon: Icon(
selectedIcon: const Icon(
Icons.collections_bookmark,
),
icon: Icon(
icon: const Icon(
Icons.collections_bookmark_outlined,
),
label: Padding(
padding: EdgeInsets.only(top: 5),
child: Text('Library'))),
padding: const EdgeInsets.only(top: 5),
child: Text(l10n.library))),
NavigationRailDestination(
selectedIcon: Icon(
selectedIcon: const Icon(
Icons.new_releases,
),
icon: Icon(
icon: const Icon(
Icons.new_releases_outlined,
),
label: Padding(
padding: EdgeInsets.only(top: 5),
child: Text('Updates'))),
padding: const EdgeInsets.only(top: 5),
child: Text(l10n.updates))),
NavigationRailDestination(
selectedIcon: Icon(
selectedIcon: const Icon(
Icons.history,
),
icon: Icon(
icon: const Icon(
Icons.history_outlined,
),
label: Padding(
padding: EdgeInsets.only(top: 5),
child: Text("History"),
padding: const EdgeInsets.only(top: 5),
child: Text(l10n.history),
)),
NavigationRailDestination(
selectedIcon: Icon(
selectedIcon: const Icon(
Icons.explore,
),
icon: Icon(
icon: const Icon(
Icons.explore_outlined,
),
label: Padding(
padding: EdgeInsets.only(top: 5),
child: Text("Browse"),
padding: const EdgeInsets.only(top: 5),
child: Text(l10n.browse),
)),
NavigationRailDestination(
selectedIcon: Icon(
selectedIcon: const Icon(
Icons.more_horiz,
),
icon: Icon(
icon: const Icon(
Icons.more_horiz_outlined,
),
label: Padding(
padding: EdgeInsets.only(top: 5),
child: Text("More"),
padding: const EdgeInsets.only(top: 5),
child: Text(l10n.more),
)),
],
selectedIndex: currentIndex,
@ -201,47 +203,47 @@ class _MainScreenState extends State<MainScreen> {
child: NavigationBar(
animationDuration: const Duration(milliseconds: 500),
selectedIndex: currentIndex,
destinations: const [
destinations: [
NavigationDestination(
selectedIcon: Icon(
selectedIcon: const Icon(
Icons.collections_bookmark,
),
icon: Icon(
icon: const Icon(
Icons.collections_bookmark_outlined,
),
label: 'Library'),
label: l10n.library),
NavigationDestination(
selectedIcon: Icon(
selectedIcon: const Icon(
Icons.new_releases,
),
icon: Icon(
icon: const Icon(
Icons.new_releases_outlined,
),
label: 'Updates'),
label: l10n.updates),
NavigationDestination(
selectedIcon: Icon(
selectedIcon: const Icon(
Icons.history,
),
icon: Icon(
icon: const Icon(
Icons.history_outlined,
),
label: "History"),
label: l10n.history),
NavigationDestination(
selectedIcon: Icon(
selectedIcon: const Icon(
Icons.explore,
),
icon: Icon(
icon: const Icon(
Icons.explore_outlined,
),
label: "Browse"),
label: l10n.browse),
NavigationDestination(
selectedIcon: Icon(
selectedIcon: const Icon(
Icons.more_horiz,
),
icon: Icon(
icon: const Icon(
Icons.more_horiz_outlined,
),
label: "More"),
label: l10n.more),
],
onDestinationSelected: (newIndex) {
if (mounted) {

View file

@ -14,6 +14,7 @@ import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/download.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/modules/library/providers/local_archive.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/sources/utils/utils.dart';
import 'package:mangayomi/utils/cached_network.dart';
import 'package:mangayomi/utils/colors.dart';
@ -257,6 +258,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
preferredSize: Size.fromHeight(AppBar().preferredSize.height),
child: Consumer(
builder: (context, ref, child) {
final l10n = l10nLocalizations(context)!;
final isNotFiltering = ref.watch(
chapterFilterResultStateProvider(manga: widget.manga!));
final isLongPressed = ref.watch(isLongPressedStateProvider);
@ -350,16 +352,16 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
PopupMenuButton(itemBuilder: (context) {
return [
if (widget.manga!.favorite)
const PopupMenuItem<int>(
PopupMenuItem<int>(
value: 0,
child: Text("Edit categories")),
child: Text(l10n.edit_categories)),
if (!isLocalArchive)
if (widget.manga!.favorite)
const PopupMenuItem<int>(
value: 1, child: Text("Migrate")),
PopupMenuItem<int>(
value: 1, child: Text(l10n.migrate)),
if (!isLocalArchive)
const PopupMenuItem<int>(
value: 2, child: Text("Share")),
PopupMenuItem<int>(
value: 2, child: Text(l10n.share)),
];
}, onSelected: (value) {
if (value == 0) {
@ -415,6 +417,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
padding: const EdgeInsets.only(top: 0, bottom: 60),
itemCount: chapters.length + 1,
itemBuilder: (context, index) {
final l10n = l10nLocalizations(context)!;
int finalIndex = index - 1;
if (index == 0) {
return isTablet(context)
@ -439,7 +442,8 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
.symmetric(
horizontal: 8),
child: Text(
'${chapters.length} chapters',
l10n.n_chapters(
chapters.length),
style: const TextStyle(
fontWeight:
FontWeight.bold),
@ -461,7 +465,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
color: secondaryColor(
context)),
label: Text(
'Add chapters',
l10n.add_chapters,
style: TextStyle(
fontWeight:
FontWeight.bold,
@ -505,7 +509,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
chap.isNotEmpty && chap.first.isBookmarked! && getLength1;
bool checkReadBookmarked =
chap.isNotEmpty && chap.first.isRead! && getLength1;
final l10n = l10nLocalizations(context)!;
return AnimatedContainer(
curve: Curves.easeIn,
decoration: BoxDecoration(
@ -699,8 +703,8 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"Delete chapters ?",
title: Text(
l10n.delete_chapters,
),
actions: [
Row(
@ -711,7 +715,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
onPressed: () {
Navigator.pop(context);
},
child: const Text("Cancel")),
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
@ -740,7 +744,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
Navigator.pop(context);
}
},
child: const Text("Delete")),
child: Text(l10n.delete)),
],
)
],
@ -773,7 +777,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
Consumer(builder: (context, ref, child) {
final scanlators =
ref.watch(scanlatorsFilterStateProvider(widget.manga!));
final l10n = l10nLocalizations(context)!;
return DraggableMenu(
ui: ClassicDraggableMenu(barItem: Container(), radius: 20),
expandable: false,
@ -792,10 +796,10 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
children: [
TabBar(
controller: tabBarController,
tabs: const [
Tab(text: "Filter"),
Tab(text: "Sort"),
Tab(text: "Display"),
tabs: [
Tab(text: l10n.filter),
Tab(text: l10n.sort),
Tab(text: l10n.display),
],
),
Flexible(
@ -807,7 +811,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
children: [
if (!isLocalArchive)
ListTileChapterFilter(
label: "Downloaded",
label: l10n.downloaded,
type: ref.watch(
chapterFilterDownloadedStateProvider(
mangaId: widget.manga!.id!)),
@ -821,7 +825,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
.update();
}),
ListTileChapterFilter(
label: "Unread",
label: l10n.unread,
type: ref.watch(
chapterFilterUnreadStateProvider(
mangaId: widget.manga!.id!)),
@ -835,7 +839,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
.update();
}),
ListTileChapterFilter(
label: "Bookmarked",
label: l10n.bookmarked,
type: ref.watch(
chapterFilterBookmarkedStateProvider(
mangaId: widget.manga!.id!)),
@ -869,8 +873,8 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
widget
.manga!));
return AlertDialog(
title: const Text(
"Filter scanlator groups",
title: Text(
l10n.filter_scanlator_groups,
),
content: SizedBox(
width:
@ -915,7 +919,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
Navigator.pop(context);
},
child: Text(
"Reset",
l10n.reset,
style: TextStyle(color: primaryColor(context)),
)),
],
@ -930,7 +934,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
Navigator.pop(context);
},
child: Text(
"Cancel",
l10n.cancel,
style: TextStyle(color: primaryColor(context)),
)),
TextButton(
@ -939,7 +943,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
Navigator.pop(context);
},
child: Text(
"Filter",
l10n.filter,
style: TextStyle(color: primaryColor(context)),
)),
],
@ -953,8 +957,8 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
});
});
},
child: const Text(
"Filter scanlator groups")),
child: Text(l10n
.filter_scanlator_groups)),
),
],
),
@ -975,7 +979,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
children: [
for (var i = 0; i < 3; i++)
ListTileChapterSort(
label: _getSortNameByIndex(i),
label: _getSortNameByIndex(i, context),
reverse: reverse,
onTap: () {
ref
@ -995,7 +999,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
children: [
RadioListTile(
dense: true,
title: const Text("Source title"),
title: Text(l10n.source_title),
value: "e",
groupValue: "e",
selected: true,
@ -1003,7 +1007,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
),
RadioListTile(
dense: true,
title: const Text("Chapter number"),
title: Text(l10n.chapter_number),
value: "ej",
groupValue: "e",
selected: false,
@ -1024,16 +1028,18 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
);
}
String _getSortNameByIndex(int index) {
String _getSortNameByIndex(int index, BuildContext context) {
final l10n = l10nLocalizations(context)!;
if (index == 0) {
return "By source";
return l10n.by_source;
} else if (index == 1) {
return "By chapter number";
return l10n.by_chapter_number;
}
return "By upload date";
return l10n.by_upload_date;
}
Widget _bodyContainer({required int chapterLength}) {
final l10n = l10nLocalizations(context)!;
return Stack(
children: [
Container(
@ -1185,7 +1191,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
padding:
const EdgeInsets.symmetric(horizontal: 8),
child: Text(
'$chapterLength chapters',
l10n.n_chapters(chapterLength),
style: const TextStyle(
fontWeight: FontWeight.bold),
),
@ -1200,7 +1206,7 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
icon: Icon(Icons.add,
color: secondaryColor(context)),
label: Text(
'Add chapters',
l10n.add_chapters,
style: TextStyle(
fontWeight: FontWeight.bold,
color: secondaryColor(context)),

View file

@ -8,6 +8,7 @@ import 'package:mangayomi/modules/history/providers/isar_providers.dart';
import 'package:mangayomi/modules/manga/detail/widgets/custom_floating_action_btn.dart';
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/constant.dart';
import 'package:mangayomi/utils/media_query.dart';
@ -32,6 +33,7 @@ class MangaDetailsView extends ConsumerStatefulWidget {
class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
bool? isLocalArchive = widget.manga.isLocalArchive ?? false;
return Scaffold(
floatingActionButton: Consumer(
@ -57,7 +59,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
if (entries.isNotEmpty && !incognitoMode) {
return CustomFloatingActionBtn(
isExtended: !isExtended,
label: 'Resume',
label: l10n.resume,
onPressed: () {
pushMangaReaderView(
context: context,
@ -70,7 +72,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
}
return CustomFloatingActionBtn(
isExtended: !isExtended,
label: 'Read',
label: l10n.read,
onPressed: () {
pushMangaReaderView(
context: context,
@ -110,7 +112,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
const SizedBox(
width: 4,
),
Text(getMangaStatusName(widget.manga.status)),
Text(getMangaStatusName(widget.manga.status, context)),
const Text(''),
Text(widget.manga.source!),
Text(' (${widget.manga.lang!.toUpperCase()})')
@ -134,18 +136,19 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
isar.mangas.putSync(model);
});
},
child: const Column(
child: Column(
children: [
Icon(
const Icon(
Icons.favorite,
size: 22,
),
SizedBox(
const SizedBox(
height: 4,
),
Text(
'In library',
style: TextStyle(fontSize: 13),
l10n.in_library,
style: const TextStyle(fontSize: 13),
textAlign: TextAlign.center,
)
],
),
@ -183,7 +186,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
height: 4,
),
Text(
'Add to library',
l10n.add_to_library,
style: TextStyle(
color: secondaryColor(context), fontSize: 13),
)
@ -206,9 +209,10 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
final l10n = l10nLocalizations(context)!;
return AlertDialog(
title: const Text(
"Set categories",
title: Text(
l10n.set_categories,
),
content: SizedBox(
width: mediaWidth(context, 0.8),
@ -255,14 +259,14 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
context.push("/categories");
Navigator.pop(context);
},
child: const Text("Edit")),
child: Text(l10n.edit)),
Row(
children: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("Cancel")),
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
@ -280,8 +284,8 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
Navigator.pop(context);
}
},
child: const Text(
"OK",
child: Text(
l10n.ok,
)),
],
),

View file

@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$updateMangaDetailHash() => r'80479a109b0beb0e0d57d93a32a587bbf41d5bc0';
String _$updateMangaDetailHash() => r'7c8e4cae20be71b2cab42f7d784888fb4037aa00';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/date.dart';
import 'package:mangayomi/modules/manga/reader/providers/push_router.dart';
import 'package:mangayomi/utils/colors.dart';
@ -20,7 +21,7 @@ class ChapterListTileWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final isLongPressed = ref.watch(isLongPressedStateProvider);
final l10n = l10nLocalizations(context)!;
return Container(
color: chapterList.contains(chapter)
? primaryColor(context).withOpacity(0.4)
@ -73,7 +74,7 @@ class ChapterListTileWidget extends ConsumerWidget {
children: [
if ((chapter.manga.value!.isLocalArchive ?? false) == false)
Text(
dateFormat(chapter.dateUpload!, ref: ref),
dateFormat(chapter.dateUpload!, ref: ref, context: context),
style: const TextStyle(fontSize: 11),
),
if (!chapter.isRead!)
@ -83,7 +84,7 @@ class ChapterListTileWidget extends ConsumerWidget {
children: [
const Text(''),
Text(
"Page ${chapter.lastPageRead}",
l10n.page(chapter.lastPageRead!),
style: TextStyle(
fontSize: 11,
color: isLight(context)

View file

@ -1,5 +1,6 @@
import 'package:expandable_text/expandable_text.dart';
import 'package:flutter/material.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/media_query.dart';
class ReadMoreWidget extends StatefulWidget {
@ -17,8 +18,14 @@ class ReadMoreWidgetState extends State<ReadMoreWidget>
late bool expanded = widget.text.trim().length < 232;
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
return widget.text.isEmpty
? const Text("No description")
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(l10n.no_description),
],
)
: Column(
children: [
Stack(

View file

@ -9,6 +9,7 @@ import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/download.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/providers/storage_provider.dart';
import 'package:mangayomi/modules/manga/download/providers/download_provider.dart';
@ -67,6 +68,7 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
bool _isStarted = false;
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context)!;
super.build(context);
return SizedBox(
height: 41,
@ -100,8 +102,8 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
}
},
itemBuilder: (context) => [
const PopupMenuItem(value: 0, child: Text("Send")),
const PopupMenuItem(value: 1, child: Text('Delete')),
PopupMenuItem(value: 0, child: Text(l10n.send)),
PopupMenuItem(value: 1, child: Text(l10n.delete)),
],
)
: entries.first.isStartDownload! &&
@ -123,11 +125,10 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
}
},
itemBuilder: (context) => [
const PopupMenuItem(
PopupMenuItem(
value: 1,
child: Text("Start downlading now")),
const PopupMenuItem(
value: 0, child: Text("Cancel")),
child: Text(l10n.start_downloading)),
PopupMenuItem(value: 0, child: Text(l10n.cancel)),
],
))
: entries.first.succeeded != 0
@ -191,11 +192,11 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
}
},
itemBuilder: (context) => [
const PopupMenuItem(
PopupMenuItem(
value: 1,
child: Text("Start downlading now")),
const PopupMenuItem(
value: 0, child: Text("Cancel")),
child: Text(l10n.start_downloading)),
PopupMenuItem(
value: 0, child: Text(l10n.cancel)),
],
))
: entries.first.succeeded == 0
@ -233,8 +234,8 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
}
},
itemBuilder: (context) => [
const PopupMenuItem(
value: 0, child: Text("Retry")),
PopupMenuItem(
value: 0, child: Text(l10n.retry)),
],
));
}
@ -253,9 +254,9 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
}
},
itemBuilder: (context) => [
const PopupMenuItem(
value: 1, child: Text("Start downlading now")),
const PopupMenuItem(value: 0, child: Text("Cancel")),
PopupMenuItem(
value: 1, child: Text(l10n.start_downloading)),
PopupMenuItem(value: 0, child: Text(l10n.cancel)),
],
))
: IconButton(

View file

@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/eval/bridge_class/model.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/get_latest_updates_manga.dart';
import 'package:mangayomi/services/get_popular_manga.dart';
import 'package:mangayomi/services/search_manga.dart';
@ -37,11 +38,15 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
int _fullDataLength = 20;
int _page = 1;
int _selectedIndex = 0;
final List<TypeMangaSelector> _types = [
TypeMangaSelector(Icons.favorite, 'Popular'),
TypeMangaSelector(Icons.new_releases_outlined, 'Latest'),
TypeMangaSelector(Icons.filter_list_outlined, 'Filter'),
];
List<TypeMangaSelector> _types(BuildContext context) {
final l10n = l10nLocalizations(context)!;
return [
TypeMangaSelector(Icons.favorite, l10n.popular),
TypeMangaSelector(Icons.new_releases_outlined, l10n.latest),
TypeMangaSelector(Icons.filter_list_outlined, l10n.filter),
];
}
final _textEditingController = TextEditingController();
String _query = "";
bool _isSearch = false;
@ -61,7 +66,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
page: 1,
));
}
final l10n = l10nLocalizations(context)!;
return Scaffold(
appBar: AppBar(
title: _isSearch ? null : Text('${widget.source.name}'),
@ -136,9 +141,9 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
itemCount: 3,
itemBuilder: (context, index) {
return MangasCardSelector(
icon: _types[index].icon,
icon: _types(context)[index].icon,
selected: _selectedIndex == index,
text: _types[index].title,
text: _types(context)[index].title,
onPressed: () {
setState(() {
_selectedIndex = index;
@ -283,7 +288,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
}
if (data.isEmpty) {
return const Center(child: Text("No result"));
return Center(child: Text(l10n.no_result));
}
if (!_isSearch) {
_scrollController.addListener(() {

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/search_manga.dart';
import 'package:mangayomi/modules/manga/home/manga_home_screen.dart';
import 'package:mangayomi/modules/widgets/gridview_widget.dart';
@ -18,6 +19,7 @@ class SearchResultScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context)!;
final search =
ref.watch(searchMangaProvider(source: source, query: query, page: 1));
return Scaffold(
@ -43,8 +45,8 @@ class SearchResultScreen extends ConsumerWidget {
},
);
}
return const Center(
child: Text("Empty"),
return Center(
child: Text(l10n.no_result),
);
}));
}

View file

@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:mangayomi/modules/manga/reader/manga_reader_view.dart';
import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/media_query.dart';
class ChapterIntervalPageView extends ConsumerWidget {
@ -20,16 +21,18 @@ class ChapterIntervalPageView extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context)!;
final readerController =
ReaderController(chapter: uChapDataPreload.chapter!);
String text = uChapDataPreload.hasPrevPrePage && hasPrevChapter
? "Current:"
: "Finished:";
? l10n.current(":")
: l10n.finished(":");
final noMoreChapter = uChapDataPreload.hasNextPrePage && !hasNextChapter ||
uChapDataPreload.hasPrevPrePage && !hasPrevChapter;
String noMore =
uChapDataPreload.hasNextPrePage && !hasNextChapter ? "Next" : "Previous";
// String noMore = uChapDataPreload.hasNextPrePage && !hasNextChapter
// ? l10n.next("")
// : l10n.previous("");
return SizedBox(
height: mediaHeight(context, 0.27),
child: Column(
@ -38,9 +41,9 @@ class ChapterIntervalPageView extends ConsumerWidget {
if (uChapDataPreload.hasPrevPrePage && hasPrevChapter)
Column(
children: [
const Text(
"Previous:",
style: TextStyle(
Text(
l10n.previous(":"),
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 12),
@ -85,7 +88,7 @@ class ChapterIntervalPageView extends ConsumerWidget {
),
if (noMoreChapter)
Text(
"There's no $noMore chapter",
l10n.no_more_chapter,
style: const TextStyle(color: Colors.white, fontSize: 14),
textAlign: TextAlign.center,
),
@ -123,9 +126,9 @@ class ChapterIntervalPageView extends ConsumerWidget {
const SizedBox(
height: 10,
),
const Text(
"Next:",
style: TextStyle(
Text(
l10n.next(":"),
style: const TextStyle(
fontWeight: FontWeight.bold, color: Colors.white),
),
Text(

View file

@ -795,7 +795,7 @@ class _MangaChapterPageGalleryState
width: 7,
),
Text(
getReaderModeName(readerMode),
getReaderModeName(readerMode, context),
style: const TextStyle(
color: Colors.white,
fontSize: 12,
@ -1064,7 +1064,8 @@ class _MangaChapterPageGalleryState
final model = resultMap[_listViewContext];
if (model == null) return;
_posIndex = model.firstChild?.index ?? 0;
if (!(_uChapDataPreload[_posIndex ?? 0].hasNextPrePage ||
if (!(_uChapDataPreload[_posIndex ?? 0]
.hasNextPrePage ||
_uChapDataPreload[_posIndex ?? 0].hasPrevPrePage)) {
_readerController = ReaderController(
chapter:

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:package_info_plus/package_info_plus.dart';
@ -46,9 +47,10 @@ class _AboutScreenState extends State<AboutScreen> {
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context);
return Scaffold(
appBar: AppBar(
title: const Text('About'),
title: Text(l10n!.about),
),
body: Column(
children: [
@ -78,7 +80,7 @@ class _AboutScreenState extends State<AboutScreen> {
),
ListTile(
onTap: () {},
title: const Text('Check for update'),
title: Text(l10n.check_for_update),
),
// ListTile(
// onTap: () {},

View file

@ -5,6 +5,7 @@ import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/modules/more/categoties/providers/isar_providers.dart';
import 'package:mangayomi/modules/more/categoties/widgets/custom_textfield.dart';
import 'package:mangayomi/modules/widgets/progress_center.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class CategoriesScreen extends ConsumerStatefulWidget {
const CategoriesScreen({super.key});
@ -17,20 +18,21 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
List<Category> _entries = [];
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context);
final categories = ref.watch(getMangaCategorieStreamProvider);
return Scaffold(
appBar: AppBar(
title: const Text("Edit categories"),
title: Text(l10n!.edit_categories),
),
body: categories.when(
data: (data) {
if (data.isEmpty) {
_entries = [];
return const Center(
return Center(
child: Padding(
padding: EdgeInsets.all(8.0),
padding: const EdgeInsets.all(8.0),
child: Text(
"You have no categories. Tap the plus button to create one for organizing your library",
l10n.edit_categories_description,
textAlign: TextAlign.center,
),
),
@ -96,12 +98,12 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: const Text(
"Delete category",
title: Text(
l10n.delete_category,
),
content: Text(
"Do you wish to delete the category"
' "${_entries[index].name}"?'),
l10n.delete_category_msg(
_entries[index].name!)),
actions: [
Row(
mainAxisAlignment:
@ -112,8 +114,8 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
Navigator.pop(
context);
},
child: const Text(
"Cancel")),
child: Text(
l10n.cancel)),
const SizedBox(
width: 15,
),
@ -132,8 +134,8 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
context);
}
},
child: const Text(
"OK",
child: Text(
l10n.ok,
)),
],
)
@ -157,11 +159,11 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
},
error: (Object error, StackTrace stackTrace) {
_entries = [];
return const Center(
return Center(
child: Padding(
padding: EdgeInsets.all(8.0),
padding: const EdgeInsets.all(8.0),
child: Text(
"You have no categories. Tap the plus button to create one for organizing your library",
l10n.edit_categories_description,
textAlign: TextAlign.center,
),
),
@ -182,9 +184,7 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
child: StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: const Text(
"Add category",
),
title: Text(l10n.add_category),
content: CustomTextFormField(
controller: controller,
entries: _entries,
@ -204,27 +204,26 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
onPressed: () {
Navigator.pop(context);
},
child: const Text("Cancel")),
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed:
controller.text.isEmpty || isExist
? null
: () async {
await isar.writeTxn(() async {
await isar.categorys
.put(Category(
name: controller.text,
));
});
if (mounted) {
Navigator.pop(context);
}
},
onPressed: controller.text.isEmpty ||
isExist
? null
: () async {
await isar.writeTxn(() async {
await isar.categorys.put(Category(
name: controller.text,
));
});
if (mounted) {
Navigator.pop(context);
}
},
child: Text(
"Add",
l10n.add,
style: TextStyle(
color:
controller.text.isEmpty || isExist
@ -242,13 +241,13 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
);
});
},
label: const Row(
label: Row(
children: [
Icon(Icons.add),
SizedBox(
const Icon(Icons.add),
const SizedBox(
width: 10,
),
Text("Add")
Text(l10n.add)
],
)),
);
@ -263,9 +262,10 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
final l10n = l10nLocalizations(context);
return AlertDialog(
title: const Text(
"Rename category",
title: Text(
l10n!.rename_category,
),
content: CustomTextFormField(
controller: controller,
@ -291,26 +291,25 @@ class _CategoriesScreenState extends ConsumerState<CategoriesScreen> {
onPressed: () {
Navigator.pop(context);
},
child: const Text("Cancel")),
child: Text(l10n.cancel)),
const SizedBox(
width: 15,
),
TextButton(
onPressed: controller.text.isEmpty ||
isExist ||
isSameName
? null
: () async {
await isar.writeTxn(() async {
category.name = controller.text;
await isar.categorys.put(category);
});
if (mounted) {
Navigator.pop(context);
}
},
onPressed:
controller.text.isEmpty || isExist || isSameName
? null
: () async {
await isar.writeTxn(() async {
category.name = controller.text;
await isar.categorys.put(category);
});
if (mounted) {
Navigator.pop(context);
}
},
child: Text(
"OK",
l10n.ok,
style: TextStyle(
color: controller.text.isEmpty ||
isExist ||

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:mangayomi/models/category.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class CustomTextFormField extends StatelessWidget {
final TextEditingController controller;
@ -22,6 +23,7 @@ class CustomTextFormField extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context);
return TextFormField(
autofocus: true,
controller: controller,
@ -38,11 +40,11 @@ class CustomTextFormField extends StatelessWidget {
onFieldSubmitted: (s) {},
decoration: InputDecoration(
helperText: isExist == true
? "A category with this name already exist!"
: "*required",
? l10n!.add_category_error_exist
: l10n!.category_name_required,
helperStyle: TextStyle(color: isExist == true ? Colors.red : null),
isDense: true,
label: Text("Name",
label: Text(l10n.name,
style: TextStyle(color: isExist == true ? Colors.red : null)),
filled: true,
fillColor: Colors.transparent,

View file

@ -5,12 +5,14 @@ import 'package:grouped_list/grouped_list.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/download.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class DownloadQueueScreen extends ConsumerWidget {
const DownloadQueueScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context);
return StreamBuilder(
stream:
isar.downloads.filter().idIsNotNull().watch(fireImmediately: true),
@ -27,7 +29,7 @@ class DownloadQueueScreen extends ConsumerWidget {
appBar: AppBar(
title: Row(
children: [
const Text('Download queue'),
Text(l10n!.download_queue),
const SizedBox(
width: 10,
),
@ -139,8 +141,8 @@ class DownloadQueueScreen extends ConsumerWidget {
}
},
itemBuilder: (context) => [
const PopupMenuItem(
value: 'Cancel', child: Text("Cancel")),
PopupMenuItem(
value: 'Cancel', child: Text(l10n.cancel)),
],
),
)
@ -157,9 +159,9 @@ class DownloadQueueScreen extends ConsumerWidget {
}
return Scaffold(
appBar: AppBar(
title: const Text('Download queue'),
title: Text(l10n!.download_queue),
),
body: const Center(child: Text('No downloads')),
body: Center(child: Text(l10n.no_downloads)),
);
},
);

View file

@ -2,12 +2,14 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mangayomi/modules/more/widgets/incognito_mode_widget.dart';
import 'package:mangayomi/modules/more/widgets/list_tile_widget.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class MoreScreen extends StatelessWidget {
const MoreScreen({super.key});
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context);
return Scaffold(
body: SingleChildScrollView(
child: Column(
@ -40,14 +42,14 @@ class MoreScreen extends StatelessWidget {
context.push('/downloadQueue');
},
icon: Icons.download_outlined,
title: 'Donwload queue',
title: l10n!.download_queue,
),
ListTileWidget(
onTap: () {
context.push('/categories');
},
icon: Icons.label_outline_rounded,
title: 'Categories',
title: l10n.categories,
),
const Divider(),
// ListTile(
@ -74,19 +76,18 @@ class MoreScreen extends StatelessWidget {
context.push('/settings');
},
icon: Icons.settings_outlined,
title: 'Settings',
title: l10n.settings,
),
ListTileWidget(
onTap: () {
context.push('/about');
},
icon: Icons.info_outline,
title: 'About',
),
onTap: () {
context.push('/about');
},
icon: Icons.info_outline,
title: l10n.about),
ListTileWidget(
onTap: () {},
icon: Icons.help_outline,
title: 'Help',
title: l10n.help,
),
],
),

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/date.dart';
import 'package:mangayomi/utils/media_query.dart';
@ -14,12 +15,13 @@ class AppearanceScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context);
final dateFormatState = ref.watch(dateFormatStateProvider);
final relativeTimestamps = ref.watch(relativeTimesTampsStateProvider);
final pureBlackDarkMode = ref.watch(pureBlackDarkModeStateProvider);
return Scaffold(
appBar: AppBar(
title: const Text("Appearance"),
title: Text(l10n!.appearance),
),
body: Column(
children: [
@ -31,7 +33,7 @@ class AppearanceScreen extends ConsumerWidget {
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
children: [
Text("Theme",
Text(l10n.theme,
style: TextStyle(
fontSize: 13, color: primaryColor(context))),
],
@ -42,7 +44,7 @@ class AppearanceScreen extends ConsumerWidget {
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: SwitchListTile(
title: const Text("Pure black dark mode"),
title: Text(l10n.pure_black_dark_mode),
value: pureBlackDarkMode,
onChanged: (value) {
ref
@ -62,7 +64,7 @@ class AppearanceScreen extends ConsumerWidget {
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
children: [
Text("Timestamps",
Text(l10n.timestamp,
style: TextStyle(
fontSize: 13, color: primaryColor(context))),
],
@ -74,14 +76,15 @@ class AppearanceScreen extends ConsumerWidget {
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"Relative timestamps",
title: Text(
l10n.relative_timestamp,
),
content: SizedBox(
width: mediaWidth(context, 0.8),
child: ListView.builder(
shrinkWrap: true,
itemCount: relativeTimestampsList.length,
itemCount:
relativeTimestampsList(context).length,
itemBuilder: (context, index) {
return RadioListTile(
dense: true,
@ -98,7 +101,8 @@ class AppearanceScreen extends ConsumerWidget {
},
title: Row(
children: [
Text(relativeTimestampsList[index])
Text(relativeTimestampsList(
context)[index])
],
),
);
@ -113,7 +117,7 @@ class AppearanceScreen extends ConsumerWidget {
Navigator.pop(context);
},
child: Text(
"Cancel",
l10n.cancel,
style: TextStyle(
color: primaryColor(context)),
)),
@ -123,9 +127,9 @@ class AppearanceScreen extends ConsumerWidget {
);
});
},
title: const Text("Relative timestamps"),
title: Text(l10n.relative_timestamp),
subtitle: Text(
relativeTimestampsList[relativeTimestamps],
relativeTimestampsList(context)[relativeTimestamps],
style:
TextStyle(fontSize: 11, color: secondaryColor(context)),
),
@ -136,8 +140,8 @@ class AppearanceScreen extends ConsumerWidget {
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"Date format",
title: Text(
l10n.date_format,
),
content: SizedBox(
width: mediaWidth(context, 0.8),
@ -160,7 +164,7 @@ class AppearanceScreen extends ConsumerWidget {
title: Row(
children: [
Text(
"${dateFormatsList[index]} (${dateFormat(DateTime.now().millisecondsSinceEpoch.toString(), useRelativeTimesTamps: false, dateFormat: dateFormatsList[index], ref: ref)})")
"${dateFormatsList[index]} (${dateFormat(context: context, DateTime.now().millisecondsSinceEpoch.toString(), useRelativeTimesTamps: false, dateFormat: dateFormatsList[index], ref: ref)})")
],
),
);
@ -175,7 +179,7 @@ class AppearanceScreen extends ConsumerWidget {
Navigator.pop(context);
},
child: Text(
"Cancel",
l10n.cancel,
style: TextStyle(
color: primaryColor(context)),
)),
@ -185,9 +189,9 @@ class AppearanceScreen extends ConsumerWidget {
);
});
},
title: const Text("Date format"),
title: Text(l10n.date_format),
subtitle: Text(
"$dateFormatState (${dateFormat(DateTime.now().millisecondsSinceEpoch.toString(), useRelativeTimesTamps: false, dateFormat: dateFormatState, ref: ref)})",
"$dateFormatState (${dateFormat(context: context, DateTime.now().millisecondsSinceEpoch.toString(), useRelativeTimesTamps: false, dateFormat: dateFormatState, ref: ref)})",
style:
TextStyle(fontSize: 11, color: secondaryColor(context)),
),

View file

@ -2,6 +2,7 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/modules/more/settings/appearance/providers/blend_level_state_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class BlendLevelSlider extends ConsumerWidget {
const BlendLevelSlider({super.key});
@ -9,14 +10,15 @@ class BlendLevelSlider extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final blendLevel = ref.watch(blendLevelStateProvider);
final l10n = l10nLocalizations(context);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(left: 18),
Padding(
padding: const EdgeInsets.only(left: 18),
child: Text(
'Color blend Level',
style: TextStyle(fontWeight: FontWeight.bold),
l10n!.color_blend_level,
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
Slider(

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart';
// import 'package:rive/rive.dart';
@ -17,6 +18,7 @@ class _DarkModeButtonState extends ConsumerState<DarkModeButton> {
@override
Widget build(BuildContext context) {
bool isDark = ref.watch(themeModeStateProvider);
final l10n = l10nLocalizations(context);
return SwitchListTile(
onChanged: (value) {
if (value) {
@ -25,9 +27,9 @@ class _DarkModeButtonState extends ConsumerState<DarkModeButton> {
ref.read(themeModeStateProvider.notifier).setLightTheme();
}
},
title: const Text("Dark mode"),
title: Text(l10n!.dark_mode),
subtitle: Text(
!isDark ? 'Off' : 'On',
!isDark ? l10n.off : l10n.on,
style: TextStyle(fontSize: 11, color: secondaryColor(context)),
),
value: isDark,

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
@ -11,9 +12,10 @@ class BrowseSScreen extends ConsumerWidget {
final showNSFWS = ref.watch(showNSFWStateProvider);
final onlyIncludePinnedSource =
ref.watch(onlyIncludePinnedSourceStateProvider);
final l10n = l10nLocalizations(context);
return Scaffold(
appBar: AppBar(
title: const Text("Browse"),
title: Text(l10n!.browse),
),
body: Column(
children: [
@ -25,7 +27,7 @@ class BrowseSScreen extends ConsumerWidget {
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
children: [
Text("Global search",
Text(l10n.global_search,
style: TextStyle(
fontSize: 13, color: primaryColor(context))),
],
@ -33,7 +35,7 @@ class BrowseSScreen extends ConsumerWidget {
),
SwitchListTile(
value: onlyIncludePinnedSource,
title: const Text("Only include pinned sources"),
title: Text(l10n.only_include_pinned_sources),
onChanged: (value) {
ref
.read(onlyIncludePinnedSourceStateProvider.notifier)
@ -50,7 +52,7 @@ class BrowseSScreen extends ConsumerWidget {
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
children: [
Text("NSFW (18+) sources",
Text(l10n.nsfw_sources,
style: TextStyle(
fontSize: 13, color: primaryColor(context))),
],
@ -58,7 +60,7 @@ class BrowseSScreen extends ConsumerWidget {
),
SwitchListTile(
value: showNSFWS,
title: const Text("Show in sources and extensions lists"),
title: Text(l10n.nsfw_sources_show),
onChanged: (value) {
ref.read(showNSFWStateProvider.notifier).set(value);
}),
@ -74,8 +76,7 @@ class BrowseSScreen extends ConsumerWidget {
],
),
),
subtitle: Text(
"This does not prevent unofficial or potentially incorrectly flagged extensions from surfacing NSFW (18+) content within the app",
subtitle: Text(l10n.nsfw_sources_info,
style: TextStyle(
fontSize: 11, color: secondaryColor(context))),
)

View file

@ -2,6 +2,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/modules/more/settings/downloads/providers/downloads_state_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/media_query.dart';
@ -21,9 +22,10 @@ class _DownloadsScreenState extends ConsumerState<DownloadsScreen> {
final onlyOnWifiState = ref.watch(onlyOnWifiStateProvider);
final downloadLocationState = ref.watch(downloadLocationStateProvider);
ref.read(downloadLocationStateProvider.notifier).refresh();
final l10n = l10nLocalizations(context);
return Scaffold(
appBar: AppBar(
title: const Text("Downloads"),
title: Text(l10n!.downloads),
),
body: Column(
children: [
@ -33,8 +35,8 @@ class _DownloadsScreenState extends ConsumerState<DownloadsScreen> {
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"Download location",
title: Text(
l10n.download_location,
),
content: SizedBox(
width: mediaWidth(context, 0.8),
@ -76,7 +78,7 @@ class _DownloadsScreenState extends ConsumerState<DownloadsScreen> {
if (!mounted) return;
Navigator.pop(context);
},
title: const Text("Custom location")),
title: Text(l10n.custom_location)),
],
)),
actions: [
@ -88,7 +90,7 @@ class _DownloadsScreenState extends ConsumerState<DownloadsScreen> {
Navigator.pop(context);
},
child: Text(
"Cancel",
l10n.cancel,
style:
TextStyle(color: primaryColor(context)),
)),
@ -98,7 +100,7 @@ class _DownloadsScreenState extends ConsumerState<DownloadsScreen> {
);
});
},
title: const Text("Download location"),
title: Text(l10n.download_location),
subtitle: Text(
downloadLocationState.$2.isEmpty
? downloadLocationState.$1
@ -108,13 +110,13 @@ class _DownloadsScreenState extends ConsumerState<DownloadsScreen> {
),
SwitchListTile(
value: onlyOnWifiState,
title: const Text("Only on wifi"),
title: Text(l10n.only_on_wifi),
onChanged: (value) {
ref.read(onlyOnWifiStateProvider.notifier).set(value);
}),
SwitchListTile(
value: saveAsCBZArchiveState,
title: const Text("Save as CBZ archive"),
title: Text(l10n.save_as_cbz_archive),
onChanged: (value) {
ref.read(saveAsCBZArchiveStateProvider.notifier).set(value);
}),

View file

@ -1,16 +1,21 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/utils/media_query.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class GeneralScreen extends ConsumerWidget {
const GeneralScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context);
final l10nLocale = ref.watch(l10nLocaleStateProvider);
return Scaffold(
appBar: AppBar(
title: const Text("General"),
title: Text(l10n!.general),
),
body: Column(
children: [
@ -20,26 +25,30 @@ class GeneralScreen extends ConsumerWidget {
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"App language",
title: Text(
l10n.app_language,
),
content: SizedBox(
width: mediaWidth(context, 0.8),
child: ListView.builder(
shrinkWrap: true,
itemCount: 1,
itemCount: AppLocalizations.supportedLocales.length,
itemBuilder: (context, index) {
final locale =
AppLocalizations.supportedLocales[index];
return RadioListTile(
dense: true,
contentPadding: const EdgeInsets.all(0),
value: index,
groupValue: 0,
value: locale,
groupValue: l10nLocale,
onChanged: (value) {
ref
.read(l10nLocaleStateProvider.notifier)
.setLocale(locale);
Navigator.pop(context);
},
title: const Row(
children: [Text("English")],
),
title: Text(completeLanguageName(
locale.toLanguageTag())),
);
},
)),
@ -52,7 +61,7 @@ class GeneralScreen extends ConsumerWidget {
Navigator.pop(context);
},
child: Text(
"Cancel",
l10n.cancel,
style:
TextStyle(color: primaryColor(context)),
)),
@ -62,9 +71,9 @@ class GeneralScreen extends ConsumerWidget {
);
});
},
title: const Text("App language"),
title: Text(l10n.app_language),
subtitle: Text(
"English",
completeLanguageName(l10nLocale.toLanguageTag()),
style: TextStyle(fontSize: 11, color: secondaryColor(context)),
),
),

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/media_query.dart';
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
@ -10,6 +11,7 @@ class ReaderScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context);
final defaultReadingMode = ref.watch(defaultReadingModeStateProvider);
final animatePageTransitions =
ref.watch(animatePageTransitionsStateProvider);
@ -18,7 +20,7 @@ class ReaderScreen extends ConsumerWidget {
ref.watch(doubleTapAnimationSpeedStateProvider);
return Scaffold(
appBar: AppBar(
title: const Text("Reader"),
title: Text(l10n!.reader),
),
body: Column(
children: [
@ -28,9 +30,7 @@ class ReaderScreen extends ConsumerWidget {
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"Default reading mode",
),
title: Text(l10n.default_reading_mode),
content: SizedBox(
width: mediaWidth(context, 0.8),
child: ListView.builder(
@ -52,7 +52,7 @@ class ReaderScreen extends ConsumerWidget {
title: Row(
children: [
Text(getReaderModeName(
ReaderMode.values[index]))
ReaderMode.values[index], context))
],
),
);
@ -67,7 +67,7 @@ class ReaderScreen extends ConsumerWidget {
Navigator.pop(context);
},
child: Text(
"Cancel",
l10n.cancel,
style:
TextStyle(color: primaryColor(context)),
)),
@ -77,9 +77,9 @@ class ReaderScreen extends ConsumerWidget {
);
});
},
title: const Text("Default reading mode"),
title: Text(l10n.default_reading_mode),
subtitle: Text(
getReaderModeName(defaultReadingMode),
getReaderModeName(defaultReadingMode, context),
style: TextStyle(fontSize: 11, color: secondaryColor(context)),
),
),
@ -89,8 +89,8 @@ class ReaderScreen extends ConsumerWidget {
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"Double tap animation speed",
title: Text(
l10n.double_tap_animation_speed,
),
content: SizedBox(
width: mediaWidth(context, 0.8),
@ -112,7 +112,7 @@ class ReaderScreen extends ConsumerWidget {
},
title: Row(
children: [
Text(getAnimationSpeedName(index))
Text(getAnimationSpeedName(index, context))
],
),
);
@ -127,7 +127,7 @@ class ReaderScreen extends ConsumerWidget {
Navigator.pop(context);
},
child: Text(
"Cancel",
l10n.cancel,
style:
TextStyle(color: primaryColor(context)),
)),
@ -137,15 +137,15 @@ class ReaderScreen extends ConsumerWidget {
);
});
},
title: const Text("Double tap animation speed"),
title: Text(l10n.double_tap_animation_speed),
subtitle: Text(
getAnimationSpeedName(doubleTapAnimationSpeed),
getAnimationSpeedName(doubleTapAnimationSpeed, context),
style: TextStyle(fontSize: 11, color: secondaryColor(context)),
),
),
SwitchListTile(
value: animatePageTransitions,
title: const Text("Animate page transitions"),
title: Text(l10n.animate_page_transitions),
onChanged: (value) {
ref
.read(animatePageTransitionsStateProvider.notifier)
@ -153,11 +153,9 @@ class ReaderScreen extends ConsumerWidget {
}),
SwitchListTile(
value: cropBorders,
title: const Text("Crop borders"),
title: Text(l10n.crop_borders),
onChanged: (value) {
ref
.read(cropBordersStateProvider.notifier)
.set(value);
ref.read(cropBordersStateProvider.notifier).set(value);
}),
],
),
@ -165,22 +163,24 @@ class ReaderScreen extends ConsumerWidget {
}
}
String getReaderModeName(ReaderMode readerMode) {
String getReaderModeName(ReaderMode readerMode, BuildContext context) {
final l10n = l10nLocalizations(context);
return readerMode == ReaderMode.vertical
? 'Vertical'
? l10n!.reading_mode_vertical
: readerMode == ReaderMode.verticalContinuous
? 'Verical continuous'
? l10n!.reading_mode_vertical_continuous
: readerMode == ReaderMode.ltr
? 'Left to Right'
? l10n!.reading_mode_left_to_right
: readerMode == ReaderMode.rtl
? 'Right to Left'
: 'Webtoon';
? l10n!.reading_mode_right_to_left
: l10n!.reading_mode_webtoon;
}
String getAnimationSpeedName(int type) {
String getAnimationSpeedName(int type, BuildContext context) {
final l10n = l10nLocalizations(context);
return type == 0
? 'No animation'
? l10n!.no_animation
: type == 1
? 'Normal'
: "Fast";
? l10n!.normal
: l10n!.fast;
}

View file

@ -1,47 +1,49 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mangayomi/modules/more/widgets/list_tile_widget.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class SettingsScreen extends StatelessWidget {
const SettingsScreen({super.key});
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context);
return Scaffold(
appBar: AppBar(
title: const Text("Settings"),
title: Text(l10n!.settings),
),
body: SingleChildScrollView(
child: Column(
children: [
ListTileWidget(
title: 'General',
subtitle: 'App language',
title: l10n.general,
subtitle: l10n.general_subtitle,
icon: Icons.tune_rounded,
onTap: () => context.push('/general')),
ListTileWidget(
title: 'Appearance',
subtitle: 'Theme, date & time format',
title: l10n.appearance,
subtitle: l10n.appearance_subtitle,
icon: Icons.color_lens_rounded,
onTap: () => context.push('/appearance')),
// ListTileWidget(
// title: 'Library',
// title: l10n.library,
// subtitle: 'Categories',
// icon: Icons.collections_bookmark_rounded,
// onTap: () {}),
ListTileWidget(
title: 'Reader',
subtitle: 'Reading mode, display, navigation',
title: l10n.reader,
subtitle: l10n.reader_subtitle,
icon: Icons.chrome_reader_mode_rounded,
onTap: () => context.push('/readerMode')),
ListTileWidget(
title: 'Downloads',
subtitle: 'Downloads settings',
title: l10n.downloads,
subtitle: l10n.downloads_subtitle,
icon: Icons.download_outlined,
onTap: () => context.push('/downloads')),
ListTileWidget(
title: 'Browse',
subtitle: 'Sources, global search',
title: l10n.browse,
subtitle: l10n.browse_subtitle,
icon: Icons.explore_rounded,
onTap: () => context.push('/browseS')),
ListTileWidget(
@ -49,7 +51,7 @@ class SettingsScreen extends StatelessWidget {
context.push('/about');
},
icon: Icons.info_outline,
title: 'About',
title: l10n.about,
),
],
),

View file

@ -3,12 +3,14 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/modules/more/providers/incognito_mode_state_provider.dart';
import 'package:mangayomi/modules/more/widgets/list_tile_widget.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class IncognitoModeWidget extends ConsumerWidget {
const IncognitoModeWidget({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context);
final incognitoMode = ref.watch(incognitoModeStateProvider);
return ListTileWidget(
onTap: () {
@ -19,8 +21,8 @@ class IncognitoModeWidget extends ConsumerWidget {
}
},
icon: CupertinoIcons.eyeglasses,
subtitle: 'pauses reading history',
title: 'Incognito mode',
subtitle: l10n!.incognito_mode_description,
title: l10n.incognito_mode,
trailing: Switch(
value: incognitoMode,
onChanged: (value) {

View file

@ -1,16 +1,18 @@
import 'package:flutter/material.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class UpdatesScreen extends StatelessWidget {
const UpdatesScreen({super.key});
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context);
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
title: Text(
'Updates',
l10n!.updates,
style: TextStyle(color: Theme.of(context).hintColor),
),
actions: [
@ -20,8 +22,8 @@ class UpdatesScreen extends StatelessWidget {
icon: Icon(Icons.refresh, color: Theme.of(context).hintColor)),
],
),
body: const Center(
child: Text("No recent updates"),
body: Center(
child: Text(l10n.no_recent_updates),
),
);
}

View file

@ -8,6 +8,7 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/services/http_service/cloudflare/cookie.dart';
import 'package:mangayomi/utils/constant.dart';
import 'package:url_launcher/url_launcher.dart';
@ -71,6 +72,7 @@ class _MangaWebViewState extends ConsumerState<MangaWebView> {
@override
Widget build(BuildContext context) {
final l10n = l10nLocalizations(context);
return !isNotDesktop
? Scaffold(
appBar: AppBar(
@ -142,14 +144,14 @@ class _MangaWebViewState extends ConsumerState<MangaWebView> {
),
PopupMenuButton(itemBuilder: (context) {
return [
const PopupMenuItem<int>(
value: 0, child: Text("Refresh")),
const PopupMenuItem<int>(
value: 1, child: Text("Share")),
const PopupMenuItem<int>(
value: 2, child: Text("Open in browser")),
const PopupMenuItem<int>(
value: 3, child: Text("Clear cookie")),
PopupMenuItem<int>(
value: 0, child: Text(l10n!.refresh)),
PopupMenuItem<int>(
value: 1, child: Text(l10n.share)),
PopupMenuItem<int>(
value: 2, child: Text(l10n.open_in_browser)),
PopupMenuItem<int>(
value: 3, child: Text(l10n.clear_cookie)),
];
}, onSelected: (value) async {
if (value == 0) {

View file

@ -8,6 +8,7 @@ import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/eval/bridge_class/model.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/headers.dart';
import 'package:mangayomi/modules/widgets/bottom_text_widget.dart';
@ -26,6 +27,7 @@ class MangaImageCardWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context);
return StreamBuilder(
stream: isar.mangas
.filter()
@ -78,7 +80,7 @@ class MangaImageCardWidget extends ConsumerWidget {
child: Padding(
padding: const EdgeInsets.all(2),
child: Text(
"In library",
l10n!.in_library,
style: TextStyle(
fontSize: 12,
color: Theme.of(context)

View file

@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
part 'l10n_providers.g.dart';
@riverpod
class L10nLocaleState extends _$L10nLocaleState {
@override
Locale build() {
return Locale(
_getLocale()!.languageCode ?? "en", _getLocale()!.countryCode ?? "");
}
L10nLocale? _getLocale() {
return isar.settings.getSync(227)!.locale ??
L10nLocale(languageCode: "en", countryCode: "");
}
void setLocale(Locale locale) async {
final settings = isar.settings.getSync(227)!;
isar.writeTxnSync(() {
isar.settings.putSync(settings
..locale = L10nLocale(
languageCode: locale.languageCode,
countryCode: locale.countryCode));
});
state = locale;
}
}
AppLocalizations? l10nLocalizations(BuildContext context) =>
AppLocalizations.of(context);
Locale currentLocale(BuildContext context) {
return Localizations.localeOf(context);
}

View file

@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'l10n_providers.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$l10nLocaleStateHash() => r'a1f842ccc55a111698bf7e096644858008014123';
/// See also [L10nLocaleState].
@ProviderFor(L10nLocaleState)
final l10nLocaleStateProvider =
AutoDisposeNotifierProvider<L10nLocaleState, Locale>.internal(
L10nLocaleState.new,
name: r'l10nLocaleStateProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$l10nLocaleStateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$L10nLocaleState = AutoDisposeNotifier<Locale>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions

View file

@ -1,6 +1,5 @@
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/source.dart';
@ -27,9 +26,12 @@ import 'package:mangayomi/modules/more/settings/browse/browse_screen.dart';
import 'package:mangayomi/modules/more/settings/general/general_screen.dart';
import 'package:mangayomi/modules/more/settings/reader/reader_screen.dart';
import 'package:mangayomi/modules/more/settings/settings_screen.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'router.g.dart';
final routerProvider = Provider<GoRouter>((ref) {
final router = AsyncRouterNotifier();
@riverpod
GoRouter router(RouterRef ref) {
final router = RouterNotifier();
return GoRouter(
observers: [BotToastNavigatorObserver()],
@ -38,9 +40,9 @@ final routerProvider = Provider<GoRouter>((ref) {
refreshListenable: router,
routes: router._routes,
);
});
}
class AsyncRouterNotifier extends ChangeNotifier {
class RouterNotifier extends ChangeNotifier {
List<RouteBase> get _routes => [
ShellRoute(
builder: (context, state, child) => MainScreen(child: child),

23
lib/router/router.g.dart Normal file
View file

@ -0,0 +1,23 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'router.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$routerHash() => r'1049511ecc105e3fcf813ac0a8a47295ca0fa399';
/// See also [router].
@ProviderFor(router)
final routerProvider = AutoDisposeProvider<GoRouter>.internal(
router,
name: r'routerProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$routerHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef RouterRef = AutoDisposeProviderRef<GoRouter>;
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions

View file

@ -7,7 +7,7 @@ part of 'get_latest_updates_manga.dart';
// **************************************************************************
String _$getLatestUpdatesMangaHash() =>
r'6ad1f68ce7a320c661817e5d5ff1bbf8d68b3948';
r'80d9ccc7583754fa37f4c545cc78635ab598027c';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'get_manga_detail.dart';
// RiverpodGenerator
// **************************************************************************
String _$getMangaDetailHash() => r'e5c9845c4481eb584cbd899dacaaceda8167ae44';
String _$getMangaDetailHash() => r'20b69ef0370efa89e9bbc642773eb6afc8359572';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'get_popular_manga.dart';
// RiverpodGenerator
// **************************************************************************
String _$getPopularMangaHash() => r'f0999a803936680db27e22750a620566c25ae69e';
String _$getPopularMangaHash() => r'004a790418e152205eb693fed82bf249b2347ca1';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'cookie.dart';
// RiverpodGenerator
// **************************************************************************
String _$setCookieHash() => r'3e91a1c44ab0e597cebb55bf50d3a5a29d1eb29b';
String _$setCookieHash() => r'320b02afaf98d721518937f1b894240d3800d765';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'cookie_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$cookieStateHash() => r'37608903bb251f586fea7458dd4762160c456868';
String _$cookieStateHash() => r'42286f51989b6f65eed9787ca2390a96854395a8';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'search_manga.dart';
// RiverpodGenerator
// **************************************************************************
String _$searchMangaHash() => r'6e039e81e4764f69dca9a3ed133a76331d291b68';
String _$searchMangaHash() => r'e2c83ae7e80ffd8426be229ffdef215339c9ccb1';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -1,17 +1,19 @@
import 'package:flutter/material.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
const defaultUserAgent =
"Mozilla/5.0 (Linux; Android 13; 22081212UG Build/TKQ1.220829.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.5735.131 Mobile Safari/537.36";
String getMangaStatusName(Status status) {
String getMangaStatusName(Status status, BuildContext context) {
final l10n = l10nLocalizations(context)!;
return switch (status) {
Status.ongoing => "Ongoing",
Status.onHiatus => "On hiatus",
Status.canceled => "Canceled",
Status.completed => "Completed",
Status.publishingFinished => "Publishing finished",
_ => "Unknown",
Status.ongoing => l10n.ongoing,
Status.onHiatus => l10n.on_hiatus,
Status.canceled => l10n.canceled,
Status.completed => l10n.completed,
Status.publishingFinished => l10n.publishing_finished,
_ => l10n.unknown,
};
}

View file

@ -1,13 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';
import 'package:mangayomi/modules/more/settings/appearance/providers/date_format_state_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
String dateFormat(String? timestamp,
{required WidgetRef ref,
required BuildContext context,
String? stringDate,
bool forHistoryValue = false,
bool useRelativeTimesTamps = true,
String dateFormat = ""}) {
final l10n = l10nLocalizations(context)!;
final locale = currentLocale(context);
final relativeTimestamps = ref.watch(relativeTimesTampsStateProvider);
final dateFrmt = ref.watch(dateFormatStateProvider);
final dateTime = stringDate != null
@ -25,15 +30,15 @@ String dateFormat(String? timestamp,
final fiveDaysAgo = DateTime(now.year, now.month, now.day - 5);
final sixDaysAgo = DateTime(now.year, now.month, now.day - 6);
final aWeekAgo = DateTime(now.year, now.month, now.day - 7);
final formatter =
DateFormat(dateFormat.isEmpty ? dateFrmt : dateFormat, "en");
final formatter = DateFormat(
dateFormat.isEmpty ? dateFrmt : dateFormat, locale.toLanguageTag());
if (date == today && useRelativeTimesTamps && relativeTimestamps != 0) {
return 'Today';
return l10n.today;
} else if (date == yesterday &&
useRelativeTimesTamps &&
relativeTimestamps != 0) {
return 'Yesterday';
return l10n.yesterday;
} else if (useRelativeTimesTamps && relativeTimestamps == 2) {
if (date.isAfter(twoDaysAgo) ||
date.isAfter(twoDaysAgo) ||
@ -43,7 +48,7 @@ String dateFormat(String? timestamp,
date.isAfter(sixDaysAgo) ||
date.isAfter(aWeekAgo)) {
final difference = today.difference(date).inDays;
return difference != 7 ? '$difference days ago' : 'A week ago';
return difference != 7 ? l10n.n_days_ago(difference) : l10n.a_week_ago;
}
}
return forHistoryValue
@ -53,10 +58,11 @@ String dateFormat(String? timestamp,
return date.toString();
}
String dateFormatHour(String timestamp) {
String dateFormatHour(String timestamp, BuildContext context) {
final locale = currentLocale(context);
final dateTime = DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp));
return DateFormat.Hm("en").format(dateTime);
return DateFormat.Hm(locale.toLanguageTag()).format(dateTime);
}
List<String> dateFormatsList = [
@ -68,8 +74,11 @@ List<String> dateFormatsList = [
"MMM dd, yyyy"
];
List<String> relativeTimestampsList = [
"Off",
"Short (Today, Yesterday)",
"Long (Short+, n days ago)",
];
List<String> relativeTimestampsList(BuildContext context) {
final l10n = l10nLocalizations(context)!;
return [
l10n.off,
l10n.relative_timestamp_short,
l10n.relative_timestamp_long,
];
}

View file

@ -6,7 +6,7 @@ part of 'headers.dart';
// RiverpodGenerator
// **************************************************************************
String _$headersHash() => r'7c58206c3909221fabe109144db054ddf516a41f';
String _$headersHash() => r'bb9238fcab606b6fe4ae2d2dab249820d7b4e2ff';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -1,30 +0,0 @@
completeLang(String lang) {
lang = lang.toLowerCase();
for (var element in languagesMap.entries) {
if (element.value.toString().toLowerCase() == lang) {
return element.key;
}
}
return lang.toUpperCase();
}
final languagesMap = {
'Français': 'fr',
'English': 'en',
'Bulgaria': 'bg',
'العربية': 'ar',
'Português': 'pt',
'Português do brasil': 'pt-br',
'Italiano': 'it',
'Pусский язык': 'ru',
'Español': 'es',
'Español latinoamericano': 'es-419',
'Bahasa Indonesia': 'id',
'हिन्दी, हिंदी': 'hi',
'日本語': 'ja',
'Polski': 'pl',
'Türkçe': 'tr',
'Deutsch': 'de',
'中文(Zhōngwén)': 'zh',
'繁體中文(Hong Kong)': 'zh-hk'
};

68
lib/utils/language.dart Normal file
View file

@ -0,0 +1,68 @@
completeLanguageName(String lang) {
lang = lang.toLowerCase();
for (var element in languagesMap.entries) {
if (element.value.toString().toLowerCase() == lang) {
return element.key;
}
}
return lang.toUpperCase();
}
final languagesMap = {
'All': 'all',
'Français': 'fr',
'Català': 'ca',
'English': 'en',
'Tiếng Việt': 'vi',
'ไทย': 'th',
'Bulgaria': 'bg',
'العربية': 'ar',
'Português': 'pt',
'한국어': 'ko',
'Português (Brasil)': 'pt-br',
'Italiano': 'it',
'Pусский язык': 'ru',
'Español': 'es',
'Español (Latinoamérica)': 'es-419',
'Indonesia': 'id',
'हिन्दी, हिंदी': 'hi',
'日本語': 'ja',
'Polski': 'pl',
'Türkçe': 'tr',
'Deutsch': 'de',
'中文(Zhōngwén)': 'zh',
'繁體中文(Hong Kong)': 'zh-hk',
"Filipino": "fil",
"Ελληνικά": "el",
"dansk": "da",
"বাংলা": "bn",
"Afrikaans": "af",
"አማርኛ": "am",
"Azərbaycan": "az",
"беларуская": "be",
"bosanski": "bs",
"svenska": "sv",
"suomi": "fi",
"فارسی": "fa",
"euskara": "eu",
"Norwegian Bokmål (Norway)": "nb-no",
"lietuvių kalba": "lt",
"srpskohrvatski": "sh",
"Norsk": "no",
"עברית": "he",
"Монгол": "mn",
"മലയാളം": "ml",
"Українська": "uk",
"isiZulu": "zu",
"isiXhosa": "xh",
"Nederlands": "nl",
"ဗမာစာ": "my",
"Malaysia": "ms",
"Hrvatski": "hr",
"Română": "ro",
"български": "bg",
"čeština": "cs",
"Kurdî": "ku",
"Magyar": "hu",
"polski": "pl",
};

View file

@ -1,32 +1,12 @@
name: mangayomi
description: Free and open source manga reader multi plateform app inspired by Tachiyomi.
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 0.0.2+5
environment:
sdk: '>=3.0.0 <4.0.0'
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
@ -69,8 +49,6 @@ dependencies:
bot_toast: ^4.0.4
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
dev_dependencies:
@ -82,64 +60,10 @@ dev_dependencies:
isar_generator: 3.1.0+1
flutter_lints: ^2.0.1
# flutter_launcher_icons:
# android: "launcher_icon"
# ios: true
# remove_alpha_ios: true
# image_path: "assets/mangayomi_logo.png"
# min_sdk_android: 24
# windows:
# generate: true
# image_path: "assets/mangayomi_logo.png"
# macos:
# generate: true
# image_path: "assets/mangayomi_logo.png"
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
generate: true
# To add assets to your application, add an assets section, like this:
assets:
- assets/
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages