🌐 Localized the dashboard and the command pattle

This commit is contained in:
2025-12-21 12:37:27 +08:00
parent b0085c2ab0
commit 7a56e7882e
6 changed files with 607 additions and 279 deletions

View File

@@ -32,6 +32,7 @@
"fieldEmailAddressMustBeValid": "The email address must be valid.", "fieldEmailAddressMustBeValid": "The email address must be valid.",
"logout": "Logout", "logout": "Logout",
"updateYourProfile": "Profile Settings", "updateYourProfile": "Profile Settings",
"updateYourProfileDescription": "Adjust how you looks on the Solar Network.",
"accountBasicInfo": "Basic Info", "accountBasicInfo": "Basic Info",
"accountProfile": "Your Profile", "accountProfile": "Your Profile",
"saveChanges": "Save Changes", "saveChanges": "Save Changes",
@@ -69,15 +70,18 @@
"authFactorPin": "Pin Code", "authFactorPin": "Pin Code",
"authFactorPinDescription": "It consists of 6 digits. It cannot be used to log in. When performing some dangerous operations, the system will ask you to enter this PIN for confirmation.", "authFactorPinDescription": "It consists of 6 digits. It cannot be used to log in. When performing some dangerous operations, the system will ask you to enter this PIN for confirmation.",
"realms": "Realms", "realms": "Realms",
"realmsDescription": "Manage realms you've joined.",
"createRealm": "Create a Realm", "createRealm": "Create a Realm",
"createRealmHint": "Meet friends with same interests, build communities, and more.", "createRealmHint": "Meet friends with same interests, build communities, and more.",
"editRealm": "Edit Realm", "editRealm": "Edit Realm",
"deleteRealm": "Delete Realm", "deleteRealm": "Delete Realm",
"deleteRealmHint": "Are you sure to delete this realm? This will also deleted all the channels, publishers, and posts under this realm.", "deleteRealmHint": "Are you sure to delete this realm? This will also deleted all the channels, publishers, and posts under this realm.",
"explore": "Explore", "explore": "Explore",
"exploreDescription": "Explore contents on the Solar Network.",
"exploreFilterSubscriptions": "Subscriptions", "exploreFilterSubscriptions": "Subscriptions",
"exploreFilterFriends": "Friends", "exploreFilterFriends": "Friends",
"account": "Account", "account": "Account",
"accountDescription": "Information about your account.",
"name": "Name", "name": "Name",
"slug": "Slug", "slug": "Slug",
"slugHint": "The slug will be used in the URL to access this resource, it should be unique and URL safe.", "slugHint": "The slug will be used in the URL to access this resource, it should be unique and URL safe.",
@@ -86,6 +90,7 @@
"deleteChatRoom": "Delete Room", "deleteChatRoom": "Delete Room",
"deleteChatRoomHint": "Are you sure to delete this room? This action cannot be undone.", "deleteChatRoomHint": "Are you sure to delete this room? This action cannot be undone.",
"chat": "Chat", "chat": "Chat",
"chatDescription": "Group Chats and Direct Messages",
"chatTabAll": "All", "chatTabAll": "All",
"chatTabDirect": "Direct Messages", "chatTabDirect": "Direct Messages",
"chatTabGroup": "Group Chats", "chatTabGroup": "Group Chats",
@@ -192,7 +197,9 @@
"statusActivityTitle": "{} is {} {}", "statusActivityTitle": "{} is {} {}",
"statusActivityEndedTitle": "{} is {} {} until {}", "statusActivityEndedTitle": "{} is {} {} until {}",
"appSettings": "App Settings", "appSettings": "App Settings",
"appSettingsDescription": "Customize your app.",
"accountSettings": "Account Settings", "accountSettings": "Account Settings",
"accountSettingsDescription": "Manage your preferences on the Solar Network.",
"settings": "Settings", "settings": "Settings",
"language": "Language", "language": "Language",
"accountLanguageHint": "This language will be used for email and push notifications.", "accountLanguageHint": "This language will be used for email and push notifications.",
@@ -251,6 +258,7 @@
"translatorBadgeName": "Translator", "translatorBadgeName": "Translator",
"translatorBadgeDescription": "Helping translate Solar Network into different languages", "translatorBadgeDescription": "Helping translate Solar Network into different languages",
"wallet": "Wallet", "wallet": "Wallet",
"walletDescription": "Your source point wallet.",
"walletCurrencyPoints": "New Solar Points", "walletCurrencyPoints": "New Solar Points",
"walletCurrencyShortPoints": "NSP", "walletCurrencyShortPoints": "NSP",
"walletCurrencyGolds": "The Solar Dollars", "walletCurrencyGolds": "The Solar Dollars",
@@ -258,6 +266,7 @@
"retry": "Retry", "retry": "Retry",
"creatorHubUnselectedHint": "Pick / create a publisher to get started.", "creatorHubUnselectedHint": "Pick / create a publisher to get started.",
"relationships": "Relationships", "relationships": "Relationships",
"relationshipsDescription": "Friends and connections.",
"addFriend": "Send a Friend Request", "addFriend": "Send a Friend Request",
"addFriendShort": "Add as Friend", "addFriendShort": "Add as Friend",
"addFriendHint": "Add a friend to your relationship list.", "addFriendHint": "Add a friend to your relationship list.",
@@ -670,7 +679,9 @@
"publisherFeatureDevelopHint": "Currently, this feature is under active development, you need send a request to unlock this feature.", "publisherFeatureDevelopHint": "Currently, this feature is under active development, you need send a request to unlock this feature.",
"learnMore": "Learn More", "learnMore": "Learn More",
"webArticlesStand": "Article Stand", "webArticlesStand": "Article Stand",
"webArticlesStandDescription": "Explore external sites articles.",
"about": "About", "about": "About",
"aboutDescription": "Learn more about the Solar Network.",
"somethingWentWrong": "Something went wrong", "somethingWentWrong": "Something went wrong",
"editedAt": "Edited at {}", "editedAt": "Edited at {}",
"addAudio": "Add audio", "addAudio": "Add audio",
@@ -691,6 +702,7 @@
"sharePostPhoto": "Share Post as Photo", "sharePostPhoto": "Share Post as Photo",
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?", "wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
"abuseReports": "Abuse Reports", "abuseReports": "Abuse Reports",
"abuseReportsDescription": "View and manage abuse reports.",
"membershipCancel": "Cancel Membership", "membershipCancel": "Cancel Membership",
"membershipCancelConfirm": "Are you sure to cancel your membership?", "membershipCancelConfirm": "Are you sure to cancel your membership?",
"membershipCancelHint": "Are you sure to cancel your membership? You will not be charged again. Your membership will remain active until the end of the current billing period. And you will not able to resubscribe until the end of the current subscription ends.", "membershipCancelHint": "Are you sure to cancel your membership? You will not be charged again. Your membership will remain active until the end of the current billing period. And you will not able to resubscribe until the end of the current subscription ends.",
@@ -762,6 +774,7 @@
"publisherCannotBeEmpty": "Publisher cannot be empty", "publisherCannotBeEmpty": "Publisher cannot be empty",
"operationFailed": "Operation failed: {}", "operationFailed": "Operation failed: {}",
"stickerMarketplace": "Sticker Marketplace", "stickerMarketplace": "Sticker Marketplace",
"stickerMarketplaceDescription": "Browse and add sticker packs from the Solar Network marketplace.",
"stickerPackAdded": "Sticker pack added to your collection", "stickerPackAdded": "Sticker pack added to your collection",
"stickerPackRemoved": "Sticker pack removed from your collection", "stickerPackRemoved": "Sticker pack removed from your collection",
"addPack": "Add Pack", "addPack": "Add Pack",
@@ -789,6 +802,7 @@
"joinedAt": "Joined at {}", "joinedAt": "Joined at {}",
"searchAccounts": "Search accounts...", "searchAccounts": "Search accounts...",
"webFeeds": "Web Feeds", "webFeeds": "Web Feeds",
"webFeedsDescription": "Browse and subscribe to web feeds from the Solar Network.",
"polls": "Polls", "polls": "Polls",
"sharePostSlogan": "Explore more on the Solar Network", "sharePostSlogan": "Explore more on the Solar Network",
"filesListAdditional": { "filesListAdditional": {
@@ -867,6 +881,7 @@
"contactMethodPublic": "Public", "contactMethodPublic": "Public",
"contactMethodPrivate": "Private", "contactMethodPrivate": "Private",
"discoverRealms": "Realms", "discoverRealms": "Realms",
"discoverRealmsDescription": "Discover new realms and join them.",
"discoverPublishers": "Publishers", "discoverPublishers": "Publishers",
"discoverShuffledPost": "Random Posts", "discoverShuffledPost": "Random Posts",
"projects": "Projects", "projects": "Projects",
@@ -910,7 +925,9 @@
"fileHash": "File Hash", "fileHash": "File Hash",
"exifData": "EXIF Data", "exifData": "EXIF Data",
"postShuffle": "Shuffle Posts", "postShuffle": "Shuffle Posts",
"postShuffleDescription": "Shuffle posts to see the posts randomly.",
"leveling": "Leveling", "leveling": "Leveling",
"levelingDescription": "See your leveling progress and history.",
"levelingHistory": "Leveling History", "levelingHistory": "Leveling History",
"stellarProgram": "Stellar Program", "stellarProgram": "Stellar Program",
"socialCredits": "Social Credits", "socialCredits": "Social Credits",
@@ -1053,6 +1070,7 @@
"fileSizeExceeded": "File size exceeds the maximum limit of {}", "fileSizeExceeded": "File size exceeds the maximum limit of {}",
"fileTypeNotAccepted": "File type is not accepted by this pool", "fileTypeNotAccepted": "File type is not accepted by this pool",
"files": "Files", "files": "Files",
"filesDescription": "Manage your files on the Solar Network Drive.",
"confirmDeleteFile": "Are you sure you want to delete this file?", "confirmDeleteFile": "Are you sure you want to delete this file?",
"deleteFile": "Delete File", "deleteFile": "Delete File",
"failedToDeleteFile": "Failed to delete file", "failedToDeleteFile": "Failed to delete file",
@@ -1319,6 +1337,7 @@
"backToHub": "Back to Hub", "backToHub": "Back to Hub",
"advancedFilters": "Advanced Filters", "advancedFilters": "Advanced Filters",
"searchPosts": "Search Posts", "searchPosts": "Search Posts",
"searchPostsDescription": "Search posts by title, content, or else.",
"sortBy": "Sort by", "sortBy": "Sort by",
"fromDate": "From Date", "fromDate": "From Date",
"toDate": "To Date", "toDate": "To Date",
@@ -1502,58 +1521,10 @@
"recentChats": "Recent Chats", "recentChats": "Recent Chats",
"noFeaturedPostsAvailable": "No featured posts available", "noFeaturedPostsAvailable": "No featured posts available",
"searchChatsAndPages": "Search chats and pages...", "searchChatsAndPages": "Search chats and pages...",
"routeDashboard": "Dashboard", "dashboard": "Dashboard",
"routeDashboardDesc": "Main dashboard", "dashboardDescription": "All your data in one place.",
"routeExplore": "Explore", "postTagsCategories": "Post Tags and Categories",
"routeExploreDesc": "Discover content", "postTagsCategoriesDescription": "Browse posts by category and tags.",
"routePostSearch": "Post Search", "debugLogs": "Debug Logs",
"routePostSearchDesc": "Search posts", "debugLogsDescription": "View debug logs for troubleshooting."
"routePostShuffle": "Post Shuffle",
"routePostShuffleDesc": "Random posts",
"routePostCategories": "Post Categories",
"routePostCategoriesDesc": "Browse categories",
"routeDiscoveryRealms": "Discovery Realms",
"routeDiscoveryRealmsDesc": "Explore realms",
"routeChat": "Chat",
"routeChatDesc": "Messages and conversations",
"routeRealms": "Realms",
"routeRealmsDesc": "Community realms",
"routeAccount": "Account",
"routeAccountDesc": "Your profile and settings",
"routeStickerMarketplace": "Sticker Marketplace",
"routeStickerMarketplaceDesc": "Browse sticker packs",
"routeWebFeeds": "Web Feeds",
"routeWebFeedsDesc": "RSS and web feeds",
"routeWallet": "Wallet",
"routeWalletDesc": "Your digital wallet",
"routeRelationships": "Relationships",
"routeRelationshipsDesc": "Friends and connections",
"routeUpdateProfile": "Update Profile",
"routeUpdateProfileDesc": "Edit your profile",
"routeLeveling": "Leveling",
"routeLevelingDesc": "Your progress and levels",
"routeAccountSettings": "Account Settings",
"routeAccountSettingsDesc": "App preferences",
"routeReports": "Reports",
"routeReportsDesc": "Your abuse reports",
"routeFiles": "Files",
"routeFilesDesc": "File manager",
"routeThought": "Thought",
"routeThoughtDesc": "AI assistant",
"routeCreatorHub": "Creator Hub",
"routeCreatorHubDesc": "Content creation tools",
"routeDeveloperHub": "Developer Hub",
"routeDeveloperHubDesc": "Developer tools",
"routeLogs": "Logs",
"routeLogsDesc": "Application logs",
"routeArticles": "Articles",
"routeArticlesDesc": "Web articles",
"routeLogin": "Login",
"routeLoginDesc": "Sign in to your account",
"routeCreateAccount": "Create Account",
"routeCreateAccountDesc": "Create a new account",
"routeSettings": "Settings",
"routeSettingsDesc": "Application settings",
"routeAbout": "About",
"routeAboutDesc": "About this app"
} }

