add uri normalization
This commit is contained in:
@@ -29,4 +29,14 @@ extension UriX on Uri {
|
||||
bool get isHttp => isScheme('http');
|
||||
bool get isHttps => isScheme('https');
|
||||
bool get isHttpOrHttps => isHttp || isHttps;
|
||||
|
||||
/// Removes a bare root path (`/`) when there is no query or fragment, so
|
||||
/// that `https://example.com/` and `https://example.com` are treated as
|
||||
/// equivalent.
|
||||
Uri get normalized {
|
||||
if (path == '/' && !hasQuery && !hasFragment) {
|
||||
return replace(path: '');
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,8 @@ class SearchScreen extends HookConsumerWidget {
|
||||
if (startedWithUrl) {
|
||||
hasUserModifiedInput.value = text != initialSearchText;
|
||||
}
|
||||
isUrlInput.value = text.isNotEmpty &&
|
||||
isUrlInput.value =
|
||||
text.isNotEmpty &&
|
||||
classifyAddressBarInput(text) is NavigateInputClassification;
|
||||
},
|
||||
);
|
||||
@@ -371,26 +372,18 @@ class SearchScreen extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
final emptyStateWidgets = <SearchModuleType, Widget>{
|
||||
SearchModuleType.topSites: TopSitesSection(
|
||||
onUriSelected: openUriInTab,
|
||||
),
|
||||
SearchModuleType.topSites: TopSitesSection(onUriSelected: openUriInTab),
|
||||
SearchModuleType.recentArticles: RecentFeedArticlesSection(
|
||||
onArticleSelected: (article) {
|
||||
unawaited(
|
||||
FeedArticleRoute(articleId: article.id).push(context),
|
||||
);
|
||||
FeedArticleRoute(articleId: article.id).pushReplacement(context);
|
||||
},
|
||||
),
|
||||
SearchModuleType.recentTabs: RecentTabsSection(
|
||||
onTabSelected: (tabId) async {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectTab(tabId);
|
||||
await ref.read(tabRepositoryProvider.notifier).selectTab(tabId);
|
||||
|
||||
if (context.mounted) {
|
||||
ref
|
||||
.read(bottomSheetControllerProvider.notifier)
|
||||
.requestDismiss();
|
||||
ref.read(bottomSheetControllerProvider.notifier).requestDismiss();
|
||||
const BrowserRoute().go(context);
|
||||
}
|
||||
},
|
||||
@@ -436,9 +429,7 @@ class SearchScreen extends HookConsumerWidget {
|
||||
};
|
||||
|
||||
final searchWidgets = <SearchModuleType, Widget>{
|
||||
SearchModuleType.tabs: TabSearch(
|
||||
searchTextListenable: sampledSearchText,
|
||||
),
|
||||
SearchModuleType.tabs: TabSearch(searchTextListenable: sampledSearchText),
|
||||
SearchModuleType.bookmarks: BookmarkSearch(
|
||||
searchTextListenable: sampledSearchText,
|
||||
onUriSelected: openUriInTab,
|
||||
@@ -671,9 +662,7 @@ class SearchScreen extends HookConsumerWidget {
|
||||
(!isUrlInput.value ||
|
||||
entry.type != SearchModuleType.articles))
|
||||
searchWidgets[entry.type]!,
|
||||
const _CustomizeSectionsButton(
|
||||
group: SearchModuleGroup.search,
|
||||
),
|
||||
const _CustomizeSectionsButton(group: SearchModuleGroup.search),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:weblibre/extensions/uri.dart';
|
||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/daos/top_site.drift.dart';
|
||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.dart';
|
||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/definitions.drift.dart';
|
||||
@@ -42,7 +43,8 @@ class TopSiteDao extends DatabaseAccessor<TopSiteDatabase>
|
||||
}
|
||||
|
||||
Future<TopSiteData?> getPersistedTopSiteByUrl(Uri url) {
|
||||
return (db.topSite.select()..where((t) => t.url.equalsValue(url)))
|
||||
return (db.topSite.select()
|
||||
..where((t) => t.url.equalsValue(url.normalized)))
|
||||
.getSingleOrNull();
|
||||
}
|
||||
|
||||
@@ -63,7 +65,7 @@ class TopSiteDao extends DatabaseAccessor<TopSiteDatabase>
|
||||
TopSiteCompanion.insert(
|
||||
id: id,
|
||||
title: title,
|
||||
url: url,
|
||||
url: url.normalized,
|
||||
source: StoredTopSiteSource.pinned,
|
||||
orderKey: orderKey,
|
||||
createdAt: DateTime.now(),
|
||||
@@ -83,7 +85,7 @@ class TopSiteDao extends DatabaseAccessor<TopSiteDatabase>
|
||||
required Uri url,
|
||||
}) {
|
||||
return (db.topSite.update()..where((t) => t.id.equals(id))).write(
|
||||
TopSiteCompanion(title: Value(title), url: Value(url)),
|
||||
TopSiteCompanion(title: Value(title), url: Value(url.normalized)),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+9
-4
@@ -22,6 +22,7 @@ import 'dart:async';
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:weblibre/core/uuid.dart';
|
||||
import 'package:weblibre/extensions/uri.dart';
|
||||
import 'package:weblibre/features/geckoview/features/history/domain/repositories/history.dart';
|
||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/definitions.drift.dart';
|
||||
import 'package:weblibre/features/geckoview/features/top_sites/data/entities/stored_top_site_source.dart';
|
||||
@@ -55,7 +56,7 @@ class TopSiteRepository extends _$TopSiteRepository {
|
||||
TopSiteCompanion.insert(
|
||||
id: uuid.v7(),
|
||||
title: seeds[i].title,
|
||||
url: seeds[i].url,
|
||||
url: seeds[i].url.normalized,
|
||||
source: StoredTopSiteSource.seeded,
|
||||
orderKey: orderKey,
|
||||
createdAt: now,
|
||||
@@ -80,7 +81,9 @@ class TopSiteRepository extends _$TopSiteRepository {
|
||||
final remaining = targetCount - persisted.length;
|
||||
final historyItems = await _getHistoryItems(
|
||||
limit: remaining,
|
||||
excludeUrls: persisted.map((s) => s.url.toString()).toSet(),
|
||||
excludeUrls: persisted
|
||||
.map((s) => s.url.normalized.toString())
|
||||
.toSet(),
|
||||
);
|
||||
|
||||
return [...persisted, ...historyItems];
|
||||
@@ -103,7 +106,9 @@ class TopSiteRepository extends _$TopSiteRepository {
|
||||
final remaining = targetCount - persistedItems.length;
|
||||
final historyItems = await _getHistoryItems(
|
||||
limit: remaining,
|
||||
excludeUrls: persistedItems.map((s) => s.url.toString()).toSet(),
|
||||
excludeUrls: persistedItems
|
||||
.map((s) => s.url.normalized.toString())
|
||||
.toSet(),
|
||||
);
|
||||
|
||||
return [...persistedItems, ...historyItems];
|
||||
@@ -259,7 +264,7 @@ class TopSiteRepository extends _$TopSiteRepository {
|
||||
final uri = Uri.tryParse(site.url);
|
||||
if (uri == null) continue;
|
||||
|
||||
if (excludeUrls.contains(uri.toString())) continue;
|
||||
if (excludeUrls.contains(uri.normalized.toString())) continue;
|
||||
|
||||
final title = (site.title?.trim().isNotEmpty == true)
|
||||
? site.title!.trim()
|
||||
|
||||
Reference in New Issue
Block a user