Added source template for testing

This commit is contained in:
kodjomoustapha 2023-11-29 17:45:41 +01:00
parent 757587a64d
commit 3dd8c8f14b
11 changed files with 220 additions and 84 deletions

View file

@ -51,5 +51,11 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>
<key>UISupportsDocumentBrowser</key>
<true/>
</dict>
</plist>

View file

@ -15,24 +15,26 @@ class $MSource implements MSource, $Instance {
BridgeFunctionDef(returns: BridgeTypeAnnotation($type), params: []))
},
fields: {
'id': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int))),
'id':
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.int))),
'name': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'baseUrl': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'lang': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'isFullData': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))),
'hasCloudflare': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))),
'isFullData':
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))),
'hasCloudflare':
BridgeFieldDef(BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.bool))),
'dateFormat': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'dateFormatLocale': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'apiUrl': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
'additionalParams': BridgeFieldDef(
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string))),
},
wrap: true);
@ -69,6 +71,8 @@ class $MSource implements MSource, $Instance {
return $String($value.dateFormatLocale!);
case 'apiUrl':
return $String($value.apiUrl!);
case 'additionalParams':
return $String($value.additionalParams!);
default:
return _superclass.$getProperty(runtime, identifier);
@ -99,6 +103,8 @@ class $MSource implements MSource, $Instance {
$value.dateFormatLocale = value.$reified;
case 'apiUrl':
$value.apiUrl = value.$reified;
case 'additionalParams':
$value.additionalParams = value.$reified;
default:
_superclass.$setProperty(runtime, identifier, value);
}
@ -131,6 +137,9 @@ class $MSource implements MSource, $Instance {
@override
String? get name => $value.name;
@override
String? get additionalParams => $value.additionalParams;
@override
set apiUrl(String? apiUrl) {}
@ -157,4 +166,7 @@ class $MSource implements MSource, $Instance {
@override
set name(String? name) {}
@override
set additionalParams(String? additionalParams) {}
}

View file

@ -17,6 +17,8 @@ class MSource {
String? apiUrl;
String? additionalParams;
MSource(
{this.id,
this.name,
@ -26,5 +28,6 @@ class MSource {
this.hasCloudflare,
this.dateFormat,
this.dateFormatLocale,
this.apiUrl});
this.apiUrl,
this.additionalParams});
}

View file

@ -51,6 +51,8 @@ class Source {
String? appMinVerReq;
String? additionalParams;
Source(
{this.id = 0,
this.name = '',
@ -74,7 +76,8 @@ class Source {
this.sourceCode = '',
this.headers = '',
this.isManga = true,
this.appMinVerReq = ""});
this.appMinVerReq = "",
this.additionalParams = ""});
Source.fromJson(Map<String, dynamic> json) {
apiUrl = json['apiUrl'];
@ -100,6 +103,7 @@ class Source {
typeSource = json['typeSource'];
version = json['version'];
versionLast = json['versionLast'];
additionalParams = json['additionalParams'] ?? "";
}
Map<String, dynamic> toJson() {
@ -127,6 +131,7 @@ class Source {
data['typeSource'] = typeSource;
data['version'] = version;
data['versionLast'] = versionLast;
data['additionalParams'] = additionalParams;
return data;
}
@ -140,6 +145,7 @@ class Source {
baseUrl: baseUrl,
apiUrl: apiUrl,
dateFormat: dateFormat,
dateFormatLocale: dateFormatLocale);
dateFormatLocale: dateFormatLocale,
additionalParams: additionalParams);
}
}

View file