View File

@@ -1,5 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:material_symbols_icons/symbols.dart';
part 'route_item.freezed.dart'; part 'route_item.freezed.dart';
@@ -9,6 +11,221 @@ sealed class RouteItem with _$RouteItem {
required String name, required String name,
required String path, required String path,
required String description, required String description,
@Default([]) List<String> searchableAliases,
required IconData icon, required IconData icon,
}) = _RouteItem; }) = _RouteItem;
} }
final List<RouteItem> kAvailableRoutes = [
RouteItem(
name: 'dashboard'.tr(),
path: '/',
description: 'dashboardDescription'.tr(),
searchableAliases: ['dashboard', 'home'],
icon: Symbols.home,
),
RouteItem(
name: 'explore'.tr(),
path: '/explore',
description: 'exploreDescription'.tr(),
searchableAliases: ['explore', 'discover'],
icon: Symbols.explore,
),
RouteItem(
name: 'searchPosts'.tr(),
path: '/posts/search',
description: 'searchPostsDescription'.tr(),
searchableAliases: ['search', 'posts'],
icon: Symbols.search,
),
RouteItem(
name: 'postShuffle'.tr(),
path: '/posts/shuffle',
description: 'postShuffleDescription'.tr(),
searchableAliases: ['shuffle', 'random', 'posts'],
icon: Symbols.shuffle,
),
RouteItem(
name: 'postTagsCategories'.tr(),
path: '/posts/categories',
description: 'postTagsCategoriesDescription'.tr(),
searchableAliases: ['tags', 'categories', 'posts'],
icon: Symbols.category,
),
RouteItem(
name: 'discoverRealms'.tr(),
path: '/discovery/realms',
description: 'discoverRealmsDescription'.tr(),
searchableAliases: ['realms', 'groups', 'communities'],
icon: Symbols.public,
),
RouteItem(
name: 'chat'.tr(),
path: '/chat',
description: 'chatDescription'.tr(),
searchableAliases: ['chat', 'messages', 'conversations', 'dm'],
icon: Symbols.chat,
),
RouteItem(
name: 'realms'.tr(),
path: '/realms',
description: 'realmsDescription'.tr(),
searchableAliases: ['realms', 'groups', 'communities'],
icon: Symbols.group,
),
RouteItem(
name: 'account'.tr(),
path: '/account',
description: 'accountDescription'.tr(),
searchableAliases: ['account', 'me', 'profile', 'user'],
icon: Symbols.person,
),
RouteItem(
name: 'stickerMarketplace'.tr(),
path: '/stickers',
description: 'stickerMarketplaceDescription'.tr(),
searchableAliases: ['stickers', 'marketplace', 'emojis', 'emojis'],
icon: Symbols.emoji_emotions,
),
RouteItem(
name: 'webFeeds'.tr(),
path: '/feeds',
description: 'webFeedsDescription'.tr(),
searchableAliases: ['feeds', 'web feeds', 'rss', 'news'],
icon: Symbols.feed,
),
RouteItem(
name: 'wallet'.tr(),
path: '/account/wallet',
description: 'walletDescription'.tr(),
searchableAliases: [
'wallet',
'balance',
'money',
'source points',
'gold points',
'nsp',
'shd',
],
icon: Symbols.account_balance_wallet,
),
RouteItem(
name: 'relationships'.tr(),
path: '/account/relationships',
description: 'relationshipsDescription'.tr(),
searchableAliases: ['relationships', 'friends', 'block list', 'blocks'],
icon: Symbols.people,
),
RouteItem(
name: 'updateYourProfile'.tr(),
path: '/account/me/update',
description: 'updateYourProfileDescription'.tr(),
searchableAliases: ['profile', 'update', 'edit', 'my profile'],
icon: Symbols.edit,
),
RouteItem(
name: 'leveling'.tr(),
path: '/account/me/leveling',
description: 'levelingDescription'.tr(),
searchableAliases: [
'leveling',
'level',
'levels',
'subscriptions',
'social credits',
],
icon: Symbols.trending_up,
),
RouteItem(
name: 'accountSettings'.tr(),
path: '/account/me/settings',
description: 'accountSettingsDescription'.tr(),
searchableAliases: [
'settings',
'preferences',
'account',
'account settings',
],
icon: Symbols.settings,
),
RouteItem(
name: 'abuseReports'.tr(),
path: '/safety/reports/me',
description: 'abuseReportsDescription'.tr(),
searchableAliases: ['reports', 'abuse', 'safety'],
icon: Symbols.report,
),
RouteItem(
name: 'files'.tr(),
path: '/files',
description: 'filesDescription'.tr(),
searchableAliases: ['files', 'folders', 'storage', 'drive', 'cloud'],
icon: Symbols.folder,
),
RouteItem(
name: 'aiThought'.tr(),
path: '/thought',
description: 'aiThoughtTitle'.tr(),
searchableAliases: ['thought', 'ai', 'ai thought'],
icon: Symbols.psychology,
),
RouteItem(
name: 'creatorHub'.tr(),
path: '/creators',
description: 'creatorHubDescription'.tr(),
searchableAliases: ['creators', 'hub', 'creator hub', 'creators hub'],
icon: Symbols.create,
),
RouteItem(
name: 'developerPortal'.tr(),
path: '/developers',
description: 'developerPortalDescription'.tr(),
searchableAliases: [
'developers',
'dev',
'developer',
'developer hub',
'developers hub',
],
icon: Symbols.code,
),
RouteItem(
name: 'debugLogs'.tr(),
path: '/logs',
description: 'debugLogsDescription'.tr(),
searchableAliases: ['logs', 'debug', 'debug logs'],
icon: Symbols.bug_report,
),
RouteItem(
name: 'webArticlesStand'.tr(),
path: '/feeds/articles',
description: 'webArticlesStandDescription'.tr(),
searchableAliases: ['articles', 'stand', 'feed', 'web feed'],
icon: Symbols.article,
),
RouteItem(
name: 'appSettings'.tr(),
path: '/settings',
description: 'appSettingsDescription'.tr(),
searchableAliases: ['settings', 'preferences', 'app', 'app settings'],
icon: Symbols.settings,
),
RouteItem(
name: 'about'.tr(),
path: '/about',
description: 'about'.tr(),
searchableAliases: ['about', 'info'],
icon: Symbols.info,
),
];
@freezed
sealed class SpecialAction with _$SpecialAction {
const factory SpecialAction({
required String name,
required String description,
required IconData icon,
required VoidCallback action,
@Default([]) List<String> searchableAliases,
}) = _SpecialAction;
}

