good state
This commit is contained in:
@@ -975,6 +975,7 @@ class ArticleView extends ViewInfo<ArticleView, FeedArticle>
|
||||
contentMarkdown,
|
||||
contentPlain,
|
||||
icon,
|
||||
siteLink,
|
||||
];
|
||||
@override
|
||||
String get aliasedName => _alias ?? entityName;
|
||||
@@ -983,7 +984,7 @@ class ArticleView extends ViewInfo<ArticleView, FeedArticle>
|
||||
@override
|
||||
Map<SqlDialect, String> get createViewStatements => {
|
||||
SqlDialect.sqlite:
|
||||
'CREATE VIEW article_view AS SELECT a.*, f.icon FROM article AS a INNER JOIN feed AS f ON f.url = a.feed_id',
|
||||
'CREATE VIEW article_view AS SELECT a.*, f.icon, f.site_link FROM article AS a INNER JOIN feed AS f ON f.url = a.feed_id',
|
||||
};
|
||||
@override
|
||||
ArticleView get asDslTable => this;
|
||||
@@ -1071,6 +1072,12 @@ class ArticleView extends ViewInfo<ArticleView, FeedArticle>
|
||||
data['${effectivePrefix}icon'],
|
||||
),
|
||||
),
|
||||
siteLink: Feed.$convertersiteLinkn.fromSql(
|
||||
attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}site_link'],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1181,6 +1188,13 @@ class ArticleView extends ViewInfo<ArticleView, FeedArticle>
|
||||
true,
|
||||
type: DriftSqlType.string,
|
||||
).withConverter<Uri?>(Feed.$convertericonn);
|
||||
late final GeneratedColumnWithTypeConverter<Uri?, String> siteLink =
|
||||
GeneratedColumn<String>(
|
||||
'site_link',
|
||||
aliasedName,
|
||||
true,
|
||||
type: DriftSqlType.string,
|
||||
).withConverter<Uri?>(Feed.$convertersiteLinkn);
|
||||
@override
|
||||
ArticleView createAlias(String alias) {
|
||||
return ArticleView(attachedDatabase, alias);
|
||||
|
||||
@@ -41,6 +41,8 @@ abstract class _$FeedArticleCWProxy {
|
||||
|
||||
FeedArticle icon(Uri? icon);
|
||||
|
||||
FeedArticle siteLink(Uri? siteLink);
|
||||
|
||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `FeedArticle(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||
///
|
||||
/// Usage
|
||||
@@ -65,6 +67,7 @@ abstract class _$FeedArticleCWProxy {
|
||||
String? contentMarkdown,
|
||||
String? contentPlain,
|
||||
Uri? icon,
|
||||
Uri? siteLink,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -131,6 +134,9 @@ class _$FeedArticleCWProxyImpl implements _$FeedArticleCWProxy {
|
||||
@override
|
||||
FeedArticle icon(Uri? icon) => this(icon: icon);
|
||||
|
||||
@override
|
||||
FeedArticle siteLink(Uri? siteLink) => this(siteLink: siteLink);
|
||||
|
||||
@override
|
||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `FeedArticle(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||
///
|
||||
@@ -156,6 +162,7 @@ class _$FeedArticleCWProxyImpl implements _$FeedArticleCWProxy {
|
||||
Object? contentMarkdown = const $CopyWithPlaceholder(),
|
||||
Object? contentPlain = const $CopyWithPlaceholder(),
|
||||
Object? icon = const $CopyWithPlaceholder(),
|
||||
Object? siteLink = const $CopyWithPlaceholder(),
|
||||
}) {
|
||||
return FeedArticle(
|
||||
id:
|
||||
@@ -243,6 +250,11 @@ class _$FeedArticleCWProxyImpl implements _$FeedArticleCWProxy {
|
||||
? _value.icon
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: icon as Uri?,
|
||||
siteLink:
|
||||
siteLink == const $CopyWithPlaceholder()
|
||||
? _value.siteLink
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: siteLink as Uri?,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -293,6 +305,8 @@ FeedArticle _$FeedArticleFromJson(Map<String, dynamic> json) => FeedArticle(
|
||||
contentMarkdown: json['contentMarkdown'] as String?,
|
||||
contentPlain: json['contentPlain'] as String?,
|
||||
icon: json['icon'] == null ? null : Uri.parse(json['icon'] as String),
|
||||
siteLink:
|
||||
json['siteLink'] == null ? null : Uri.parse(json['siteLink'] as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$FeedArticleToJson(FeedArticle instance) =>
|
||||
@@ -314,4 +328,5 @@ Map<String, dynamic> _$FeedArticleToJson(FeedArticle instance) =>
|
||||
'contentMarkdown': instance.contentMarkdown,
|
||||
'contentPlain': instance.contentPlain,
|
||||
'icon': instance.icon?.toString(),
|
||||
'siteLink': instance.siteLink?.toString(),
|
||||
};
|
||||
|
||||
@@ -684,7 +684,7 @@ class _FetchWebFeedProviderElement
|
||||
Uri get url => (origin as FetchWebFeedProvider).url;
|
||||
}
|
||||
|
||||
String _$articleSearchHash() => r'8bf2c4aa8d8b3918be8a416909535682abfbab35';
|
||||
String _$articleSearchHash() => r'cc59a5d3c4b926db9f03ed96db592965ff925b04';
|
||||
|
||||
abstract class _$ArticleSearch
|
||||
extends BuildlessAutoDisposeStreamNotifier<List<FeedArticle>> {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import 'package:lensai/core/logger.dart';
|
||||
import 'package:lensai/extensions/nullable.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'add_dialog_blocking.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class AddFeedDialogBlocking extends _$AddFeedDialogBlocking {
|
||||
DateTime? _lastIgnore;
|
||||
final _ignoredUrls = <Uri, DateTime>{};
|
||||
|
||||
void ignore(Uri url) {
|
||||
final date = DateTime.now();
|
||||
|
||||
_lastIgnore = date;
|
||||
_ignoredUrls[url] = date;
|
||||
}
|
||||
|
||||
bool canPush(Uri url) {
|
||||
if (_lastIgnore.mapNotNull(
|
||||
(last) =>
|
||||
DateTime.now().difference(last) <= const Duration(seconds: 30),
|
||||
) ??
|
||||
false) {
|
||||
logger.i('Blocking add feed default timeout for $url');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_ignoredUrls[url].mapNotNull(
|
||||
(last) =>
|
||||
DateTime.now().difference(last) <= const Duration(minutes: 5),
|
||||
) ??
|
||||
false) {
|
||||
logger.i('Blocking add feed url specific for $url');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
void build() {}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'add_dialog_blocking.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$addFeedDialogBlockingHash() =>
|
||||
r'513071d5e507dd292df6b4a3ee3ef7d2217db5bb';
|
||||
|
||||
/// See also [AddFeedDialogBlocking].
|
||||
@ProviderFor(AddFeedDialogBlocking)
|
||||
final addFeedDialogBlockingProvider =
|
||||
NotifierProvider<AddFeedDialogBlocking, void>.internal(
|
||||
AddFeedDialogBlocking.new,
|
||||
name: r'addFeedDialogBlockingProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$addFeedDialogBlockingHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AddFeedDialogBlocking = 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, deprecated_member_use_from_same_package
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:lensai/core/logger.dart';
|
||||
import 'package:lensai/extensions/nullable.dart';
|
||||
import 'package:lensai/features/web_feed/data/models/feed_article.dart';
|
||||
import 'package:lensai/features/web_feed/data/providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
@@ -29,10 +28,10 @@ class ArticleContentProcessorService extends _$ArticleContentProcessorService {
|
||||
articles
|
||||
.mapIndexed(
|
||||
(index, article) => article.copyWith(
|
||||
contentMarkdown: content[index].markdown.whenNotEmpty,
|
||||
contentPlain: content[index].plain.whenNotEmpty,
|
||||
summaryMarkdown: summary[index].markdown.whenNotEmpty,
|
||||
summaryPlain: summary[index].plain.whenNotEmpty,
|
||||
contentMarkdown: content[index].markdown ?? '',
|
||||
contentPlain: content[index].plain,
|
||||
summaryMarkdown: summary[index].markdown ?? '',
|
||||
summaryPlain: summary[index].plain,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
|
||||
@@ -7,7 +7,7 @@ part of 'article_content_processor.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$articleContentProcessorServiceHash() =>
|
||||
r'182cd89e38a0a9a86b7425c16ad2bd1fc39c6704';
|
||||
r'e7cc3da71f6dcf39b0c10df4dcd061f816d5c12e';
|
||||
|
||||
/// See also [ArticleContentProcessorService].
|
||||
@ProviderFor(ArticleContentProcessorService)
|
||||
|
||||
@@ -16,8 +16,9 @@ extension ParseRssCategory on List<RssCategory> {
|
||||
List<FeedCategory> toFeedCategories() {
|
||||
return where((category) => category.value.isNotEmpty)
|
||||
.map(
|
||||
(category) =>
|
||||
FeedCategory(id: '${category.domain} ${category.value}'.trim()),
|
||||
(category) => FeedCategory(
|
||||
id: '${category.domain ?? ''} ${category.value ?? ''}'.trim(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/core/routing/routes.dart';
|
||||
import 'package:lensai/features/web_feed/domain/providers/add_dialog_blocking.dart';
|
||||
import 'package:lensai/utils/form_validators.dart';
|
||||
import 'package:lensai/utils/uri_parser.dart' as uri_parser;
|
||||
|
||||
@@ -38,6 +39,16 @@ class AddFeedDialog extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
if (initialUri != null)
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(addFeedDialogBlockingProvider.notifier)
|
||||
.ignore(initialUri!);
|
||||
context.pop();
|
||||
},
|
||||
child: const Text('Ignore'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
|
||||
Reference in New Issue
Block a user