@ -6,6 +6,7 @@ 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/providers/l10n_providers.dart';
import 'package:mangayomi/sources/source_test.dart';
import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
@ -53,6 +54,8 @@ class SourcesScreen extends ConsumerWidget {
return SingleChildScrollView(
child: Column(
children: [
if (useTestSourceCode)
SourceListTile(source: testSourceModel, isManga: isManga),
GroupedListView<Source, String>(
elements: entries,
groupBy: (element) => "",

View file

@ -76,9 +76,8 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
source: widget.source,
page: _page + 1,
).future);
} else if (_selectedIndex == 2 &&
_isSearch &&
(_query.isNotEmpty || _isFiltering)) {
} else if (_selectedIndex == 2 && (_isSearch && _query.isNotEmpty) ||
_isFiltering) {
mangaResList = await ref.watch(searchProvider(
source: widget.source,
query: _query,
@ -105,19 +104,15 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
@override
Widget build(BuildContext context) {
final filterList = getFilterList(source: widget.source);
if (_selectedIndex == 2 &&
_isSearch &&
(_query.isNotEmpty || _isFiltering)) {
if (_selectedIndex == 2 && (_isSearch && _query.isNotEmpty) ||
_isFiltering) {
_getManga = ref.watch(searchProvider(
source: widget.source, query: _query, page: 1, filterList: filters));
} else if (_selectedIndex == 1 && !_isSearch && _query.isEmpty) {
_getManga =
ref.watch(getLatestUpdatesProvider(source: widget.source, page: 1));
} else if (_selectedIndex == 0 && !_isSearch && _query.isEmpty) {
_getManga = ref.watch(getPopularProvider(
source: widget.source,
page: 1,
));
_getManga = ref.watch(getPopularProvider(source: widget.source, page: 1));
}
final l10n = l10nLocalizations(context)!;
return Scaffold(
@ -198,6 +193,9 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
shrinkWrap: true,
itemCount: 3,
itemBuilder: (context, index) {
if (filterList.isEmpty && index == 2) {
return const SizedBox.shrink();
}
return MangasCardSelector(
icon: _types(context)[index].icon,
selected: _selectedIndex == index,
@ -206,7 +204,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
if (filters.isEmpty) {
filters = filterList;
}
if (filters.isNotEmpty && index == 2) {
if (index == 2) {
final result = await showModalBottomSheet(
context: context,
builder: (context) =>
@ -228,10 +226,18 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
),
const Spacer(),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
primaryColor(context)),
onPressed: () {
Navigator.pop(context, 'filter');
},
child: Text(l10n.filter),
child: Text(
l10n.filter,
style: TextStyle(
color: Theme.of(context)
.scaffoldBackgroundColor),
),
),
],
),
@ -256,7 +262,6 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
setState(() {
_selectedIndex = 2;
_isFiltering = true;
_isSearch = true;
_page = 1;
});
}
@ -271,6 +276,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
setState(() {
_selectedIndex = index;
_isFiltering = false;
_isSearch = false;
_page = 1;
});
}
@ -416,8 +422,8 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
IconButton(
onPressed: () {
if (_selectedIndex == 2 &&
_isSearch &&
(_query.isNotEmpty || _isFiltering)) {
(_isSearch && _query.isNotEmpty) ||
_isFiltering) {
ref.invalidate(searchProvider(
source: widget.source,
query: _query,

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:mangayomi/eval/model/filter.dart';
import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/media_query.dart';
class FilterWidget extends StatelessWidget {
final List<dynamic> filterList;
@ -19,26 +20,13 @@ class FilterWidget extends StatelessWidget {
final filterState = filterList[idx];
Widget? widget;
if (filterState is TextFilter) {
widget = Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
widget = SeachFormTextFieldWidget(
text: filterState.state,
onChanged: (val) {
filterList[idx] = filterState..state = val;
onChanged(filterList);
},
decoration: InputDecoration(
isDense: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: secondaryColor(context)),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: primaryColor(context)),
),
border: const OutlineInputBorder(borderSide: BorderSide()),
labelText: filterState.name,
),
),
);
labelText: filterState.name);
} else if (filterState is HeaderFilter) {
widget = ListTile(dense: true, title: Text(filterState.name));
} else if (filterState is SeparatorFilter) {
@ -117,43 +105,46 @@ class FilterWidget extends StatelessWidget {
}).toList(),
);
} else if (filterState is SelectFilter) {
widget = Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: ListTile(
dense: true,
title: Text(filterState.name),
widget = SizedBox(
width: mediaWidth(context, 1),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: ListTile(
dense: true,
title: Text(filterState.name),
),
),
),
Expanded(
child: DropdownButtonHideUnderline(
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 8, horizontal: 25),
child: DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
isExpanded: true,
value: filterState.values[filterState.state],
hint: Text(filterState.name,
style: const TextStyle(fontSize: 13)),
items: filterState.values
.map((e) => DropdownMenuItem(
value: e,
child: Text(e.name,
style: const TextStyle(fontSize: 13)),
))
.toList(),
onChanged: (value) {
filterState.state = filterState.values
.indexWhere((element) => element == value);
onChanged(filterList);
},
Expanded(
child: DropdownButtonHideUnderline(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8, horizontal: 25),
child: DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
isExpanded: true,
value: filterState.values[filterState.state],
hint: Text(filterState.name,
style: const TextStyle(fontSize: 13)),
items: filterState.values
.map((e) => DropdownMenuItem(
value: e,
child: Text(e.name,
style: const TextStyle(fontSize: 13)),
))
.toList(),
onChanged: (value) {
filterState.state = filterState.values
.indexWhere((element) => element == value);
onChanged(filterList);
},
),
),
),
),
),
],
],
),
);
}
return widget ?? const SizedBox.shrink();
@ -161,3 +152,43 @@ class FilterWidget extends StatelessWidget {
);
}
}
class SeachFormTextFieldWidget extends StatefulWidget {
final String labelText;
final String text;
final Function(String) onChanged;
const SeachFormTextFieldWidget(
{super.key,
required this.text,
required this.onChanged,
required this.labelText});
@override
State<SeachFormTextFieldWidget> createState() =>
_SeachFormTextFieldWidgetState();
}
class _SeachFormTextFieldWidgetState extends State<SeachFormTextFieldWidget> {
late final _controller = TextEditingController(text: widget.text);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: _controller,
onChanged: widget.onChanged,
decoration: InputDecoration(
isDense: true,
filled: false,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: secondaryColor(context)),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: primaryColor(context)),
),
border: const OutlineInputBorder(borderSide: BorderSide()),
labelText: widget.labelText,
),
));
}
}

