diff --git a/.vscode/lemmur.code-snippets b/.vscode/lemmur.code-snippets index be4b841..b0c9b60 100644 --- a/.vscode/lemmur.code-snippets +++ b/.vscode/lemmur.code-snippets @@ -34,7 +34,7 @@ "L10n string": { "scope": "dart", "prefix": "l10n", - "body": ["L10n.of(context)!.$0"] + "body": ["L10n.of(context).$0"] }, "Mobx store": { "prefix": "mobxstore", diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f7bad6..6483f01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## Unreleased + +### Added + +- You can now add an instance from the three dots menu on the instance page + ## v0.8.0 - 2022-01-14 ### Added diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index f9af2a1..eb54d4e 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -215,7 +215,10 @@ "number_of_users_online": "{formattedCount,plural, =1{{formattedCount} user online} other{{formattedCount} users online}}", "@number_of_users_online": { "placeholders": { - "formattedCount": {} + "formattedCount": { + "type": "int", + "format": "compact" + } } }, "number_of_comments": "{formattedCount,plural, =1{{formattedCount} comment} other{{formattedCount} comments}}", @@ -239,13 +242,28 @@ "number_of_subscribers": "{formattedCount,plural, =1{{formattedCount} subscriber} other{{formattedCount} subscribers}}", "@number_of_subscribers": { "placeholders": { - "formattedCount": {} + "formattedCount": { + "type": "int", + "format": "compact" + } } }, "number_of_users": "{formattedCount,plural, =1{{formattedCount} user} other{{formattedCount} users}}", "@number_of_users": { "placeholders": { - "formattedCount": {} + "formattedCount": { + "type": "int", + "format": "compact" + } + } + }, + "number_of_communities": "{formattedCount,plural, =1{{formattedCount} community} other{{formattedCount} communities}}", + "@number_of_communities": { + "placeholders": { + "formattedCount": { + "type": "int", + "format": "compact" + } } }, "unsubscribe": "unsubscribe", @@ -291,5 +309,41 @@ "show_bot_accounts": "Show Bot Accounts", "@show_bot_accounts": {}, "show_read_posts": "Show Read Posts", - "@show_read_posts": {} + "@show_read_posts": {}, + "site_not_set_up": "This site has not yet been set up", + "@site_not_set_up": {}, + "nerd_stuff": "Nerd stuff", + "@nerd_stuff": {}, + "open_in_browser": "Open in browser", + "@open_in_browser": {}, + "cannot_open_in_browser": "Can't open in browser", + "@cannot_open_in_browser": {}, + "about": "About", + "@about": {}, + "see_all": "See all", + "@see_all": {}, + "admins": "Admins", + "@admins": {}, + "trending_communities": "Trending communities", + "@trending_communities": {}, + "communities_of_instance": "Communities of {instance}", + "@communities_of_instance": { + "placeholders": { + "instance": { + "type": "String" + } + } + }, + "day": "day", + "@day": {}, + "week": "week", + "@week": {}, + "month": "month", + "@month": {}, + "six_months": "6 months", + "@six_months": {}, + "add_instance": "Add instance", + "@add_instance": {}, + "instance_added": "Instance successfully added", + "@instance_added": {} } diff --git a/assets/l10n/untranslated.json b/assets/l10n/untranslated.json deleted file mode 100644 index 0b47b7b..0000000 --- a/assets/l10n/untranslated.json +++ /dev/null @@ -1,1842 +0,0 @@ -{ - "ar": [ - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users" - ], - - "bn": [ - "password", - "email_or_username", - "community", - "url", - "title", - "body", - "nsfw", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "from", - "to", - "restore", - "yes", - "no", - "display_name", - "bio", - "email", - "matrix_user", - "sort_type", - "type", - "show_nsfw", - "send_notifications_to_email", - "saved", - "theme", - "language", - "hot", - "new_", - "old", - "top", - "chat", - "by", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "not_logged_in", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "new_password", - "verify_password", - "old_password", - "search", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active" - ], - - "ca": [ - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "cs": [ - "to", - "couldnt_like_comment", - "couldnt_like_post", - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users" - ], - - "cy": [ - "settings", - "password", - "email_or_username", - "modlog", - "community", - "url", - "title", - "body", - "nsfw", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "from", - "to", - "deleted_by_creator", - "more", - "mark_as_read", - "mark_as_unread", - "reply", - "edit", - "delete", - "restore", - "yes", - "no", - "avatar", - "banner", - "display_name", - "bio", - "email", - "matrix_user", - "sort_type", - "type", - "show_nsfw", - "send_notifications_to_email", - "delete_account", - "saved", - "communities", - "users", - "theme", - "language", - "hot", - "new_", - "old", - "top", - "chat", - "admin", - "by", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "not_logged_in", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "locked", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "invalid_community_name", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "delete_account_confirm", - "new_password", - "verify_password", - "old_password", - "show_avatars", - "search", - "send_message", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "da": [ - "not_a_mod_or_admin", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "eo": [ - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "fa": [ - "banner" - ], - - "fr": [ - "show_bot_accounts", - "show_read_posts" - ], - - "ga": [ - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "hi": [ - "password", - "email_or_username", - "modlog", - "url", - "title", - "body", - "nsfw", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "from", - "to", - "deleted_by_creator", - "mark_as_read", - "mark_as_unread", - "delete", - "restore", - "yes", - "no", - "banner", - "display_name", - "bio", - "email", - "matrix_user", - "sort_type", - "type", - "show_nsfw", - "send_notifications_to_email", - "delete_account", - "saved", - "theme", - "language", - "hot", - "new_", - "old", - "top", - "chat", - "by", - "not_a_mod_or_admin", - "not_an_admin", - "not_logged_in", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "invalid_community_name", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "delete_account_confirm", - "new_password", - "verify_password", - "old_password", - "search", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "hr": [ - "settings", - "password", - "email_or_username", - "posts", - "comments", - "modlog", - "community", - "url", - "title", - "body", - "nsfw", - "post", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "from", - "to", - "deleted_by_creator", - "more", - "mark_as_read", - "mark_as_unread", - "reply", - "edit", - "delete", - "restore", - "yes", - "no", - "avatar", - "banner", - "display_name", - "bio", - "email", - "matrix_user", - "sort_type", - "type", - "show_nsfw", - "send_notifications_to_email", - "delete_account", - "saved", - "communities", - "users", - "theme", - "language", - "hot", - "new_", - "old", - "top", - "chat", - "admin", - "by", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "not_logged_in", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "locked", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "invalid_community_name", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "delete_account_confirm", - "new_password", - "verify_password", - "old_password", - "show_avatars", - "search", - "send_message", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "hu": [ - "local", - "banner", - "display_name", - "bio", - "not_a_mod_or_admin", - "invalid_url", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "not_a_moderator", - "invalid_password", - "captcha_incorrect", - "bio_length_overflow", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "ja": [ - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report" - ], - - "ka": [ - "local", - "banner", - "display_name", - "bio", - "not_a_mod_or_admin", - "invalid_url", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "invalid_community_name", - "not_a_moderator", - "invalid_password", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_private_message", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "km": [ - "settings", - "password", - "email_or_username", - "posts", - "comments", - "modlog", - "community", - "url", - "title", - "body", - "nsfw", - "post", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "from", - "to", - "deleted_by_creator", - "more", - "mark_as_read", - "mark_as_unread", - "reply", - "edit", - "delete", - "restore", - "yes", - "no", - "avatar", - "banner", - "display_name", - "bio", - "email", - "matrix_user", - "sort_type", - "type", - "show_nsfw", - "send_notifications_to_email", - "delete_account", - "saved", - "communities", - "users", - "theme", - "language", - "hot", - "new_", - "old", - "top", - "chat", - "admin", - "by", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "not_logged_in", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "locked", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "invalid_community_name", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "delete_account_confirm", - "new_password", - "verify_password", - "old_password", - "show_avatars", - "search", - "send_message", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "ml": [ - "comments", - "community", - "body", - "nsfw", - "subscribed", - "from", - "to", - "deleted_by_creator", - "matrix_user", - "sort_type", - "show_nsfw", - "by", - "couldnt_find_post", - "community_ban", - "downvotes_disabled", - "invalid_url", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "user_already_exists", - "number_of_subscribers", - "unsubscribe", - "subscribe", - "delete_account_confirm", - "top_day", - "top_week", - "most_comments", - "new_comments" - ], - - "mnc": [ - "settings", - "password", - "email_or_username", - "modlog", - "community", - "url", - "title", - "body", - "nsfw", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "from", - "to", - "deleted_by_creator", - "more", - "mark_as_read", - "mark_as_unread", - "reply", - "edit", - "delete", - "restore", - "yes", - "no", - "avatar", - "banner", - "display_name", - "bio", - "email", - "matrix_user", - "sort_type", - "type", - "show_nsfw", - "send_notifications_to_email", - "delete_account", - "saved", - "communities", - "users", - "theme", - "language", - "hot", - "new_", - "old", - "top", - "chat", - "admin", - "by", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "not_logged_in", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "locked", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "invalid_community_name", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "delete_account_confirm", - "new_password", - "verify_password", - "old_password", - "show_avatars", - "search", - "send_message", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "nb": [ - "settings", - "password", - "email_or_username", - "modlog", - "community", - "url", - "title", - "body", - "nsfw", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "from", - "to", - "deleted_by_creator", - "mark_as_read", - "mark_as_unread", - "delete", - "restore", - "yes", - "no", - "bio", - "email", - "matrix_user", - "sort_type", - "type", - "show_nsfw", - "send_notifications_to_email", - "delete_account", - "saved", - "theme", - "language", - "hot", - "new_", - "old", - "top", - "chat", - "admin", - "by", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "not_logged_in", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "locked", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "invalid_community_name", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "delete_account_confirm", - "new_password", - "verify_password", - "old_password", - "search", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "show_read_posts" - ], - - "oc": [ - "email_or_username", - "modlog", - "nsfw", - "save", - "subscribed", - "local", - "all", - "from", - "to", - "deleted_by_creator", - "mark_as_read", - "mark_as_unread", - "matrix_user", - "show_nsfw", - "send_notifications_to_email", - "hot", - "old", - "top", - "chat", - "admin", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "site_ban", - "community_ban", - "downvotes_disabled", - "locked", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "number_of_subscribers", - "unsubscribe", - "subscribe", - "banned_users", - "delete_account_confirm", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "active", - "show_read_posts" - ], - - "pl": [ - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users" - ], - - "pt_BR": [ - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "top_all", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "ru": [ - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users" - ], - - "sk": [ - "settings", - "password", - "email_or_username", - "modlog", - "community", - "url", - "title", - "body", - "nsfw", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "from", - "to", - "deleted_by_creator", - "more", - "mark_as_read", - "mark_as_unread", - "reply", - "edit", - "delete", - "restore", - "yes", - "no", - "avatar", - "banner", - "display_name", - "bio", - "email", - "matrix_user", - "sort_type", - "type", - "show_nsfw", - "send_notifications_to_email", - "delete_account", - "saved", - "theme", - "language", - "hot", - "new_", - "old", - "top", - "chat", - "admin", - "by", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "not_logged_in", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "locked", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "invalid_community_name", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "delete_account_confirm", - "new_password", - "verify_password", - "old_password", - "show_avatars", - "search", - "send_message", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "sq": [ - "local", - "banner", - "display_name", - "bio", - "not_a_mod_or_admin", - "invalid_url", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "not_a_moderator", - "invalid_password", - "captcha_incorrect", - "bio_length_overflow", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "sr": [ - "settings", - "password", - "email_or_username", - "posts", - "comments", - "modlog", - "community", - "url", - "title", - "body", - "nsfw", - "post", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "from", - "to", - "deleted_by_creator", - "more", - "mark_as_read", - "mark_as_unread", - "reply", - "edit", - "delete", - "restore", - "yes", - "no", - "avatar", - "banner", - "display_name", - "bio", - "email", - "matrix_user", - "sort_type", - "type", - "show_nsfw", - "send_notifications_to_email", - "delete_account", - "saved", - "communities", - "users", - "theme", - "language", - "hot", - "new_", - "old", - "top", - "chat", - "admin", - "by", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "not_logged_in", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "locked", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "invalid_community_name", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "delete_account_confirm", - "new_password", - "verify_password", - "old_password", - "show_avatars", - "search", - "send_message", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "sr_Latn": [ - "settings", - "email_or_username", - "posts", - "comments", - "modlog", - "title", - "post", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "deleted_by_creator", - "more", - "mark_as_read", - "mark_as_unread", - "reply", - "edit", - "delete", - "restore", - "avatar", - "banner", - "display_name", - "bio", - "sort_type", - "type", - "delete_account", - "saved", - "communities", - "users", - "hot", - "new_", - "old", - "top", - "admin", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "not_logged_in", - "site_ban", - "community_ban", - "invalid_url", - "locked", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "invalid_community_name", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "delete_account_confirm", - "show_avatars", - "search", - "send_message", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "th": [ - "modlog", - "nsfw", - "subscribed", - "local", - "deleted_by_creator", - "restore", - "display_name", - "matrix_user", - "sort_type", - "show_nsfw", - "send_notifications_to_email", - "hot", - "top", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "locked", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_get_comments", - "report_reason_required", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "site_already_exists", - "couldnt_update_site", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "invalid_password", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "user_already_exists", - "number_of_users_online", - "number_of_subscribers", - "banned_users", - "delete_account_confirm", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active" - ], - - "tr": [ - "local", - "banner", - "display_name", - "bio", - "not_a_mod_or_admin", - "invalid_url", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "not_a_moderator", - "invalid_password", - "captcha_incorrect", - "bio_length_overflow", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_read_posts" - ], - - "uk": [ - "local", - "banner", - "display_name", - "bio", - "not_a_mod_or_admin", - "invalid_url", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "not_a_moderator", - "invalid_password", - "captcha_incorrect", - "bio_length_overflow", - "number_of_users_online", - "number_of_comments", - "number_of_posts", - "number_of_subscribers", - "number_of_users", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active", - "bot_account", - "show_bot_accounts", - "show_read_posts" - ], - - "zh": [ - "show_read_posts" - ], - - "zh_Hant": [ - "password", - "email_or_username", - "community", - "url", - "title", - "body", - "nsfw", - "save", - "subscribed", - "local", - "all", - "replies", - "mentions", - "from", - "to", - "restore", - "yes", - "no", - "display_name", - "bio", - "email", - "matrix_user", - "sort_type", - "type", - "show_nsfw", - "send_notifications_to_email", - "saved", - "theme", - "language", - "hot", - "new_", - "old", - "top", - "chat", - "admin", - "by", - "not_a_mod_or_admin", - "not_an_admin", - "couldnt_find_post", - "not_logged_in", - "site_ban", - "community_ban", - "downvotes_disabled", - "invalid_url", - "couldnt_create_comment", - "couldnt_like_comment", - "couldnt_update_comment", - "no_comment_edit_allowed", - "couldnt_save_comment", - "couldnt_get_comments", - "report_reason_required", - "report_too_long", - "couldnt_create_report", - "couldnt_resolve_report", - "invalid_post_title", - "couldnt_create_post", - "couldnt_like_post", - "couldnt_find_community", - "couldnt_get_posts", - "no_post_edit_allowed", - "couldnt_save_post", - "site_already_exists", - "couldnt_update_site", - "community_already_exists", - "community_moderator_already_exists", - "community_follower_already_exists", - "not_a_moderator", - "couldnt_update_community", - "no_community_edit_allowed", - "system_err_login", - "community_user_already_banned", - "couldnt_find_that_username_or_email", - "password_incorrect", - "registration_closed", - "invalid_password", - "passwords_dont_match", - "captcha_incorrect", - "invalid_username", - "bio_length_overflow", - "couldnt_update_user", - "couldnt_update_private_message", - "couldnt_update_post", - "couldnt_create_private_message", - "no_private_message_edit_allowed", - "post_title_too_long", - "email_already_exists", - "user_already_exists", - "number_of_users_online", - "number_of_subscribers", - "number_of_users", - "unsubscribe", - "subscribe", - "messages", - "banned_users", - "delete_account_confirm", - "new_password", - "verify_password", - "old_password", - "search", - "top_day", - "top_week", - "top_month", - "top_year", - "top_all", - "most_comments", - "new_comments", - "active" - ] -} diff --git a/l10n.yaml b/l10n.yaml index be9e344..5d87b43 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -4,6 +4,5 @@ template-arb-file: intl_en.arb output-localization-file: l10n.dart preferred-supported-locales: [en] output-class: L10n -untranslated-messages-file: assets/l10n/untranslated.json synthetic-package: false nullable-getter: false diff --git a/lib/pages/communities_list.dart b/lib/pages/communities_list.dart index 1d82c25..72c9d82 100644 --- a/lib/pages/communities_list.dart +++ b/lib/pages/communities_list.dart @@ -9,11 +9,7 @@ import '../widgets/sortable_infinite_list.dart'; /// Infinite list of Communities fetched by the given fetcher class CommunitiesListPage extends StatelessWidget { final String title; - final Future> Function( - int page, - int batchSize, - SortType sortType, - ) fetcher; + final FetcherWithSorting fetcher; const CommunitiesListPage({Key? key, required this.fetcher, this.title = ''}) : super(key: key); @@ -21,6 +17,7 @@ class CommunitiesListPage extends StatelessWidget { @override Widget build(BuildContext context) { final theme = Theme.of(context); + return Scaffold( appBar: AppBar( backgroundColor: theme.cardColor, diff --git a/lib/pages/communities_tab.dart b/lib/pages/communities_tab.dart index c0fcc5b..5e92632 100644 --- a/lib/pages/communities_tab.dart +++ b/lib/pages/communities_tab.dart @@ -15,6 +15,7 @@ import '../util/goto.dart'; import '../util/text_color.dart'; import '../widgets/avatar.dart'; import '../widgets/pull_to_refresh.dart'; +import 'instance/instance.dart'; /// List of subscribed communities per instance class CommunitiesTab extends HookWidget { @@ -171,8 +172,11 @@ class CommunitiesTab extends HookWidget { Column( children: [ ListTile( - onTap: () => goToInstance(context, - accountsStore.loggedInInstances.elementAt(i)), + onTap: () => Navigator.of(context).push( + InstancePage.route( + accountsStore.loggedInInstances.elementAt(i), + ), + ), onLongPress: () => toggleCollapse(i), leading: Avatar( url: instances[i].icon, diff --git a/lib/pages/community/community_overview.dart b/lib/pages/community/community_overview.dart index c41e6b1..0d4c851 100644 --- a/lib/pages/community/community_overview.dart +++ b/lib/pages/community/community_overview.dart @@ -4,10 +4,10 @@ import 'package:lemmy_api_client/v3.dart'; import '../../l10n/l10n.dart'; import '../../util/extensions/api.dart'; -import '../../util/goto.dart'; import '../../widgets/avatar.dart'; import '../../widgets/cached_network_image.dart'; import '../../widgets/fullscreenable_image.dart'; +import '../instance/instance.dart'; import 'community_follow_button.dart'; class CommunityOverview extends StatelessWidget { @@ -93,9 +93,10 @@ class CommunityOverview extends StatelessWidget { text: community.community.originInstanceHost, style: const TextStyle(fontWeight: FontWeight.w600), recognizer: TapGestureRecognizer() - ..onTap = () => goToInstance( - context, - community.community.originInstanceHost, + ..onTap = () => Navigator.of(context).push( + InstancePage.route( + community.community.originInstanceHost, + ), ), ), ], diff --git a/lib/pages/home_tab.dart b/lib/pages/home_tab.dart index f73d07a..8893bbb 100644 --- a/lib/pages/home_tab.dart +++ b/lib/pages/home_tab.dart @@ -15,6 +15,7 @@ import '../widgets/cached_network_image.dart'; import '../widgets/infinite_scroll.dart'; import '../widgets/sortable_infinite_list.dart'; import 'inbox.dart'; +import 'instance/instance.dart'; import 'settings/add_account_page.dart'; /// First thing users sees when opening the app @@ -128,7 +129,9 @@ class HomeTab extends HookWidget { color: theme.textTheme.bodyText1?.color?.withOpacity(0.7)), ), - onTap: () => goToInstance(context, instance), + onTap: () => Navigator.of(context).push( + InstancePage.route(instance), + ), dense: true, contentPadding: EdgeInsets.zero, visualDensity: const VisualDensity( diff --git a/lib/pages/instance.dart b/lib/pages/instance.dart deleted file mode 100644 index 46d6d6e..0000000 --- a/lib/pages/instance.dart +++ /dev/null @@ -1,387 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:lemmy_api_client/v3.dart'; -import 'package:url_launcher/url_launcher.dart' as ul; - -import '../hooks/stores.dart'; -import '../l10n/l10n.dart'; -import '../util/extensions/spaced.dart'; -import '../util/goto.dart'; -import '../util/icons.dart'; -import '../util/share.dart'; -import '../util/text_color.dart'; -import '../widgets/avatar.dart'; -import '../widgets/bottom_modal.dart'; -import '../widgets/cached_network_image.dart'; -import '../widgets/fullscreenable_image.dart'; -import '../widgets/info_table_popup.dart'; -import '../widgets/markdown_text.dart'; -import '../widgets/reveal_after_scroll.dart'; -import '../widgets/sortable_infinite_list.dart'; -import '../widgets/user_tile.dart'; -import 'communities_list.dart'; -import 'modlog/modlog.dart'; - -/// Displays posts, comments, and general info about the given instance -class InstancePage extends HookWidget { - final String instanceHost; - final Future siteFuture; - final Future> communitiesFuture; - - InstancePage({required this.instanceHost}) - : siteFuture = LemmyApiV3(instanceHost).run(const GetSite()), - communitiesFuture = LemmyApiV3(instanceHost).run(const ListCommunities( - type: PostListingType.local, sort: SortType.hot, limit: 6)); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final siteSnap = useFuture(siteFuture); - final colorOnCard = textColorBasedOnBackground(theme.cardColor); - final accStore = useAccountsStore(); - final scrollController = useScrollController(); - - if (!siteSnap.hasData || siteSnap.data!.siteView == null) { - return Scaffold( - appBar: AppBar(), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (siteSnap.hasError) ...[ - const Icon(Icons.error), - Padding( - padding: const EdgeInsets.all(8), - child: Text('ERROR: ${siteSnap.error}'), - ) - ] else if (siteSnap.hasData && siteSnap.data!.siteView == null) - const Text('ERROR') - else - const CircularProgressIndicator.adaptive( - semanticsLabel: 'loading') - ], - ), - ), - ); - } - - final site = siteSnap.data!; - final siteView = site.siteView!; - - void _share() => share('https://$instanceHost', context: context); - - void _openMoreMenu() { - showBottomModal( - context: context, - builder: (context) => Column( - children: [ - ListTile( - leading: const Icon(Icons.open_in_browser), - title: const Text('Open in browser'), - onTap: () async => await ul - .canLaunch('https://${site.instanceHost}') - ? ul.launch('https://${site.instanceHost}') - : ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text("can't open in browser"))), - ), - ListTile( - leading: const Icon(Icons.info_outline), - title: const Text('Nerd stuff'), - onTap: () { - showInfoTablePopup(context: context, table: site.toJson()); - }, - ), - ], - ), - ); - } - - return Scaffold( - body: DefaultTabController( - length: 3, - child: NestedScrollView( - controller: scrollController, - headerSliverBuilder: (context, innerBoxIsScrolled) => [ - SliverAppBar( - expandedHeight: 250, - pinned: true, - backgroundColor: theme.cardColor, - title: RevealAfterScroll( - after: 150, - fade: true, - scrollController: scrollController, - child: Text( - siteView.site.name, - style: TextStyle(color: colorOnCard), - ), - ), - actions: [ - IconButton(icon: Icon(shareIcon), onPressed: _share), - IconButton(icon: Icon(moreIcon), onPressed: _openMoreMenu), - ], - flexibleSpace: FlexibleSpaceBar( - background: Stack(children: [ - if (siteView.site.banner != null) - FullscreenableImage( - url: siteView.site.banner!, - child: CachedNetworkImage( - imageUrl: siteView.site.banner!, - errorBuilder: (_, ___) => const SizedBox.shrink(), - ), - ), - SafeArea( - child: Center( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(top: 40), - child: siteView.site.icon == null - ? const SizedBox(height: 100, width: 100) - : FullscreenableImage( - url: siteView.site.icon!, - child: CachedNetworkImage( - width: 100, - height: 100, - imageUrl: siteView.site.icon!, - errorBuilder: (_, ___) => - const Icon(Icons.warning), - ), - ), - ), - Text(siteView.site.name, - style: theme.textTheme.headline6), - Text(instanceHost, style: theme.textTheme.caption) - ], - ), - ), - ), - ]), - ), - bottom: PreferredSize( - preferredSize: const TabBar(tabs: []).preferredSize, - child: Material( - color: theme.cardColor, - child: TabBar( - tabs: [ - Tab(text: L10n.of(context).posts), - Tab(text: L10n.of(context).comments), - const Tab(text: 'About'), - ], - ), - ), - ), - ), - ], - body: TabBarView( - children: [ - InfinitePostList( - fetcher: (page, batchSize, sort) => - LemmyApiV3(instanceHost).run(GetPosts( - // TODO: switch between all and subscribed - type: PostListingType.all, - sort: sort, - limit: batchSize, - page: page, - savedOnly: false, - auth: - accStore.defaultUserDataFor(instanceHost)?.jwt.raw, - ))), - InfiniteCommentList( - fetcher: (page, batchSize, sort) => - LemmyApiV3(instanceHost).run(GetComments( - type: CommentListingType.all, - sort: sort, - limit: batchSize, - page: page, - savedOnly: false, - auth: - accStore.defaultUserDataFor(instanceHost)?.jwt.raw, - ))), - _AboutTab(site, - communitiesFuture: communitiesFuture, - instanceHost: instanceHost), - ], - ), - ), - ), - ); - } -} - -class _AboutTab extends HookWidget { - final FullSiteView site; - final Future> communitiesFuture; - final String instanceHost; - - const _AboutTab( - this.site, { - required this.communitiesFuture, - required this.instanceHost, - }); - - // void goToBannedUsers(BuildContext context) { - // goTo( - // context, - // (_) => UsersListPage( - // users: site.banned.reversed.toList(), - // title: L10n.of(context).banned_users, - // ), - // ); - // } - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final commSnap = useFuture(communitiesFuture); - final accStore = useAccountsStore(); - - void goToCommunities() { - goTo( - context, - (_) => CommunitiesListPage( - fetcher: (page, batchSize, sortType) => LemmyApiV3(instanceHost).run( - ListCommunities( - type: PostListingType.local, - sort: sortType, - limit: batchSize, - page: page, - auth: accStore.defaultUserDataFor(instanceHost)?.jwt.raw, - ), - ), - title: 'Communities of ${site.siteView?.site.name}', - ), - ); - } - - final siteView = site.siteView; - - if (siteView == null) { - return const SingleChildScrollView( - child: Center( - child: Padding( - padding: EdgeInsets.all(16), - child: Text('error'), - ))); - } - - return SingleChildScrollView( - child: SafeArea( - top: false, - child: Column( - children: [ - if (siteView.site.description != null) ...[ - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 15, vertical: 15), - child: MarkdownText( - siteView.site.description!, - instanceHost: instanceHost, - ), - ), - const _Divider(), - ], - SizedBox( - height: 32, - child: ListView( - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.symmetric(horizontal: 15), - children: [ - Chip( - label: Text(L10n.of(context) - .number_of_users_online(site.online))), - Chip( - label: Text( - '${siteView.counts.usersActiveDay} users / day')), - Chip( - label: Text( - '${siteView.counts.usersActiveWeek} users / week')), - Chip( - label: Text( - '${siteView.counts.usersActiveMonth} users / month')), - Chip( - label: Text( - '${siteView.counts.usersActiveHalfYear} users / 6 months')), - Chip( - label: Text(L10n.of(context) - .number_of_users(siteView.counts.users))), - Chip( - label: - Text('${siteView.counts.communities} communities')), - Chip(label: Text('${siteView.counts.posts} posts')), - Chip(label: Text('${siteView.counts.comments} comments')), - ].spaced(8), - ), - ), - const _Divider(), - ListTile( - title: Center( - child: Text( - 'Trending communities:', - style: theme.textTheme.headline6?.copyWith(fontSize: 18), - ), - ), - ), - if (commSnap.hasData) - for (final c in commSnap.data!) - ListTile( - onTap: () => goToCommunity.byId( - context, c.instanceHost, c.community.id), - title: Text(c.community.name), - leading: Avatar(url: c.community.icon), - ) - else if (commSnap.hasError) - Padding( - padding: const EdgeInsets.all(8), - child: Text("Can't load communities, ${commSnap.error}"), - ) - else - const Padding( - padding: EdgeInsets.symmetric(vertical: 10), - child: CircularProgressIndicator.adaptive(), - ), - ListTile( - title: const Center(child: Text('See all')), - onTap: goToCommunities, - ), - const _Divider(), - ListTile( - title: Center( - child: Text( - 'Admins:', - style: theme.textTheme.headline6?.copyWith(fontSize: 18), - ), - ), - ), - for (final u in site.admins) - PersonTile( - u.person, - expanded: true, - ), - const _Divider(), - // TODO: transition to new API - // ListTile( - // title: Center(child: Text(L10n.of(context).banned_users)), - // onTap: () => goToBannedUsers(context), - // ), - ListTile( - title: Center(child: Text(L10n.of(context).modlog)), - onTap: () => Navigator.of(context).push( - ModlogPage.forInstanceRoute(instanceHost), - ), - ), - ], - ), - ), - ); - } -} - -class _Divider extends StatelessWidget { - const _Divider(); - - @override - Widget build(BuildContext context) => const Padding( - padding: EdgeInsets.symmetric(horizontal: 15, vertical: 10), - child: Divider(), - ); -} diff --git a/lib/pages/instance/instance.dart b/lib/pages/instance/instance.dart new file mode 100644 index 0000000..8211576 --- /dev/null +++ b/lib/pages/instance/instance.dart @@ -0,0 +1,204 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:lemmy_api_client/v3.dart'; + +import '../../l10n/l10n.dart'; +import '../../util/extensions/context.dart'; +import '../../util/icons.dart'; +import '../../util/mobx_provider.dart'; +import '../../util/observer_consumers.dart'; +import '../../util/share.dart'; +import '../../util/text_color.dart'; +import '../../widgets/cached_network_image.dart'; +import '../../widgets/failed_to_load.dart'; +import '../../widgets/fullscreenable_image.dart'; +import '../../widgets/reveal_after_scroll.dart'; +import '../../widgets/sortable_infinite_list.dart'; +import 'instance_about_tab.dart'; +import 'instance_more_menu.dart'; +import 'instance_store.dart'; + +/// Displays posts, comments, and general info about the given instance +class InstancePage extends HookWidget { + const InstancePage(); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final colorOnCard = textColorBasedOnBackground(theme.cardColor); + final scrollController = useScrollController(); + + return ObserverBuilder( + builder: (context, store) { + final instanceUrl = 'https://${store.instanceHost}'; + + return store.siteState.map( + loading: () => Scaffold( + appBar: AppBar(), + body: const Center(child: CircularProgressIndicator.adaptive()), + ), + error: (errorTerm) => Scaffold( + appBar: AppBar(), + body: Center( + child: FailedToLoad( + refresh: () => store.fetch( + context.defaultJwt(store.instanceHost), + ), + message: errorTerm.tr(context), + ), + ), + ), + data: (site) { + final siteView = site.siteView; + + if (siteView == null) { + return Scaffold( + appBar: AppBar(), + body: Center(child: Text(L10n.of(context).site_not_set_up)), + ); + } + + return Scaffold( + body: DefaultTabController( + length: 3, + child: NestedScrollView( + controller: scrollController, + headerSliverBuilder: (context, innerBoxIsScrolled) => [ + SliverAppBar( + expandedHeight: 250, + pinned: true, + backgroundColor: theme.cardColor, + title: RevealAfterScroll( + after: 150, + fade: true, + scrollController: scrollController, + child: Text( + siteView.site.name, + style: TextStyle(color: colorOnCard), + ), + ), + actions: [ + IconButton( + icon: Icon(shareIcon), + onPressed: () => share(instanceUrl, context: context), + ), + IconButton( + icon: Icon(moreIcon), + onPressed: () => InstanceMoreMenu.open(context, site), + ), + ], + flexibleSpace: FlexibleSpaceBar( + background: Stack( + children: [ + if (siteView.site.banner != null) + FullscreenableImage( + url: siteView.site.banner!, + child: CachedNetworkImage( + imageUrl: siteView.site.banner!, + errorBuilder: (_, ___) => const SizedBox(), + ), + ), + SafeArea( + child: Center( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 40), + child: siteView.site.icon == null + ? const SizedBox( + height: 100, + width: 100, + ) + : FullscreenableImage( + url: siteView.site.icon!, + child: CachedNetworkImage( + width: 100, + height: 100, + imageUrl: siteView.site.icon!, + errorBuilder: (_, ___) => + const Icon(Icons.warning), + ), + ), + ), + Text( + siteView.site.name, + style: theme.textTheme.headline6, + ), + Text( + store.instanceHost, + style: theme.textTheme.caption, + ) + ], + ), + ), + ), + ], + ), + ), + bottom: PreferredSize( + preferredSize: const TabBar(tabs: []).preferredSize, + child: Material( + color: theme.cardColor, + child: TabBar( + tabs: [ + Tab(text: L10n.of(context).posts), + Tab(text: L10n.of(context).comments), + Tab(text: L10n.of(context).about), + ], + ), + ), + ), + ), + ], + body: TabBarView( + children: [ + InfinitePostList( + fetcher: (page, batchSize, sort) => + LemmyApiV3(store.instanceHost).run(GetPosts( + // TODO: switch between all and subscribed + type: PostListingType.all, + sort: sort, + limit: batchSize, + page: page, + savedOnly: false, + auth: context.defaultJwt(store.instanceHost)?.raw, + )), + ), + InfiniteCommentList( + fetcher: (page, batchSize, sort) => + LemmyApiV3(store.instanceHost).run(GetComments( + type: CommentListingType.all, + sort: sort, + limit: batchSize, + page: page, + savedOnly: false, + auth: context.defaultJwt(store.instanceHost)?.raw, + )), + ), + InstanceAboutTab( + site: site, + siteView: siteView, + ), + ], + ), + ), + ), + ); + }, + ); + }, + ); + } + + static Route route(String instanceHost) { + return MaterialPageRoute( + builder: (context) { + return MobxProvider( + create: (context) => InstanceStore(instanceHost) + ..fetch(context.defaultJwt(instanceHost)), + child: const InstancePage(), + ); + }, + ); + } +} diff --git a/lib/pages/instance/instance_about_tab.dart b/lib/pages/instance/instance_about_tab.dart new file mode 100644 index 0000000..c870b93 --- /dev/null +++ b/lib/pages/instance/instance_about_tab.dart @@ -0,0 +1,206 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:lemmy_api_client/v3.dart'; + +import '../../l10n/l10n.dart'; +import '../../util/extensions/context.dart'; +import '../../util/extensions/spaced.dart'; +import '../../util/goto.dart'; +import '../../util/observer_consumers.dart'; +import '../../widgets/avatar.dart'; +import '../../widgets/failed_to_load.dart'; +import '../../widgets/markdown_text.dart'; +import '../../widgets/pull_to_refresh.dart'; +import '../../widgets/user_tile.dart'; +import '../communities_list.dart'; +import '../community/community.dart'; +import '../modlog/modlog.dart'; +import 'instance_store.dart'; + +class InstanceAboutTab extends HookWidget { + final FullSiteView site; + final SiteView siteView; + + const InstanceAboutTab({required this.site, required this.siteView}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final l10n = L10n.of(context); + + void goToCommunities() { + goTo( + context, + (_) => CommunitiesListPage( + fetcher: (page, batchSize, sortType) => + LemmyApiV3(site.instanceHost).run( + ListCommunities( + type: PostListingType.local, + sort: sortType, + limit: batchSize, + page: page, + auth: context.defaultJwt(site.instanceHost)?.raw, + ), + ), + title: l10n.communities_of_instance(siteView.site.name), + ), + ); + } + + return PullToRefresh( + onRefresh: () => context + .read() + .fetch(context.defaultJwt(site.instanceHost), refresh: true), + child: SingleChildScrollView( + child: SafeArea( + top: false, + child: Column( + children: [ + if (siteView.site.description != null) ...[ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 15, + vertical: 15, + ), + child: MarkdownText( + siteView.site.description!, + instanceHost: site.instanceHost, + ), + ), + const _Divider(), + ], + SizedBox( + height: 32, + child: ListView( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(horizontal: 15), + children: [ + Chip( + label: Text( + l10n.number_of_users_online(site.online), + ), + ), + Chip( + label: Text( + '${l10n.number_of_users(siteView.counts.usersActiveDay)} / ${l10n.day}', + ), + ), + Chip( + label: Text( + '${l10n.number_of_users(siteView.counts.usersActiveWeek)} / ${l10n.week}', + ), + ), + Chip( + label: Text( + '${l10n.number_of_users(siteView.counts.usersActiveMonth)} / ${l10n.month}', + ), + ), + Chip( + label: Text( + '${l10n.number_of_users(siteView.counts.usersActiveHalfYear)} / ${l10n.six_months}', + ), + ), + Chip( + label: Text( + l10n.number_of_users(siteView.counts.users), + ), + ), + Chip( + label: Text( + l10n.number_of_communities(siteView.counts.communities), + ), + ), + Chip( + label: Text( + l10n.number_of_posts(siteView.counts.posts), + ), + ), + Chip( + label: Text( + l10n.number_of_comments(siteView.counts.comments), + ), + ), + ].spaced(8), + ), + ), + const _Divider(), + ListTile( + title: Center( + child: Text( + l10n.trending_communities, + style: theme.textTheme.headline6?.copyWith(fontSize: 18), + ), + ), + ), + ObserverBuilder( + builder: (context, store) => store.communitiesState.map( + loading: () => const Padding( + padding: EdgeInsets.symmetric(vertical: 10), + child: CircularProgressIndicator.adaptive(), + ), + error: (errorTerm) => FailedToLoad( + refresh: () => store.fetchCommunites( + context.defaultJwt(store.instanceHost)), + message: errorTerm.tr(context), + ), + data: (communities) => Column( + children: [ + for (final c in communities) + ListTile( + onTap: () => Navigator.of(context).push( + CommunityPage.fromIdRoute( + store.instanceHost, + c.community.id, + ), + ), + title: Text(c.community.name), + leading: Avatar(url: c.community.icon), + ) + ], + ), + ), + ), + ListTile( + title: Center(child: Text(l10n.see_all)), + onTap: goToCommunities, + ), + const _Divider(), + ListTile( + title: Center( + child: Text( + l10n.admins, + style: theme.textTheme.headline6?.copyWith(fontSize: 18), + ), + ), + ), + for (final u in site.admins) + PersonTile( + u.person, + expanded: true, + ), + const _Divider(), + ListTile( + title: Center(child: Text(l10n.modlog)), + onTap: () => Navigator.of(context).push( + ModlogPage.forInstanceRoute(site.instanceHost), + ), + ), + ], + ), + ), + ), + ); + } +} + +class _Divider extends StatelessWidget { + const _Divider(); + + @override + Widget build(BuildContext context) { + return const Padding( + padding: EdgeInsets.symmetric(horizontal: 15, vertical: 10), + child: Divider(), + ); + } +} diff --git a/lib/pages/instance/instance_more_menu.dart b/lib/pages/instance/instance_more_menu.dart new file mode 100644 index 0000000..c1bb877 --- /dev/null +++ b/lib/pages/instance/instance_more_menu.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; +import 'package:lemmy_api_client/v3.dart'; +import 'package:url_launcher/url_launcher.dart' as ul; + +import '../../l10n/l10n.dart'; +import '../../stores/accounts_store.dart'; +import '../../util/observer_consumers.dart'; +import '../../widgets/bottom_modal.dart'; +import '../../widgets/info_table_popup.dart'; + +class InstanceMoreMenu extends StatelessWidget { + final FullSiteView site; + + const InstanceMoreMenu({Key? key, required this.site}) : super(key: key); + + @override + Widget build(BuildContext context) { + final instanceUrl = 'https://${site.instanceHost}'; + final accountsStore = context.watch(); + + return Column( + children: [ + if (!accountsStore.instances.contains(site.instanceHost)) + ListTile( + leading: const Icon(Icons.add), + title: Text(L10n.of(context).add_instance), + onTap: () { + accountsStore.addInstance(site.instanceHost, assumeValid: true); + Navigator.of(context).pop(); + ScaffoldMessenger.of(context) + ..hideCurrentSnackBar() + ..showSnackBar( + SnackBar(content: Text(L10n.of(context).instance_added)), + ); + }, + ), + ListTile( + leading: const Icon(Icons.open_in_browser), + title: Text(L10n.of(context).open_in_browser), + onTap: () async { + if (await ul.canLaunch(instanceUrl)) { + await ul.launch(instanceUrl); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(L10n.of(context).cannot_open_in_browser), + ), + ); + } + }, + ), + ListTile( + leading: const Icon(Icons.info_outline), + title: Text(L10n.of(context).nerd_stuff), + onTap: () { + showInfoTablePopup(context: context, table: site.toJson()); + }, + ), + ], + ); + } + + static void open(BuildContext context, FullSiteView site) { + showBottomModal( + context: context, + builder: (context) => InstanceMoreMenu(site: site), + ); + } +} diff --git a/lib/pages/instance/instance_store.dart b/lib/pages/instance/instance_store.dart new file mode 100644 index 0000000..aa88a1a --- /dev/null +++ b/lib/pages/instance/instance_store.dart @@ -0,0 +1,43 @@ +import 'package:lemmy_api_client/v3.dart'; +import 'package:mobx/mobx.dart'; + +import '../../util/async_store.dart'; + +part 'instance_store.g.dart'; + +class InstanceStore = _InstanceStore with _$InstanceStore; + +abstract class _InstanceStore with Store { + final String instanceHost; + + _InstanceStore(this.instanceHost); + + final siteState = AsyncStore(); + final communitiesState = AsyncStore>(); + + @action + Future fetch(Jwt? token, {bool refresh = false}) async { + await Future.wait([ + siteState.runLemmy( + instanceHost, + GetSite(auth: token?.raw), + refresh: refresh, + ), + fetchCommunites(token, refresh: refresh), + ]); + } + + @action + Future fetchCommunites(Jwt? token, {bool refresh = false}) async { + await communitiesState.runLemmy( + instanceHost, + ListCommunities( + type: PostListingType.local, + sort: SortType.hot, + limit: 6, + auth: token?.raw, + ), + refresh: refresh, + ); + } +} diff --git a/lib/pages/instance/instance_store.g.dart b/lib/pages/instance/instance_store.g.dart new file mode 100644 index 0000000..83d7c1d --- /dev/null +++ b/lib/pages/instance/instance_store.g.dart @@ -0,0 +1,34 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'instance_store.dart'; + +// ************************************************************************** +// StoreGenerator +// ************************************************************************** + +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic + +mixin _$InstanceStore on _InstanceStore, Store { + final _$fetchAsyncAction = AsyncAction('_InstanceStore.fetch'); + + @override + Future fetch(Jwt? token, {bool refresh = false}) { + return _$fetchAsyncAction.run(() => super.fetch(token, refresh: refresh)); + } + + final _$fetchCommunitesAsyncAction = + AsyncAction('_InstanceStore.fetchCommunites'); + + @override + Future fetchCommunites(Jwt? token, {bool refresh = false}) { + return _$fetchCommunitesAsyncAction + .run(() => super.fetchCommunites(token, refresh: refresh)); + } + + @override + String toString() { + return ''' + + '''; + } +} diff --git a/lib/pages/users_list.dart b/lib/pages/users_list.dart index a028460..15d1ea5 100644 --- a/lib/pages/users_list.dart +++ b/lib/pages/users_list.dart @@ -4,29 +4,35 @@ import 'package:lemmy_api_client/v3.dart'; import '../util/extensions/api.dart'; import '../util/goto.dart'; import '../widgets/avatar.dart'; +import '../widgets/infinite_scroll.dart'; import '../widgets/markdown_text.dart'; /// Infinite list of Users fetched by the given fetcher class UsersListPage extends StatelessWidget { final String title; - final List users; + final Fetcher fetcher; - const UsersListPage({Key? key, required this.users, this.title = ''}) + const UsersListPage({Key? key, required this.fetcher, this.title = ''}) : super(key: key); @override Widget build(BuildContext context) { final theme = Theme.of(context); - // TODO: change to infinite scroll return Scaffold( appBar: AppBar( backgroundColor: theme.cardColor, title: Text(title), ), - body: ListView.builder( - itemBuilder: (context, i) => UsersListItem(user: users[i]), - itemCount: users.length, + body: InfiniteScroll( + fetcher: fetcher, + itemBuilder: (user) => Column( + children: [ + const Divider(), + UsersListItem(user: user), + ], + ), + uniqueProp: (user) => user.person.actorId, ), ); } @@ -38,18 +44,20 @@ class UsersListItem extends StatelessWidget { const UsersListItem({Key? key, required this.user}) : super(key: key); @override - Widget build(BuildContext context) => ListTile( - title: Text(user.person.originPreferredName), - subtitle: user.person.bio != null - ? Opacity( - opacity: 0.7, - child: MarkdownText( - user.person.bio!, - instanceHost: user.instanceHost, - ), - ) - : null, - onTap: () => goToUser.fromPersonSafe(context, user.person), - leading: Avatar(url: user.person.avatar), - ); + Widget build(BuildContext context) { + return ListTile( + title: Text(user.person.originPreferredName), + subtitle: user.person.bio != null + ? Opacity( + opacity: 0.7, + child: MarkdownText( + user.person.bio!, + instanceHost: user.instanceHost, + ), + ) + : null, + onTap: () => goToUser.fromPersonSafe(context, user.person), + leading: Avatar(url: user.person.avatar), + ); + } } diff --git a/lib/url_launcher.dart b/lib/url_launcher.dart index 67e0042..8882b78 100644 --- a/lib/url_launcher.dart +++ b/lib/url_launcher.dart @@ -3,7 +3,7 @@ import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart' as ul; import 'pages/community/community.dart'; -import 'pages/instance.dart'; +import 'pages/instance/instance.dart'; import 'pages/media_view.dart'; import 'pages/user.dart'; import 'stores/accounts_store.dart'; @@ -48,7 +48,7 @@ Future linkLauncher({ if (matchedInstance != null && instances.any((e) => e == match?.group(1))) { if (rest == null || rest.isEmpty || rest == '/') { - return push(() => InstancePage(instanceHost: matchedInstance)); + return Navigator.of(context).push(InstancePage.route(instanceHost)); } final split = rest.split('/'); switch (split[1]) { diff --git a/lib/util/async_store.dart b/lib/util/async_store.dart index 10c0be2..8c59d4d 100644 --- a/lib/util/async_store.dart +++ b/lib/util/async_store.dart @@ -76,8 +76,10 @@ abstract class _AsyncStore with Store { bool refresh = false, }) async { try { - return await run(() => LemmyApiV3(instanceHost).run(query), - refresh: refresh); + return await run( + () => LemmyApiV3(instanceHost).run(query), + refresh: refresh, + ); } on LemmyApiException catch (err) { final data = refresh ? asyncState.mapOrNull(data: (data) => data) : null; if (data != null) { diff --git a/lib/util/extensions/api.dart b/lib/util/extensions/api.dart index af82595..b6347a9 100644 --- a/lib/util/extensions/api.dart +++ b/lib/util/extensions/api.dart @@ -52,3 +52,14 @@ extension UserPreferredNames on PersonSafe { extension CommentLink on Comment { String get link => 'https://$instanceHost/post/$postId/comment/$id'; } + +// inspired by https://github.com/LemmyNet/lemmy-ui/blob/66c846ededef8c0afd5aaadca4aaedcbaeab3ee6/src/shared/utils.ts#L533 +extension PersonSafeCakeDay on PersonSafe { + bool get isCakeDay { + final now = DateTime.now().toUtc(); + + return now.day == published.day && + now.month == published.month && + now.year != published.year; + } +} diff --git a/lib/util/extensions/cake_day.dart b/lib/util/extensions/cake_day.dart deleted file mode 100644 index 7fba60c..0000000 --- a/lib/util/extensions/cake_day.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:lemmy_api_client/v3.dart'; - -// inspired by https://github.com/LemmyNet/lemmy-ui/blob/66c846ededef8c0afd5aaadca4aaedcbaeab3ee6/src/shared/utils.ts#L533 -extension PersonSafeCakeDay on PersonSafe { - bool get isCakeDay { - final now = DateTime.now().toUtc(); - - return now.day == published.day && - now.month == published.month && - now.year != published.year; - } -} diff --git a/lib/util/extensions/context.dart b/lib/util/extensions/context.dart new file mode 100644 index 0000000..ac9764a --- /dev/null +++ b/lib/util/extensions/context.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; +import 'package:lemmy_api_client/v3.dart'; + +import '../../stores/accounts_store.dart'; +import '../observer_consumers.dart'; + +extension BuildContextExtensions on BuildContext { + /// Get default [Jwt] for an instance + Jwt? defaultJwt(String instanceHost) => + read().defaultUserDataFor(instanceHost)?.jwt; +} diff --git a/lib/util/goto.dart b/lib/util/goto.dart index 418a8ef..7298816 100644 --- a/lib/util/goto.dart +++ b/lib/util/goto.dart @@ -3,7 +3,6 @@ import 'package:lemmy_api_client/v3.dart'; import '../pages/community/community.dart'; import '../pages/full_post/full_post.dart'; -import '../pages/instance.dart'; import '../pages/media_view.dart'; import '../pages/user.dart'; @@ -25,9 +24,6 @@ Future goToReplace( builder: builder, )); -void goToInstance(BuildContext context, String instanceHost) => - goTo(context, (context) => InstancePage(instanceHost: instanceHost)); - // ignore: camel_case_types abstract class goToCommunity { /// Navigates to `CommunityPage` diff --git a/lib/widgets/comment/comment.dart b/lib/widgets/comment/comment.dart index 22501b5..b0faa80 100644 --- a/lib/widgets/comment/comment.dart +++ b/lib/widgets/comment/comment.dart @@ -9,7 +9,6 @@ import '../../l10n/l10n.dart'; import '../../stores/config_store.dart'; import '../../util/async_store_listener.dart'; import '../../util/extensions/api.dart'; -import '../../util/extensions/cake_day.dart'; import '../../util/goto.dart'; import '../../util/mobx_provider.dart'; import '../../util/observer_consumers.dart'; diff --git a/lib/widgets/infinite_scroll.dart b/lib/widgets/infinite_scroll.dart index 3a12e23..5b39723 100644 --- a/lib/widgets/infinite_scroll.dart +++ b/lib/widgets/infinite_scroll.dart @@ -17,6 +17,8 @@ class InfiniteScrollController { } } +typedef Fetcher = Future> Function(int page, int batchSize); + /// `ListView.builder` with asynchronous data fetching and no `itemCount` class InfiniteScroll extends HookWidget { /// How many items should be fetched per call @@ -31,7 +33,7 @@ class InfiniteScroll extends HookWidget { /// Fetches data to be displayed. It is important to respect `batchSize`, /// if the returned list has less than `batchSize` then the InfiniteScroll /// is considered finished - final Future> Function(int page, int batchSize) fetcher; + final Fetcher fetcher; final InfiniteScrollController? controller; diff --git a/lib/widgets/post/post_info_section.dart b/lib/widgets/post/post_info_section.dart index 7c64a48..9db26fb 100644 --- a/lib/widgets/post/post_info_section.dart +++ b/lib/widgets/post/post_info_section.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import '../../l10n/l10n.dart'; import '../../pages/community/community.dart'; +import '../../pages/instance/instance.dart'; import '../../util/extensions/api.dart'; import '../../util/goto.dart'; import '../../util/observer_consumers.dart'; @@ -67,9 +68,10 @@ class PostInfoSection extends StatelessWidget { text: post.post.originInstanceHost, style: const TextStyle(fontWeight: FontWeight.w600), recognizer: TapGestureRecognizer() - ..onTap = () => goToInstance( - context, - post.post.originInstanceHost, + ..onTap = () => Navigator.of(context).push( + InstancePage.route( + post.post.originInstanceHost, + ), ), ), ], diff --git a/lib/widgets/user_profile.dart b/lib/widgets/user_profile.dart index 6bbeddb..c0b7c21 100644 --- a/lib/widgets/user_profile.dart +++ b/lib/widgets/user_profile.dart @@ -6,9 +6,9 @@ import 'package:lemmy_api_client/v3.dart'; import '../hooks/memo_future.dart'; import '../hooks/stores.dart'; import '../l10n/l10n.dart'; +import '../pages/instance/instance.dart'; import '../pages/manage_account.dart'; import '../util/extensions/api.dart'; -import '../util/extensions/cake_day.dart'; import '../util/goto.dart'; import '../util/text_color.dart'; import 'avatar.dart'; @@ -226,8 +226,11 @@ class _UserOverview extends HookWidget { style: theme.textTheme.caption, ), InkWell( - onTap: () => goToInstance( - context, userView.person.originInstanceHost), + onTap: () => Navigator.of(context).push( + InstancePage.route( + userView.person.originInstanceHost, + ), + ), child: Text( userView.person.originInstanceHost, style: theme.textTheme.caption,