View File

@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
/// @nodoc /// @nodoc
mixin _$RouteItem { mixin _$RouteItem {
String get name; String get path; String get description; IconData get icon; String get name; String get path; String get description; List<String> get searchableAliases; IconData get icon;
/// Create a copy of RouteItem /// Create a copy of RouteItem
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@@ -25,16 +25,16 @@ $RouteItemCopyWith<RouteItem> get copyWith => _$RouteItemCopyWithImpl<RouteItem>
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is RouteItem&&(identical(other.name, name) || other.name == name)&&(identical(other.path, path) || other.path == path)&&(identical(other.description, description) || other.description == description)&&(identical(other.icon, icon) || other.icon == icon)); return identical(this, other) || (other.runtimeType == runtimeType&&other is RouteItem&&(identical(other.name, name) || other.name == name)&&(identical(other.path, path) || other.path == path)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.searchableAliases, searchableAliases)&&(identical(other.icon, icon) || other.icon == icon));
} }
@override @override
int get hashCode => Object.hash(runtimeType,name,path,description,icon); int get hashCode => Object.hash(runtimeType,name,path,description,const DeepCollectionEquality().hash(searchableAliases),icon);
@override @override
String toString() { String toString() {
return 'RouteItem(name: $name, path: $path, description: $description, icon: $icon)'; return 'RouteItem(name: $name, path: $path, description: $description, searchableAliases: $searchableAliases, icon: $icon)';
} }
@@ -45,7 +45,7 @@ abstract mixin class $RouteItemCopyWith<$Res> {
factory $RouteItemCopyWith(RouteItem value, $Res Function(RouteItem) _then) = _$RouteItemCopyWithImpl; factory $RouteItemCopyWith(RouteItem value, $Res Function(RouteItem) _then) = _$RouteItemCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
String name, String path, String description, IconData icon String name, String path, String description, List<String> searchableAliases, IconData icon
}); });
@@ -62,12 +62,13 @@ class _$RouteItemCopyWithImpl<$Res>
/// Create a copy of RouteItem /// Create a copy of RouteItem
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? name = null,Object? path = null,Object? description = null,Object? icon = null,}) { @pragma('vm:prefer-inline') @override $Res call({Object? name = null,Object? path = null,Object? description = null,Object? searchableAliases = null,Object? icon = null,}) {
return _then(_self.copyWith( return _then(_self.copyWith(
name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
as String,path: null == path ? _self.path : path // ignore: cast_nullable_to_non_nullable as String,path: null == path ? _self.path : path // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,icon: null == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable as String,searchableAliases: null == searchableAliases ? _self.searchableAliases : searchableAliases // ignore: cast_nullable_to_non_nullable
as List<String>,icon: null == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable
as IconData, as IconData,
)); ));
} }
@@ -150,10 +151,10 @@ return $default(_that);case _:
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String name, String path, String description, IconData icon)? $default,{required TResult orElse(),}) {final _that = this; @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String name, String path, String description, List<String> searchableAliases, IconData icon)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) { switch (_that) {
case _RouteItem() when $default != null: case _RouteItem() when $default != null:
return $default(_that.name,_that.path,_that.description,_that.icon);case _: return $default(_that.name,_that.path,_that.description,_that.searchableAliases,_that.icon);case _:
return orElse(); return orElse();
} }
@@ -171,10 +172,10 @@ return $default(_that.name,_that.path,_that.description,_that.icon);case _:
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String name, String path, String description, IconData icon) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String name, String path, String description, List<String> searchableAliases, IconData icon) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _RouteItem(): case _RouteItem():
return $default(_that.name,_that.path,_that.description,_that.icon);} return $default(_that.name,_that.path,_that.description,_that.searchableAliases,_that.icon);}
} }
/// A variant of `when` that fallback to returning `null` /// A variant of `when` that fallback to returning `null`
/// ///
@@ -188,10 +189,10 @@ return $default(_that.name,_that.path,_that.description,_that.icon);}
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String name, String path, String description, IconData icon)? $default,) {final _that = this; @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String name, String path, String description, List<String> searchableAliases, IconData icon)? $default,) {final _that = this;
switch (_that) { switch (_that) {
case _RouteItem() when $default != null: case _RouteItem() when $default != null:
return $default(_that.name,_that.path,_that.description,_that.icon);case _: return $default(_that.name,_that.path,_that.description,_that.searchableAliases,_that.icon);case _:
return null; return null;
} }
@@ -203,12 +204,19 @@ return $default(_that.name,_that.path,_that.description,_that.icon);case _:
class _RouteItem implements RouteItem { class _RouteItem implements RouteItem {
const _RouteItem({required this.name, required this.path, required this.description, required this.icon}); const _RouteItem({required this.name, required this.path, required this.description, final List<String> searchableAliases = const [], required this.icon}): _searchableAliases = searchableAliases;
@override final String name; @override final String name;
@override final String path; @override final String path;
@override final String description; @override final String description;
final List<String> _searchableAliases;
@override@JsonKey() List<String> get searchableAliases {
if (_searchableAliases is EqualUnmodifiableListView) return _searchableAliases;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_searchableAliases);
}
@override final IconData icon; @override final IconData icon;
/// Create a copy of RouteItem /// Create a copy of RouteItem
@@ -221,16 +229,16 @@ _$RouteItemCopyWith<_RouteItem> get copyWith => __$RouteItemCopyWithImpl<_RouteI
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _RouteItem&&(identical(other.name, name) || other.name == name)&&(identical(other.path, path) || other.path == path)&&(identical(other.description, description) || other.description == description)&&(identical(other.icon, icon) || other.icon == icon)); return identical(this, other) || (other.runtimeType == runtimeType&&other is _RouteItem&&(identical(other.name, name) || other.name == name)&&(identical(other.path, path) || other.path == path)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other._searchableAliases, _searchableAliases)&&(identical(other.icon, icon) || other.icon == icon));
} }
@override @override
int get hashCode => Object.hash(runtimeType,name,path,description,icon); int get hashCode => Object.hash(runtimeType,name,path,description,const DeepCollectionEquality().hash(_searchableAliases),icon);
@override @override
String toString() { String toString() {
return 'RouteItem(name: $name, path: $path, description: $description, icon: $icon)'; return 'RouteItem(name: $name, path: $path, description: $description, searchableAliases: $searchableAliases, icon: $icon)';
} }
@@ -241,7 +249,7 @@ abstract mixin class _$RouteItemCopyWith<$Res> implements $RouteItemCopyWith<$Re
factory _$RouteItemCopyWith(_RouteItem value, $Res Function(_RouteItem) _then) = __$RouteItemCopyWithImpl; factory _$RouteItemCopyWith(_RouteItem value, $Res Function(_RouteItem) _then) = __$RouteItemCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
String name, String path, String description, IconData icon String name, String path, String description, List<String> searchableAliases, IconData icon
}); });
@@ -258,17 +266,287 @@ class __$RouteItemCopyWithImpl<$Res>
/// Create a copy of RouteItem /// Create a copy of RouteItem
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? name = null,Object? path = null,Object? description = null,Object? icon = null,}) { @override @pragma('vm:prefer-inline') $Res call({Object? name = null,Object? path = null,Object? description = null,Object? searchableAliases = null,Object? icon = null,}) {
return _then(_RouteItem( return _then(_RouteItem(
name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
as String,path: null == path ? _self.path : path // ignore: cast_nullable_to_non_nullable as String,path: null == path ? _self.path : path // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,icon: null == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable as String,searchableAliases: null == searchableAliases ? _self._searchableAliases : searchableAliases // ignore: cast_nullable_to_non_nullable
as List<String>,icon: null == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable
as IconData, as IconData,
)); ));
} }
}
/// @nodoc
mixin _$SpecialAction {
String get name; String get description; IconData get icon; VoidCallback get action; List<String> get searchableAliases;
/// Create a copy of SpecialAction
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SpecialActionCopyWith<SpecialAction> get copyWith => _$SpecialActionCopyWithImpl<SpecialAction>(this as SpecialAction, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SpecialAction&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.icon, icon) || other.icon == icon)&&(identical(other.action, action) || other.action == action)&&const DeepCollectionEquality().equals(other.searchableAliases, searchableAliases));
}
@override
int get hashCode => Object.hash(runtimeType,name,description,icon,action,const DeepCollectionEquality().hash(searchableAliases));
@override
String toString() {
return 'SpecialAction(name: $name, description: $description, icon: $icon, action: $action, searchableAliases: $searchableAliases)';
}
}
/// @nodoc
abstract mixin class $SpecialActionCopyWith<$Res> {
factory $SpecialActionCopyWith(SpecialAction value, $Res Function(SpecialAction) _then) = _$SpecialActionCopyWithImpl;
@useResult
$Res call({
String name, String description, IconData icon, VoidCallback action, List<String> searchableAliases
});
}
/// @nodoc
class _$SpecialActionCopyWithImpl<$Res>
implements $SpecialActionCopyWith<$Res> {
_$SpecialActionCopyWithImpl(this._self, this._then);
final SpecialAction _self;
final $Res Function(SpecialAction) _then;
/// Create a copy of SpecialAction
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? name = null,Object? description = null,Object? icon = null,Object? action = null,Object? searchableAliases = null,}) {
return _then(_self.copyWith(
name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,icon: null == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable
as IconData,action: null == action ? _self.action : action // ignore: cast_nullable_to_non_nullable
as VoidCallback,searchableAliases: null == searchableAliases ? _self.searchableAliases : searchableAliases // ignore: cast_nullable_to_non_nullable
as List<String>,
));
}
}
/// Adds pattern-matching-related methods to [SpecialAction].
extension SpecialActionPatterns on SpecialAction {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SpecialAction value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _SpecialAction() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SpecialAction value) $default,){
final _that = this;
switch (_that) {
case _SpecialAction():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SpecialAction value)? $default,){
final _that = this;
switch (_that) {
case _SpecialAction() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String name, String description, IconData icon, VoidCallback action, List<String> searchableAliases)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SpecialAction() when $default != null:
return $default(_that.name,_that.description,_that.icon,_that.action,_that.searchableAliases);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String name, String description, IconData icon, VoidCallback action, List<String> searchableAliases) $default,) {final _that = this;
switch (_that) {
case _SpecialAction():
return $default(_that.name,_that.description,_that.icon,_that.action,_that.searchableAliases);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String name, String description, IconData icon, VoidCallback action, List<String> searchableAliases)? $default,) {final _that = this;
switch (_that) {
case _SpecialAction() when $default != null:
return $default(_that.name,_that.description,_that.icon,_that.action,_that.searchableAliases);case _:
return null;
}
}
}
/// @nodoc
class _SpecialAction implements SpecialAction {
const _SpecialAction({required this.name, required this.description, required this.icon, required this.action, final List<String> searchableAliases = const []}): _searchableAliases = searchableAliases;
@override final String name;
@override final String description;
@override final IconData icon;
@override final VoidCallback action;
final List<String> _searchableAliases;
@override@JsonKey() List<String> get searchableAliases {
if (_searchableAliases is EqualUnmodifiableListView) return _searchableAliases;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_searchableAliases);
}
/// Create a copy of SpecialAction
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SpecialActionCopyWith<_SpecialAction> get copyWith => __$SpecialActionCopyWithImpl<_SpecialAction>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SpecialAction&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.icon, icon) || other.icon == icon)&&(identical(other.action, action) || other.action == action)&&const DeepCollectionEquality().equals(other._searchableAliases, _searchableAliases));
}
@override
int get hashCode => Object.hash(runtimeType,name,description,icon,action,const DeepCollectionEquality().hash(_searchableAliases));
@override
String toString() {
return 'SpecialAction(name: $name, description: $description, icon: $icon, action: $action, searchableAliases: $searchableAliases)';
}
}
/// @nodoc
abstract mixin class _$SpecialActionCopyWith<$Res> implements $SpecialActionCopyWith<$Res> {
factory _$SpecialActionCopyWith(_SpecialAction value, $Res Function(_SpecialAction) _then) = __$SpecialActionCopyWithImpl;
@override @useResult
$Res call({
String name, String description, IconData icon, VoidCallback action, List<String> searchableAliases
});
}
/// @nodoc
class __$SpecialActionCopyWithImpl<$Res>
implements _$SpecialActionCopyWith<$Res> {
__$SpecialActionCopyWithImpl(this._self, this._then);
final _SpecialAction _self;
final $Res Function(_SpecialAction) _then;
/// Create a copy of SpecialAction
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? name = null,Object? description = null,Object? icon = null,Object? action = null,Object? searchableAliases = null,}) {
return _then(_SpecialAction(
name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,icon: null == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable
as IconData,action: null == action ? _self.action : action // ignore: cast_nullable_to_non_nullable
as VoidCallback,searchableAliases: null == searchableAliases ? _self._searchableAliases : searchableAliases // ignore: cast_nullable_to_non_nullable
as List<String>,
));
}
} }
// dart format on // dart format on

