first implementation finished

This commit is contained in:
Fabian Freund
2024-04-22 11:21:01 +02:00
parent 1a13ca0795
commit 0e1972242a
102 changed files with 7192 additions and 55 deletions
@@ -0,0 +1,73 @@
import 'package:exceptions/exceptions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:html/dom.dart';
import 'package:html/parser.dart' as html_parser;
import 'package:http/http.dart' as http;
import 'package:kagi_bang_bang/core/http_error_handler.dart';
import 'package:kagi_bang_bang/domain/entities/web_page_info.dart';
import 'package:kagi_bang_bang/features/web_view/utils/favicon_helper.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'generic_website.g.dart';
@Riverpod(keepAlive: true)
class GenericWebsiteService extends _$GenericWebsiteService {
late http.Client _client;
@override
void build() {
_client = http.Client();
}
static Iterable<Favicon> _extractFavicons(Uri url, Document document) sync* {
final links = document.querySelectorAll(
'link[rel="icon"], link[rel="shortcut icon"], link[rel="apple-touch-icon"]',
);
for (final link in links) {
final href = link.attributes['href'];
if (href != null) {
// Attempt to parse height and width if available
int? height;
int? width;
if (link.attributes['sizes'] case final String sizes) {
final dimensions = sizes.split('x');
if (dimensions.length == 2) {
height = int.tryParse(dimensions[0]);
width = int.tryParse(dimensions[1]);
}
}
yield Favicon(
url: WebUri.uri(url.resolve(href)),
rel: link.attributes['rel'],
width: width,
height: height,
);
}
}
}
Future<Result<WebPageInfo>> getInfo(Uri url) async {
return Result.fromAsync(
() async {
final response = await _client.get(url);
return await compute(
(args) {
final document = html_parser.parse(args[0]);
final url = Uri.parse(args[1]);
final title = document.querySelector('title')?.text;
final favicon = choseFavicon(_extractFavicons(url, document));
return WebPageInfo(url: url, title: title, favicon: favicon)
.toJson();
},
[response.body, url.toString()],
).then(WebPageInfo.fromJson);
},
exceptionHandler: handleHttpError,
);
}
}
@@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'generic_website.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$genericWebsiteServiceHash() =>
r'd3d5ec8600842eb2b7fa40f248e5e448c96e987f';
/// See also [GenericWebsiteService].
@ProviderFor(GenericWebsiteService)
final genericWebsiteServiceProvider =
NotifierProvider<GenericWebsiteService, void>.internal(
GenericWebsiteService.new,
name: r'genericWebsiteServiceProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$genericWebsiteServiceHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$GenericWebsiteService = Notifier<void>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member