View file

@ -18,7 +18,7 @@ class BackupAndRestore extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final isIOS = Platform.isIOS;
// final isIOS = Platform.isIOS;
final backupFrequency = ref.watch(backupFrequencyStateProvider);
final backupFrequencyOptions =
ref.watch(backupFrequencyOptionsStateProvider);
@ -81,12 +81,12 @@ class BackupAndRestore extends ConsumerWidget {
)),
TextButton(
onPressed: () async {
if (isIOS) {
ref.watch(doBackUpProvider(
list: indexList,
path: autoBackupLocation.$1,
context: context));
} else {
// if (isIOS) {
// ref.watch(doBackUpProvider(
// list: indexList,
// path: autoBackupLocation.$1,
// context: context));
// } else {
final result = await FilePicker.platform
.getDirectoryPath();
@ -96,7 +96,7 @@ class BackupAndRestore extends ConsumerWidget {
path: result,
context: context));
}
}
// }
},
child: Text(
l10n.ok,
@ -258,7 +258,7 @@ class BackupAndRestore extends ConsumerWidget {
style: TextStyle(fontSize: 11, color: secondaryColor(context)),
),
),
if (!isIOS)
// if (!isIOS)
ListTile(
onTap: () async {
String? result = await FilePicker.platform.getDirectoryPath();
@ -354,7 +354,7 @@ class BackupAndRestore extends ConsumerWidget {
style: TextStyle(fontSize: 11, color: secondaryColor(context)),
),
),
if (isIOS)
// if (isIOS)
ListBackupFilesFromDirectory(directory: autoBackupLocation.$1),
ListTile(
title: Padding(

View file

@ -1,2 +1,65 @@
import 'package:mangayomi/models/source.dart';
//For testing purposes, set to true
const useTestSourceCode = false;
const testSourceCode = r'''''';
final testSourceModel = Source(
name: "Test Source",
// Example: https://gogoanime3.net
baseUrl: "",
// Example: en
lang: "",
// Example: false for anime or true for manga
isManga: false);
const testSourceCode = r'''
import 'package:mangayomi/bridge_lib.dart';
import 'dart:convert';
class TestSource extends MProvider {
TestSource();
@override
Future<MPages> getPopular(MSource source, int page) async {
// TODO: implement
}
@override
Future<MPages> getLatestUpdates(MSource source, int page) async {
// TODO: implement
}
@override
Future<MPages> search(
MSource source, String query, int page, FilterList filterList) async {
// TODO: implement
}
@override
Future<MManga> getDetail(MSource source, String url) async {
// TODO: implement
}
// For anime videos
@override
Future<List<MVideo>> getVideoList(MSource source, String url) async {
// TODO: implement
}
// For manga pages
@override
Future<List<String>> getPageList(MSource source, String url) {
// TODO: implement
}
@override
List<dynamic> getFilterList() {
// TODO: implement
}
}
TestSource main() {
return TestSource();
}
''';

View file

@ -1,8 +1,12 @@
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/sources/source_test.dart';
Source? getSource(String lang, String name) {
if (useTestSourceCode) {
return testSourceModel;
}
try {
final sourcesList = isar.sources.filter().idIsNotNull().findAllSync();
return sourcesList.firstWhere(

View file

@ -10,5 +10,7 @@
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
</dict>
</plist>