View File

@@ -3,6 +3,7 @@ import 'dart:math' as math;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -61,12 +62,29 @@ class DashboardGrid extends HookConsumerWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
// Clock card spans full width // Clock card spans full width
ClockCard().padding(horizontal: isWide ? 24 : 16), if (isWide)
ClockCard().padding(horizontal: 24)
else
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Gap(8),
Expanded(child: ClockCard(compact: true)),
IconButton(
onPressed: () {
eventBus.fire(CommandPaletteTriggerEvent());
},
icon: const Icon(Symbols.search),
tooltip: 'searchAnything'.tr(),
),
],
).padding(horizontal: 24),
// Row with two cards side by side // Row with two cards side by side
if (isWide)
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: isWide ? 24 : 16), padding: EdgeInsets.symmetric(horizontal: isWide ? 24 : 16),
child: SearchBar( child: SearchBar(
hintText: 'Search Anything...', hintText: 'searchAnything'.tr(),
constraints: const BoxConstraints(minHeight: 56), constraints: const BoxConstraints(minHeight: 56),
leading: const Icon(Symbols.search).padding(horizontal: 24), leading: const Icon(Symbols.search).padding(horizontal: 24),
readOnly: true, readOnly: true,
@@ -190,7 +208,8 @@ class _DashboardGridNarrow extends HookConsumerWidget {
} }
class ClockCard extends HookConsumerWidget { class ClockCard extends HookConsumerWidget {
const ClockCard({super.key}); final bool compact;
const ClockCard({super.key, this.compact = false});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@@ -198,6 +217,12 @@ class ClockCard extends HookConsumerWidget {
final timer = useRef<Timer?>(null); final timer = useRef<Timer?>(null);
final nextNotableDay = ref.watch(nextNotableDayProvider); final nextNotableDay = ref.watch(nextNotableDayProvider);
// Determine icon based on time of day
final int hour = time.value.hour;
final IconData timeIcon = (hour >= 6 && hour < 18)
? Symbols.sunny_rounded
: Symbols.dark_mode_rounded;
useEffect(() { useEffect(() {
timer.value = Timer.periodic(const Duration(seconds: 1), (_) { timer.value = Timer.periodic(const Duration(seconds: 1), (_) {
time.value = DateTime.now(); time.value = DateTime.now();
@@ -213,14 +238,16 @@ class ClockCard extends HookConsumerWidget {
borderRadius: BorderRadius.all(Radius.circular(12)), borderRadius: BorderRadius.all(Radius.circular(12)),
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24), padding: compact
? EdgeInsets.zero
: const EdgeInsets.symmetric(horizontal: 24),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
children: [ children: [
Icon( Icon(
Symbols.schedule, timeIcon,
size: 32, size: 32,
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
), ),
@@ -321,9 +348,11 @@ class FeaturedPostCard extends HookConsumerWidget {
error: (error, stack) => Center(child: Text('Error: $error')), error: (error, stack) => Center(child: Text('Error: $error')),
data: (posts) { data: (posts) {
if (posts.isEmpty) { if (posts.isEmpty) {
return const Padding( return Padding(
padding: EdgeInsets.all(16), padding: EdgeInsets.all(16),
child: Center(child: Text('No featured posts available')), child: Center(
child: Text('noFeaturedPostsAvailable').tr(),
),
); );
} }
return PageView.builder( return PageView.builder(
@@ -384,7 +413,7 @@ class NotificationsCard extends HookConsumerWidget {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: Text( child: Text(
'Notifications', 'notifications'.tr(),
style: Theme.of(context).textTheme.titleMedium?.copyWith( style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -397,7 +426,7 @@ class NotificationsCard extends HookConsumerWidget {
error: (error, stack) => Center(child: Text('Error: $error')), error: (error, stack) => Center(child: Text('Error: $error')),
data: (notificationList) { data: (notificationList) {
if (notificationList.isEmpty) { if (notificationList.isEmpty) {
return const Center(child: Text('No notifications yet')); return Center(child: Text('noNotificationsYet').tr());
} }
// Get the most recent notification (first in the list) // Get the most recent notification (first in the list)
final recentNotification = notificationList.first; final recentNotification = notificationList.first;
@@ -406,7 +435,7 @@ class NotificationsCard extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'Most Recent', 'mostRecent'.tr(),
style: Theme.of(context).textTheme.bodySmall?.copyWith( style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
@@ -423,7 +452,7 @@ class NotificationsCard extends HookConsumerWidget {
}, },
), ),
Text( Text(
'Tap to view all notifications', 'tapToViewAllNotifications'.tr(),
style: Theme.of(context).textTheme.bodySmall?.copyWith( style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
@@ -460,7 +489,7 @@ class ChatListCard extends HookConsumerWidget {
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: Text( child: Text(
'Recent Chats', 'recentChats'.tr(),
style: Theme.of(context).textTheme.titleMedium?.copyWith( style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),

View File

@@ -20,190 +20,11 @@ import 'package:relative_time/relative_time.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:island/services/event_bus.dart'; import 'package:island/services/event_bus.dart';
class SpecialAction {
final String name;
final String description;
final IconData icon;
final VoidCallback action;
const SpecialAction({
required this.name,
required this.description,
required this.icon,
required this.action,
});
}
class CommandPattleWidget extends HookConsumerWidget { class CommandPattleWidget extends HookConsumerWidget {
final VoidCallback onDismiss; final VoidCallback onDismiss;
const CommandPattleWidget({super.key, required this.onDismiss}); const CommandPattleWidget({super.key, required this.onDismiss});
static final List<RouteItem> _availableRoutes = [
RouteItem(
name: 'Dashboard',
path: '/',
description: 'Main dashboard',
icon: Symbols.home,
),
RouteItem(
name: 'Explore',
path: '/explore',
description: 'Discover content',
icon: Symbols.explore,
),
RouteItem(
name: 'Post Search',
path: '/posts/search',
description: 'Search posts',
icon: Symbols.search,
),
RouteItem(
name: 'Post Shuffle',
path: '/posts/shuffle',
description: 'Random posts',
icon: Symbols.shuffle,
),
RouteItem(
name: 'Post Categories',
path: '/posts/categories',
description: 'Browse categories',
icon: Symbols.category,
),
RouteItem(
name: 'Discovery Realms',
path: '/discovery/realms',
description: 'Explore realms',
icon: Symbols.public,
),
RouteItem(
name: 'Chat',
path: '/chat',
description: 'Messages and conversations',
icon: Symbols.chat,
),
RouteItem(
name: 'Realms',
path: '/realms',
description: 'Community realms',
icon: Symbols.group,
),
RouteItem(
name: 'Account',
path: '/account',
description: 'Your profile and settings',
icon: Symbols.person,
),
RouteItem(
name: 'Sticker Marketplace',
path: '/stickers',
description: 'Browse sticker packs',
icon: Symbols.emoji_emotions,
),
RouteItem(
name: 'Web Feeds',
path: '/feeds',
description: 'RSS and web feeds',
icon: Symbols.feed,
),
RouteItem(
name: 'Wallet',
path: '/account/wallet',
description: 'Your digital wallet',
icon: Symbols.account_balance_wallet,
),
RouteItem(
name: 'Relationships',
path: '/account/relationships',
description: 'Friends and connections',
icon: Symbols.people,
),
RouteItem(
name: 'Update Profile',
path: '/account/me/update',
description: 'Edit your profile',
icon: Symbols.edit,
),
RouteItem(
name: 'Leveling',
path: '/account/me/leveling',
description: 'Your progress and levels',
icon: Symbols.trending_up,
),
RouteItem(
name: 'Account Settings',
path: '/account/me/settings',
description: 'App preferences',
icon: Symbols.settings,
),
RouteItem(
name: 'Reports',
path: '/safety/reports/me',
description: 'Your abuse reports',
icon: Symbols.report,
),
RouteItem(
name: 'Files',
path: '/files',
description: 'File manager',
icon: Symbols.folder,
),
RouteItem(
name: 'Thought',
path: '/thought',
description: 'AI assistant',
icon: Symbols.psychology,
),
RouteItem(
name: 'Creator Hub',
path: '/creators',
description: 'Content creation tools',
icon: Symbols.create,
),
RouteItem(
name: 'Developer Hub',
path: '/developers',
description: 'Developer tools',
icon: Symbols.code,
),
RouteItem(
name: 'Logs',
path: '/logs',
description: 'Application logs',
icon: Symbols.bug_report,
),
RouteItem(
name: 'Articles',
path: '/feeds/articles',
description: 'Web articles',
icon: Symbols.article,
),
RouteItem(
name: 'Login',
path: '/auth/login',
description: 'Sign in to your account',
icon: Symbols.login,
),
RouteItem(
name: 'Create Account',
path: '/auth/create-account',
description: 'Create a new account',
icon: Symbols.person_add,
),
RouteItem(
name: 'Settings',
path: '/settings',
description: 'Application settings',
icon: Symbols.settings,
),
RouteItem(
name: 'About',
path: '/about',
description: 'About this app',
icon: Symbols.info,
),
];
static List<SpecialAction> _getSpecialActions(BuildContext context) { static List<SpecialAction> _getSpecialActions(BuildContext context) {
return [ return [
SpecialAction( SpecialAction(
@@ -296,11 +117,14 @@ class CommandPattleWidget extends HookConsumerWidget {
final filteredRoutes = searchQuery.value.isEmpty final filteredRoutes = searchQuery.value.isEmpty
? <RouteItem>[] ? <RouteItem>[]
: _availableRoutes : kAvailableRoutes
.where((route) { .where((route) {
final query = searchQuery.value.toLowerCase(); final query = searchQuery.value.toLowerCase();
return route.name.toLowerCase().contains(query) || return route.name.toLowerCase().contains(query) ||
route.description.toLowerCase().contains(query); route.description.toLowerCase().contains(query) ||
route.searchableAliases.any(
(e) => e.toLowerCase().contains(query),
);
}) })
.take(5) // Limit to 5 results .take(5) // Limit to 5 results
.toList(); .toList();
@@ -311,7 +135,10 @@ class CommandPattleWidget extends HookConsumerWidget {
.where((action) { .where((action) {
final query = searchQuery.value.toLowerCase(); final query = searchQuery.value.toLowerCase();
return action.name.toLowerCase().contains(query) || return action.name.toLowerCase().contains(query) ||
action.description.toLowerCase().contains(query); action.description.toLowerCase().contains(query) ||
action.searchableAliases.any(
(e) => e.toLowerCase().contains(query),
);
}) })
.take(5) // Limit to 5 results .take(5) // Limit to 5 results
.toList(); .toList();
@@ -452,7 +279,7 @@ class CommandPattleWidget extends HookConsumerWidget {
SearchBar( SearchBar(
controller: textController, controller: textController,
focusNode: focusNode, focusNode: focusNode,
hintText: 'Search chats and pages...', hintText: 'searchChatsAndPages'.tr(),
leading: CircleAvatar( leading: CircleAvatar(
child: const Icon(Symbols.keyboard_command_key), child: const Icon(Symbols.keyboard_command_key),
).padding(horizontal: 8), ).padding(horizontal: 8),

View File

@@ -173,6 +173,8 @@ PODS:
- hotkey_manager_macos (0.0.1): - hotkey_manager_macos (0.0.1):
- FlutterMacOS - FlutterMacOS
- HotKey - HotKey
- in_app_review (2.0.0):
- FlutterMacOS
- irondash_engine_context (0.0.1): - irondash_engine_context (0.0.1):
- FlutterMacOS - FlutterMacOS
- KeychainAccess (4.2.2) - KeychainAccess (4.2.2)
@@ -279,6 +281,7 @@ DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`) - FlutterMacOS (from `Flutter/ephemeral`)
- gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`) - gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`)
- hotkey_manager_macos (from `Flutter/ephemeral/.symlinks/plugins/hotkey_manager_macos/macos`) - hotkey_manager_macos (from `Flutter/ephemeral/.symlinks/plugins/hotkey_manager_macos/macos`)
- in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`)
- irondash_engine_context (from `Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos`) - irondash_engine_context (from `Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos`)
- livekit_client (from `Flutter/ephemeral/.symlinks/plugins/livekit_client/macos`) - livekit_client (from `Flutter/ephemeral/.symlinks/plugins/livekit_client/macos`)
- local_auth_darwin (from `Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin`) - local_auth_darwin (from `Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin`)
@@ -367,6 +370,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/gal/darwin :path: Flutter/ephemeral/.symlinks/plugins/gal/darwin
hotkey_manager_macos: hotkey_manager_macos:
:path: Flutter/ephemeral/.symlinks/plugins/hotkey_manager_macos/macos :path: Flutter/ephemeral/.symlinks/plugins/hotkey_manager_macos/macos
in_app_review:
:path: Flutter/ephemeral/.symlinks/plugins/in_app_review/macos
irondash_engine_context: irondash_engine_context:
:path: Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos :path: Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos
livekit_client: livekit_client:
@@ -447,6 +452,7 @@ SPEC CHECKSUMS:
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
HotKey: 400beb7caa29054ea8d864c96f5ba7e5b4852277 HotKey: 400beb7caa29054ea8d864c96f5ba7e5b4852277
hotkey_manager_macos: a4317849af96d2430fa89944d3c58977ca089fbe hotkey_manager_macos: a4317849af96d2430fa89944d3c58977ca089fbe
in_app_review: 66e7680752b632d83f4f0e88b34d52ed303fbff4
irondash_engine_context: 893c7d96d20ce361d7e996f39d360c4c2f9869ba irondash_engine_context: 893c7d96d20ce361d7e996f39d360c4c2f9869ba
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51 KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
livekit_client: 3df5a1787d64010ca56c4002959d9e47c03ba3fb livekit_client: 3df5a1787d64010ca56c4002959d9e47c03ba3fb