From 15bed586dcd1d10a6a05c664cf5bab72cdbf2a46 Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Sun, 15 Nov 2020 13:57:02 +0200 Subject: report notification wip --- src/components/interactions/interactions.js | 2 ++ src/components/interactions/interactions.vue | 9 +++++++++ src/services/entity_normalizer/entity_normalizer.service.js | 7 +++++++ src/services/notification_utils/notification_utils.js | 6 +++++- 4 files changed, 23 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/interactions/interactions.js b/src/components/interactions/interactions.js index 7fe5e76d..54275a7b 100644 --- a/src/components/interactions/interactions.js +++ b/src/components/interactions/interactions.js @@ -4,6 +4,8 @@ const tabModeDict = { mentions: ['mention'], 'likes+repeats': ['repeat', 'like'], follows: ['follow'], + reactions: ['pleroma:emoji_reaction'], + reports: ['pleroma:report'], moves: ['move'] } diff --git a/src/components/interactions/interactions.vue b/src/components/interactions/interactions.vue index 57d5d87c..b7291c02 100644 --- a/src/components/interactions/interactions.vue +++ b/src/components/interactions/interactions.vue @@ -21,6 +21,15 @@ key="follows" :label="$t('interactions.follows')" /> + + { : parseUser(data.target) output.from_profile = parseUser(data.account) output.emoji = data.emoji + if (data.report) { + output.report = data.report + output.report.content = data.report.content + output.report.acct = parseUser(data.report.acct) + output.report.actor = parseUser(data.report.actor) + output.report.statuses = data.report.statuses.map(parseStatus) + } } else { const parsedNotice = parseStatus(data.notice) output.type = data.ntype diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js index d912d19f..dff97aa2 100644 --- a/src/services/notification_utils/notification_utils.js +++ b/src/services/notification_utils/notification_utils.js @@ -14,7 +14,8 @@ export const visibleTypes = store => { rootState.config.notificationVisibility.follows && 'follow', rootState.config.notificationVisibility.followRequest && 'follow_request', rootState.config.notificationVisibility.moves && 'move', - rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction' + rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction', + rootState.config.notificationVisibility.reports && 'pleroma:report' ].filter(_ => _)) } @@ -91,6 +92,9 @@ export const prepareNotificationObject = (notification, i18n) => { case 'follow_request': i18nString = 'follow_request' break + case 'pleroma:report': + i18nString = 'reported' + break } if (notification.type === 'pleroma:emoji_reaction') { -- cgit v1.2.3-70-g09d2 From 5e96260a4f855e2d93915c1b428a7209a882c8cb Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Fri, 4 Dec 2020 12:48:15 +0200 Subject: add test data for dev --- src/services/api/api.service.js | 282 +++++++++++++++++++++ .../entity_normalizer/entity_normalizer.service.js | 2 +- .../notifications_fetcher.service.js | 1 + 3 files changed, 284 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 8da933c4..6b825c37 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -484,6 +484,285 @@ const deleteUser = ({ credentials, user }) => { }) } +/* eslint-disable */ +const report = { + "account": { + "acct": "reporting_account", + "avatar": "https://develop.ilja.space/images/avi.png", + "avatar_static": "https://develop.ilja.space/images/avi.png", + "bot": false, + "created_at": "2020-09-03T14:17:00.000Z", + "display_name": "Reporting Account", + "emojis": [], + "fields": [], + "followers_count": 0, + "following_count": 0, + "header": "https://develop.ilja.space/images/banner.png", + "header_static": "https://develop.ilja.space/images/banner.png", + "id": "9ymg9LnKk74wuk9lXk", + "locked": false, + "note": "I'm an account made for an example report notification. I'm the one that will do the reporting.", + "pleroma": { + "accepts_chat_messages": true, + "ap_id": "https://develop.ilja.space/users/reporting_account", + "background_image": null, + "confirmation_pending": false, + "deactivated": false, + "favicon": null, + "hide_favorites": true, + "hide_followers": false, + "hide_followers_count": false, + "hide_follows": false, + "hide_follows_count": false, + "is_admin": false, + "is_moderator": false, + "relationship": {}, + "skip_thread_containment": false, + "tags": [] + }, + "source": { + "fields": [], + "note": "", + "pleroma": { + "actor_type": "Person", + "discoverable": false + }, + "sensitive": false + }, + "statuses_count": 0, + "url": "https://develop.ilja.space/users/reporting_account", + "username": "reporting_account" + }, + "created_at": "2020-09-03T14:22:59.000Z", + "id": "5", + "pleroma": { + "is_muted": false, + "is_seen": false + }, + "report": { + "account": { + "local": true, + "locked": false, + "acct": "reported_account", + "followers_count": 0, + "fields": [], + "avatar": "https://develop.ilja.space/images/avi.png", + "actor_type": "Person", + "url": "https://develop.ilja.space/users/reported_account", + "deactivated": false, + "id": "9ymgGklmHjZ2OpxVLM", + "bot": false, + "roles": { + "admin": false, + "moderator": false + }, + "statuses_count": 1, + "nickname": "reported_account", + "display_name": "Reported Account", + "source": { + "fields": [], + "note": "", + "pleroma": { + "actor_type": "Person", + "discoverable": false + }, + "sensitive": false + }, + "pleroma": { + "accepts_chat_messages": true, + "ap_id": "https://develop.ilja.space/users/reported_account", + "background_image": null, + "confirmation_pending": false, + "favicon": null, + "hide_favorites": true, + "hide_followers": false, + "hide_followers_count": false, + "hide_follows": false, + "hide_follows_count": false, + "is_admin": false, + "is_moderator": false, + "relationship": {}, + "skip_thread_containment": false, + "tags": [] + }, + "emojis": [], + "created_at": "2020-09-03T14:18:21.000Z", + "username": "reported_account", + "note": "I'm an account made for an example report notification. I'm the one that will be reported.", + "approval_pending": false, + "avatar_static": "https://develop.ilja.space/images/avi.png", + "header": "https://develop.ilja.space/images/banner.png", + "registration_reason": null, + "confirmation_pending": false, + "header_static": "https://develop.ilja.space/images/banner.png", + "following_count": 0, + "tags": [] + }, + "actor": { + "local": true, + "locked": false, + "acct": "reporting_account", + "followers_count": 0, + "fields": [], + "avatar": "https://develop.ilja.space/images/avi.png", + "actor_type": "Person", + "url": "https://develop.ilja.space/users/reporting_account", + "deactivated": false, + "id": "9ymg9LnKk74wuk9lXk", + "bot": false, + "roles": { + "admin": false, + "moderator": false + }, + "statuses_count": 0, + "nickname": "reporting_account", + "display_name": "Reporting Account", + "source": { + "fields": [], + "note": "", + "pleroma": { + "actor_type": "Person", + "discoverable": false + }, + "sensitive": false + }, + "pleroma": { + "accepts_chat_messages": true, + "ap_id": "https://develop.ilja.space/users/reporting_account", + "background_image": null, + "confirmation_pending": false, + "favicon": null, + "hide_favorites": true, + "hide_followers": false, + "hide_followers_count": false, + "hide_follows": false, + "hide_follows_count": false, + "is_admin": false, + "is_moderator": false, + "relationship": {}, + "skip_thread_containment": false, + "tags": [] + }, + "emojis": [], + "created_at": "2020-09-03T14:17:00.000Z", + "username": "reporting_account", + "note": "I'm an account made for an example report notification. I'm the one that will do the reporting.", + "approval_pending": false, + "avatar_static": "https://develop.ilja.space/images/avi.png", + "header": "https://develop.ilja.space/images/banner.png", + "registration_reason": null, + "confirmation_pending": false, + "header_static": "https://develop.ilja.space/images/banner.png", + "following_count": 0, + "tags": [] + }, + "content": "This is the report created by "reporting_account". It reports "reported_account".", + "created_at": "2020-09-03T14:22:59.000Z", + "id": "9ymggNcUyfIW8Cq1zM", + "notes": [], + "state": "open", + "statuses": [ + { + "account": { + "acct": "reported_account", + "avatar": "https://develop.ilja.space/images/avi.png", + "avatar_static": "https://develop.ilja.space/images/avi.png", + "bot": false, + "created_at": "2020-09-03T14:18:21.000Z", + "display_name": "Reported Account", + "emojis": [], + "fields": [], + "followers_count": 0, + "following_count": 0, + "header": "https://develop.ilja.space/images/banner.png", + "header_static": "https://develop.ilja.space/images/banner.png", + "id": "9ymgGklmHjZ2OpxVLM", + "locked": false, + "note": "I'm an account made for an example report notification. I'm the one that will be reported.", + "pleroma": { + "accepts_chat_messages": true, + "ap_id": "https://develop.ilja.space/users/reported_account", + "background_image": null, + "confirmation_pending": false, + "favicon": null, + "hide_favorites": true, + "hide_followers": false, + "hide_followers_count": false, + "hide_follows": false, + "hide_follows_count": false, + "is_admin": false, + "is_moderator": false, + "relationship": {}, + "skip_thread_containment": false, + "tags": [] + }, + "source": { + "fields": [], + "note": "", + "pleroma": { + "actor_type": "Person", + "discoverable": false + }, + "sensitive": false + }, + "statuses_count": 1, + "url": "https://develop.ilja.space/users/reported_account", + "username": "reported_account" + }, + "application": { + "name": "Web", + "website": null + }, + "bookmarked": false, + "card": null, + "content": "A post I made that will be included in the report", + "created_at": "2020-09-03T14:18:51.000Z", + "emojis": [], + "favourited": false, + "favourites_count": 0, + "id": "9ymgJaQxAbTzDDZMJs", + "in_reply_to_account_id": null, + "in_reply_to_id": null, + "language": null, + "media_attachments": [], + "mentions": [], + "muted": false, + "pinned": false, + "pleroma": { + "content": { + "text/plain": "A post I made that will be included in the report" + }, + "conversation_id": 7, + "direct_conversation_id": null, + "emoji_reactions": [], + "expires_at": null, + "in_reply_to_account_acct": null, + "local": true, + "parent_visible": false, + "spoiler_text": { + "text/plain": "" + }, + "thread_muted": false + }, + "poll": null, + "reblog": null, + "reblogged": false, + "reblogs_count": 0, + "replies_count": 0, + "sensitive": false, + "spoiler_text": "", + "tags": [], + "text": null, + "uri": "https://develop.ilja.space/objects/8fe7611a-07e7-403a-ae08-f74580b6cc53", + "url": "https://develop.ilja.space/notice/9ymgJaQxAbTzDDZMJs", + "visibility": "public" + } + ] + }, + "type": "pleroma:report" +} +/* eslint-enable */ + const fetchTimeline = ({ timeline, credentials, @@ -561,6 +840,9 @@ const fetchTimeline = ({ .then((data) => data.json()) .then((data) => { if (!data.errors) { + if (isNotifications) { + return { data: [parseNotification(report)], pagination } + } return { data: data.map(isNotifications ? parseNotification : parseStatus), pagination } } else { data.status = status diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 0fd01176..c71bc15a 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -376,7 +376,7 @@ export const parseNotification = (data) => { if (data.report) { output.report = data.report output.report.content = data.report.content - output.report.acct = parseUser(data.report.acct) + output.report.acct = parseUser(data.report.account) output.report.actor = parseUser(data.report.actor) output.report.statuses = data.report.statuses.map(parseStatus) } diff --git a/src/services/notifications_fetcher/notifications_fetcher.service.js b/src/services/notifications_fetcher/notifications_fetcher.service.js index beeb167c..91861b21 100644 --- a/src/services/notifications_fetcher/notifications_fetcher.service.js +++ b/src/services/notifications_fetcher/notifications_fetcher.service.js @@ -61,6 +61,7 @@ const fetchNotifications = ({ store, args, older }) => { messageArgs: [error.message], timeout: 5000 }) + console.error(error) }) } -- cgit v1.2.3-70-g09d2 From a4e3cccf1cba238e5bfd96ea8c60f0d12bc6b7aa Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Wed, 6 Jan 2021 18:31:34 +0200 Subject: somewhat workign version still with fixture --- src/components/notification/notification.js | 3 + src/components/notification/notification.scss | 28 +++ src/components/notification/notification.vue | 34 ++++ src/components/notifications/notifications.js | 1 + src/components/notifications/notifications.scss | 6 +- src/i18n/en.json | 3 +- src/modules/config.js | 3 +- src/services/api/api.service.js | 197 +++++++++++---------- .../entity_normalizer/entity_normalizer.service.js | 1 - 9 files changed, 177 insertions(+), 99 deletions(-) (limited to 'src') diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index 4aa9affd..a920bb3e 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -76,6 +76,9 @@ const Notification = { this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id }) this.$store.dispatch('removeFollowRequest', this.user) }) + }, + testlog (a) { + console.log(a) } }, computed: { diff --git a/src/components/notification/notification.scss b/src/components/notification/notification.scss index f5905560..b103db86 100644 --- a/src/components/notification/notification.scss +++ b/src/components/notification/notification.scss @@ -56,6 +56,34 @@ margin: 0 0.1em; } + .report-content { + margin: 0.5em 0; + } + + .reported-status { + border: 1px solid $fallback--faint; + border-color: var(--faint, $fallback--faint); + border-radius: $fallback--inputRadius; + border-radius: var(--inputRadius, $fallback--inputRadius); + color: $fallback--text; + color: var(--text, $fallback--text); + display: block; + padding: 0.5em; + margin: 0.5em 0; + + .status-content { + pointer-events: none; + } + + .reported-status-name { + font-weight: bold; + } + + .reported-status-timeago { + float: right; + } + } + &.-type--repeat .type-icon { color: $fallback--cGreen; color: var(--cGreen, $fallback--cGreen); diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index f56aa977..39e3bda0 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -106,6 +106,9 @@ + + {{ $t('notifications.submitted_report') }} +
+
+ Reported user: + + @{{ notification.report.acct.screen_name }} + + +
+
+ Reported statuses: + + + {{ status.user.name }} + + + +
+
diff --git a/src/components/settings_modal/tabs/profile_tab.js b/src/components/settings_modal/tabs/profile_tab.js index 64079fcd..bee8a7bb 100644 --- a/src/components/settings_modal/tabs/profile_tab.js +++ b/src/components/settings_modal/tabs/profile_tab.js @@ -8,6 +8,9 @@ import EmojiInput from 'src/components/emoji_input/emoji_input.vue' import suggestor from 'src/components/emoji_input/suggestor.js' import Autosuggest from 'src/components/autosuggest/autosuggest.vue' import Checkbox from 'src/components/checkbox/checkbox.vue' +import BooleanSetting from '../helpers/boolean_setting.vue' +import SharedComputedObject from '../helpers/shared_computed_object.js' + import { library } from '@fortawesome/fontawesome-svg-core' import { faTimes, @@ -27,18 +30,10 @@ const ProfileTab = { newName: this.$store.state.users.currentUser.name_unescaped, newBio: unescape(this.$store.state.users.currentUser.description), newLocked: this.$store.state.users.currentUser.locked, - newNoRichText: this.$store.state.users.currentUser.no_rich_text, - newDefaultScope: this.$store.state.users.currentUser.default_scope, newFields: this.$store.state.users.currentUser.fields.map(field => ({ name: field.name, value: field.value })), - hideFollows: this.$store.state.users.currentUser.hide_follows, - hideFollowers: this.$store.state.users.currentUser.hide_followers, - hideFollowsCount: this.$store.state.users.currentUser.hide_follows_count, - hideFollowersCount: this.$store.state.users.currentUser.hide_followers_count, showRole: this.$store.state.users.currentUser.show_role, role: this.$store.state.users.currentUser.role, - discoverable: this.$store.state.users.currentUser.discoverable, bot: this.$store.state.users.currentUser.bot, - allowFollowingMove: this.$store.state.users.currentUser.allow_following_move, pickAvatarBtnVisible: true, bannerUploading: false, backgroundUploading: false, @@ -54,12 +49,14 @@ const ProfileTab = { EmojiInput, Autosuggest, ProgressButton, - Checkbox + Checkbox, + BooleanSetting }, computed: { user () { return this.$store.state.users.currentUser }, + ...SharedComputedObject(), emojiUserSuggestor () { return suggestor({ emoji: [ @@ -123,15 +120,7 @@ const ProfileTab = { /* eslint-disable camelcase */ display_name: this.newName, fields_attributes: this.newFields.filter(el => el != null), - default_scope: this.newDefaultScope, - no_rich_text: this.newNoRichText, - hide_follows: this.hideFollows, - hide_followers: this.hideFollowers, - discoverable: this.discoverable, bot: this.bot, - allow_following_move: this.allowFollowingMove, - hide_follows_count: this.hideFollowsCount, - hide_followers_count: this.hideFollowersCount, show_role: this.showRole /* eslint-enable camelcase */ } }).then((user) => { diff --git a/src/components/settings_modal/tabs/profile_tab.vue b/src/components/settings_modal/tabs/profile_tab.vue index bb3c301d..2cf3e8be 100644 --- a/src/components/settings_modal/tabs/profile_tab.vue +++ b/src/components/settings_modal/tabs/profile_tab.vue @@ -25,61 +25,6 @@ class="bio resize-height" /> -

- - {{ $t('settings.lock_account_description') }} - -

-
- -
- -
-
-

- - {{ $t('settings.no_rich_text_description') }} - -

-

- - {{ $t('settings.hide_follows_description') }} - -

-

- - {{ $t('settings.hide_follows_count_description') }} - -

-

- - {{ $t('settings.hide_followers_description') }} - -

-

- - {{ $t('settings.hide_followers_count_description') }} - -

-

- - {{ $t('settings.allow_following_move') }} - -

-

- - {{ $t('settings.discoverable') }} - -

{{ $t('settings.profile_fields.label') }}

{{ $t('settings.avatar_size_instruction') }}

-
- @@ -269,6 +208,67 @@ {{ $t('settings.save') }}
+
+

{{ $t('settings.account_privacy') }}

+
    +
  • + + {{ $t('settings.lock_account_description') }} + +
  • +
  • + + {{ $t('settings.discoverable') }} + +
  • +
  • + + {{ $t('settings.allow_following_move') }} + +
  • +
  • + + {{ $t('settings.hide_favorites_description') }} + +
  • +
  • + + {{ $t('settings.hide_followers_description') }} + +
      +
    • + + {{ $t('settings.hide_followers_count_description') }} + +
    • +
    +
  • +
  • + + {{ $t('settings.hide_follows_description') }} + +
      +
    • + + {{ $t('settings.hide_follows_count_description') }} + +
    • +
    +
  • +
+
diff --git a/src/i18n/en.json b/src/i18n/en.json index 8eb7fcc6..932e8af5 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -259,11 +259,14 @@ }, "settings": { "app_name": "App name", + "expert_mode": "Expert mode", "save": "Save changes", "security": "Security", "setting_changed": "Setting is different from default", + "setting_server_side": "This setting is tied to your profile and affects all sessions and clients", "enter_current_password_to_confirm": "Enter your current password to confirm your identity", "post_look_feel": "Posts Look & Feel", + "mention_links": "Mention links", "mfa": { "otp": "OTP", "setup_otp": "Setup OTP", @@ -400,6 +403,7 @@ "name": "Label", "value": "Content" }, + "account_privacy": "Privacy", "use_contain_fit": "Don't crop the attachment in thumbnails", "name": "Name", "name_bio": "Name & bio", @@ -417,6 +421,7 @@ "no_rich_text_description": "Strip rich text formatting from all posts", "no_blocks": "No blocks", "no_mutes": "No mutes", + "hide_favorites_description": "Don't show list of my favorites (people still get notified)", "hide_follows_description": "Don't show who I'm following", "hide_followers_description": "Don't show who's following me", "hide_follows_count_description": "Don't show follow count", diff --git a/src/main.js b/src/main.js index 3895da89..73bd49ed 100644 --- a/src/main.js +++ b/src/main.js @@ -11,6 +11,7 @@ import statusesModule from './modules/statuses.js' import usersModule from './modules/users.js' import apiModule from './modules/api.js' import configModule from './modules/config.js' +import serverSideConfigModule from './modules/serverSideConfig.js' import shoutModule from './modules/shout.js' import oauthModule from './modules/oauth.js' import authFlowModule from './modules/auth_flow.js' @@ -88,6 +89,7 @@ const persistedStateOptions = { users: usersModule, api: apiModule, config: configModule, + serverSideConfig: serverSideConfigModule, shout: shoutModule, oauth: oauthModule, authFlow: authFlowModule, diff --git a/src/modules/config.js b/src/modules/config.js index 20979174..775ee398 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -16,6 +16,7 @@ export const multiChoiceProperties = [ ] export const defaultState = { + expertLevel: 0, // used to track which settings to show and hide colors: {}, theme: undefined, customTheme: undefined, diff --git a/src/modules/serverSideConfig.js b/src/modules/serverSideConfig.js new file mode 100644 index 00000000..75ea91be --- /dev/null +++ b/src/modules/serverSideConfig.js @@ -0,0 +1,111 @@ +import { get, set } from 'lodash' + +export const settingsMapGet = { + 'defaultScope': 'source.privacy', + 'defaultNSFW': 'source.sensitive', + 'stripRichContent': 'source.pleroma.no_rich_content', + // Privacy + 'locked': 'locked', + 'acceptChatMessages': 'pleroma.accepts_chat_messages', + 'allowFollowingMove': 'pleroma.allow_following_move', + 'discoverable': 'source.discoverable', + 'hideFavorites': 'pleroma.hide_favorites', + 'hideFollowers': 'pleroma.hide_followers', + 'hideFollows': 'pleroma.hide_follows', + 'hideFollowersCount': 'pleroma.hide_followers_count', + 'hideFollowsCount': 'pleroma.hide_follows_count', + // NotificationSettingsAPIs + 'webPushHideContents': 'pleroma.notification_settings.hide_notification_contents', + 'blockNotificationsFromStrangers': 'pleroma.notification_settings.block_from_strangers' +} + +export const settingsMapSet = { + 'defaultScope': 'source.privacy', + 'defaultNSFW': 'source.sensitive', + 'stripRichContent': 'source.pleroma.no_rich_content', + // Privacy + 'locked': 'locked', + 'acceptChatMessages': 'accepts_chat_messages', + 'allowFollowingMove': 'allow_following_move', + 'discoverable': 'source.discoverable', + 'hideFavorites': 'hide_favorites', + 'hideFollowers': 'hide_followers', + 'hideFollows': 'hide_follows', + 'hideFollowersCount': 'hide_followers_count', + 'hideFollowsCount': 'hide_follows_count', + // NotificationSettingsAPIs + 'webPushHideContents': 'hide_notification_contents', + 'blockNotificationsFromStrangers': 'block_from_strangers' +} + +export const customAPIs = { + __defaultApi: 'updateProfile', + 'webPushHideContents': 'updateNotificationSettings', + 'blockNotificationsFromStrangers': 'updateNotificationSettings' +} + +export const defaultState = Object.fromEntries(Object.keys(settingsMapGet).map(key => [key, undefined])) + +const serverSideConfig = { + state: { ...defaultState }, + mutations: { + confirmServerSideOption (state, { name, value }) { + set(state, name, value) + }, + wipeServerSideOption (state, { name }) { + set(state, name, undefined) + }, + // Set the settings based on their path location + setCurrentUser (state, user) { + Object.entries(settingsMapGet).forEach(([name, path]) => { + set(state, name, get(user._original, path)) + }) + } + }, + actions: { + setServerSideOption ({ rootState, state, commit, dispatch }, { name, value }) { + const oldValue = get(state, name) + const params = {} + const path = settingsMapSet[name] + if (!path) throw new Error('Invalid server-side setting') + commit('wipeServerSideOption', { name }) + const customAPIName = customAPIs[name] || customAPIs.__defaultApi + const api = rootState.api.backendInteractor[customAPIName] + let prefix = '' + switch (customAPIName) { + case 'updateNotificationSettings': + prefix = 'settings.' + break + default: + prefix = 'params.' + break + } + + set(params, prefix + path, value) + api(params) + .then((result) => { + switch (customAPIName) { + case 'updateNotificationSettings': + console.log(result) + if (result.status === 'success') { + commit('confirmServerSideOption', { name, value }) + } else { + commit('confirmServerSideOption', { name, value: oldValue }) + } + break + default: + commit('addNewUsers', [result]) + commit('setCurrentUser', result) + break + } + console.log(state) + }) + .catch((e) => { + console.warn('Error setting server-side option:', e) + commit('confirmServerSideOption', { name, value: oldValue }) + }) + } + } +} + +export default serverSideConfig diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 7025d803..f219c161 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -44,6 +44,7 @@ export const parseUser = (data) => { const mastoShort = masto && !data.hasOwnProperty('avatar') output.id = String(data.id) + output._original = data // used for server-side settings if (masto) { output.screen_name = data.acct -- cgit v1.2.3-70-g09d2 From b1b9260a1df561a38b9bb904e103cccb37df8ea6 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 22 Feb 2022 23:32:12 +0200 Subject: new defaults --- src/modules/config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/modules/config.js b/src/modules/config.js index 775ee398..e5321507 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -37,12 +37,12 @@ export const defaultState = { preloadImage: true, loopVideo: true, loopVideoSilentOnly: true, - streaming: false, + streaming: true, emojiReactionsOnTimeline: true, alwaysShowNewPostButton: false, autohideFloatingPostButton: false, pauseOnUnfocused: true, - stopGifs: false, + stopGifs: true, replyVisibility: 'all', notificationVisibility: { follows: true, @@ -70,7 +70,7 @@ export const defaultState = { hideFilteredStatuses: undefined, // instance default playVideosInModal: false, useOneClickNsfw: false, - useContainFit: false, + useContainFit: true, greentext: undefined, // instance default useAtIcon: undefined, // instance default mentionLinkDisplay: undefined, // instance default -- cgit v1.2.3-70-g09d2 From 9623b0e1409e85c5598989f0cd13f3ccbb504bd2 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 24 Feb 2022 14:41:55 +0200 Subject: better phrasing --- src/i18n/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/i18n/en.json b/src/i18n/en.json index 932e8af5..a66aaa0b 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -259,7 +259,7 @@ }, "settings": { "app_name": "App name", - "expert_mode": "Expert mode", + "expert_mode": "Show advanced", "save": "Save changes", "security": "Security", "setting_changed": "Setting is different from default", -- cgit v1.2.3-70-g09d2 From f626da838a7abeb3a2d3cd5f71ee4eb2ca272361 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 24 Feb 2022 15:00:08 +0200 Subject: revert to using local setting for default nsfw since backend is broken --- src/components/post_status_form/post_status_form.js | 1 + src/components/settings_modal/tabs/general_tab.vue | 3 ++- src/modules/serverSideConfig.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index fe07309f..9d7bbd75 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -117,6 +117,7 @@ const PostStatusForm = { ? this.copyMessageScope : this.$store.state.users.currentUser.default_scope + // const { defaultNSFW: sensitiveByDefault } = this.$store.state.serverSideConfig const { postContentType: contentType, sensitiveByDefault } = this.$store.getters.mergedConfig return { diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index 4accf0c1..5db70d77 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -221,7 +221,8 @@
  • - + + {{ $t('settings.sensitive_by_default') }}
  • diff --git a/src/modules/serverSideConfig.js b/src/modules/serverSideConfig.js index 75ea91be..ea2dc5e3 100644 --- a/src/modules/serverSideConfig.js +++ b/src/modules/serverSideConfig.js @@ -2,7 +2,7 @@ import { get, set } from 'lodash' export const settingsMapGet = { 'defaultScope': 'source.privacy', - 'defaultNSFW': 'source.sensitive', + 'defaultNSFW': 'source.sensitive', // BROKEN: pleroma/pleroma#2837 'stripRichContent': 'source.pleroma.no_rich_content', // Privacy 'locked': 'locked', -- cgit v1.2.3-70-g09d2 From 819b76026101ddc0363118f240049a0019ebb4d6 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 26 Feb 2022 01:53:01 +0100 Subject: Fix up and code review * Check if it works properly * Notifs are shown as BE returns them * The Interaction view has Reports, but only when you're mod or admin * Do some extra translations * Fix some console spam --- src/components/interactions/interactions.js | 3 ++- src/i18n/en.json | 2 ++ src/i18n/nl.json | 13 +++++++++++++ src/modules/reports.js | 5 +---- src/services/api/api.service.js | 3 ++- src/services/notification_utils/notification_utils.js | 2 +- .../notifications_fetcher/notifications_fetcher.service.js | 4 +--- 7 files changed, 22 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/components/interactions/interactions.js b/src/components/interactions/interactions.js index 54275a7b..53ec7d49 100644 --- a/src/components/interactions/interactions.js +++ b/src/components/interactions/interactions.js @@ -13,7 +13,8 @@ const Interactions = { data () { return { allowFollowingMove: this.$store.state.users.currentUser.allow_following_move, - filterMode: tabModeDict['mentions'] + filterMode: tabModeDict['mentions'], + canSeeReports: ['moderator', 'admin'].includes(this.$store.state.users.currentUser.role) } }, methods: { diff --git a/src/i18n/en.json b/src/i18n/en.json index 3bdd42e3..9e74840f 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -176,6 +176,8 @@ "interactions": { "favs_repeats": "Repeats and Favorites", "follows": "New follows", + "emoji_reactions": "Emoji Reactions", + "reports": "Reports", "moves": "User migrates", "load_older": "Load older interactions" }, diff --git a/src/i18n/nl.json b/src/i18n/nl.json index a01e57a0..8da07ac7 100644 --- a/src/i18n/nl.json +++ b/src/i18n/nl.json @@ -661,6 +661,8 @@ "interactions": { "favs_repeats": "Herhalingen en Favorieten", "follows": "Nieuwe volgingen", + "emoji_reactions": "Emoji Reacties", + "reports": "Rapportages", "moves": "Gebruiker migreert", "load_older": "Oudere interacties laden" }, @@ -669,6 +671,17 @@ "error": "Niet gevonden.", "remote_user_resolver": "Externe gebruikers zoeker" }, + "report": { + "reporter": "Reporteerder:", + "reported_user": "Gerapporteerde gebruiker:", + "reported_statuses": "Gerapporteerde statussen:", + "notes": "Notas:", + "state": "Status:", + "state_open": "Open", + "state_closed": "Gesloten", + "state_resolved": "Opgelost" + }, + "selectable_list": { "select_all": "Alles selecteren" }, diff --git a/src/modules/reports.js b/src/modules/reports.js index b25e9ee9..925792c0 100644 --- a/src/modules/reports.js +++ b/src/modules/reports.js @@ -43,11 +43,8 @@ const reports = { }, setReportState ({ commit, dispatch, rootState }, { id, state }) { const oldState = rootState.reports.reports[id].state - console.log(oldState, state) commit('setReportState', { id, state }) - rootState.api.backendInteractor.setReportState({ id, state }).then(report => { - console.log(report) - }).catch(e => { + rootState.api.backendInteractor.setReportState({ id, state }).catch(e => { console.error('Failed to set report state', e) dispatch('pushGlobalNotice', { level: 'error', diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index e60010fe..27ea5199 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -1270,7 +1270,8 @@ const deleteChatMessage = ({ chatId, messageId, credentials }) => { } const setReportState = ({ id, state, credentials }) => { - // Can't use promisedRequest because on OK this does not return json + // TODO: Can't use promisedRequest because on OK this does not return json + // See https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1322 return fetch(PLEROMA_ADMIN_REPORTS, { headers: { ...authHeaders(credentials), diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js index dff97aa2..b338eb8b 100644 --- a/src/services/notification_utils/notification_utils.js +++ b/src/services/notification_utils/notification_utils.js @@ -93,7 +93,7 @@ export const prepareNotificationObject = (notification, i18n) => { i18nString = 'follow_request' break case 'pleroma:report': - i18nString = 'reported' + i18nString = 'submitted_report' break } diff --git a/src/services/notifications_fetcher/notifications_fetcher.service.js b/src/services/notifications_fetcher/notifications_fetcher.service.js index 2da6d646..4ecb348e 100644 --- a/src/services/notifications_fetcher/notifications_fetcher.service.js +++ b/src/services/notifications_fetcher/notifications_fetcher.service.js @@ -24,9 +24,7 @@ const fetchAndUpdate = ({ store, credentials, older = false }) => { const timelineData = rootState.statuses.notifications const hideMutedPosts = getters.mergedConfig.hideMutedPosts - if (rootState.users.currentUser.role === 'admin') { - args['includeTypes'] = mastoApiNotificationTypes - } + args['includeTypes'] = mastoApiNotificationTypes args['withMuted'] = !hideMutedPosts args['timeline'] = 'notifications' -- cgit v1.2.3-70-g09d2 From c9e4b6e7a10b614bcf0cc0b91b7540b7b4fdcca2 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 26 Feb 2022 02:13:43 +0100 Subject: Make linter happy `npm run lint` gave warnings for two files, fixed them with `./node_modules/.bin/eslint --fix $FILENAME` --- src/components/attachment/attachment.vue | 19 +++++++++++-------- src/components/gallery/gallery.vue | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue index 59173759..c4399f30 100644 --- a/src/components/attachment/attachment.vue +++ b/src/components/attachment/attachment.vue @@ -81,56 +81,56 @@ @@ -160,7 +160,10 @@ :href="attachment.url" target="_blank" > - +

    {{ localDescription }}

    diff --git a/src/components/gallery/gallery.vue b/src/components/gallery/gallery.vue index f9cad8a9..f2e1b5ce 100644 --- a/src/components/gallery/gallery.vue +++ b/src/components/gallery/gallery.vue @@ -26,8 +26,8 @@ :size="size" :editable="editable" :remove="removeAttachment" - :shiftUp="!(attachmentIndex === 0 && rowIndex === 0) && shiftUpAttachment" - :shiftDn="!(attachmentIndex === row.items.length - 1 && rowIndex === rows.length - 1) && shiftDnAttachment" + :shift-up="!(attachmentIndex === 0 && rowIndex === 0) && shiftUpAttachment" + :shift-dn="!(attachmentIndex === row.items.length - 1 && rowIndex === rows.length - 1) && shiftDnAttachment" :edit="editAttachment" :description="descriptions && descriptions[attachment.id]" :hide-description="size === 'small' || tooManyAttachments && hidingLong" -- cgit v1.2.3-70-g09d2 From c07c0b22604ac57f91f08ed330eee98ee82e214e Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 28 Feb 2022 17:43:08 +0200 Subject: fix firefox rendering (??????????) --- src/components/settings_modal/helpers/boolean_setting.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/components/settings_modal/helpers/boolean_setting.vue b/src/components/settings_modal/helpers/boolean_setting.vue index c82cf23f..3a7bd805 100644 --- a/src/components/settings_modal/helpers/boolean_setting.vue +++ b/src/components/settings_modal/helpers/boolean_setting.vue @@ -14,9 +14,7 @@ > - - - + -- cgit v1.2.3-70-g09d2 From e3d602fdccb0dfe211fd3950210cdf8fda43bf95 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 28 Feb 2022 17:45:07 +0200 Subject: revert changes related to streaming/firehose setting, reword it so it's not confused with websocket streaming --- src/components/settings_modal/tabs/general_tab.vue | 3 +-- src/i18n/en.json | 4 ++-- src/modules/config.js | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index 5db70d77..7944b03c 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -27,7 +27,7 @@
  • - + {{ $t('settings.streaming') }}
      {{ $t('settings.pause_on_unfocused') }} diff --git a/src/i18n/en.json b/src/i18n/en.json index a66aaa0b..da5e662d 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -435,7 +435,7 @@ "valid_until": "Valid until", "revoke_token": "Revoke", "panelRadius": "Panels", - "pause_on_unfocused": "Pause streaming when tab is not focused", + "pause_on_unfocused": "Pause when tab is not focused", "presets": "Presets", "profile_background": "Profile background", "profile_banner": "Profile banner", @@ -473,7 +473,7 @@ "post_status_content_type": "Post status content type", "sensitive_by_default": "Mark posts as sensitive by default", "stop_gifs": "Pause animated images until you hover on them", - "streaming": "Enable automatic streaming of new posts when scrolled to the top", + "streaming": "Automatically show new posts when scrolled to the top", "user_mutes": "Users", "useStreamingApi": "Receive posts and notifications real-time", "useStreamingApiWarning": "(Not recommended, experimental, known to skip posts)", diff --git a/src/modules/config.js b/src/modules/config.js index e5321507..86601564 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -37,7 +37,7 @@ export const defaultState = { preloadImage: true, loopVideo: true, loopVideoSilentOnly: true, - streaming: true, + streaming: false, emojiReactionsOnTimeline: true, alwaysShowNewPostButton: false, autohideFloatingPostButton: false, -- cgit v1.2.3-70-g09d2 From 3a5ad18aca6a7303e6f6b97dd3f0919d5532184c Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 28 Feb 2022 18:00:38 +0200 Subject: fix stripping rich content not working --- src/modules/serverSideConfig.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/serverSideConfig.js b/src/modules/serverSideConfig.js index ea2dc5e3..c9d148d1 100644 --- a/src/modules/serverSideConfig.js +++ b/src/modules/serverSideConfig.js @@ -3,7 +3,7 @@ import { get, set } from 'lodash' export const settingsMapGet = { 'defaultScope': 'source.privacy', 'defaultNSFW': 'source.sensitive', // BROKEN: pleroma/pleroma#2837 - 'stripRichContent': 'source.pleroma.no_rich_content', + 'stripRichContent': 'source.pleroma.no_rich_text', // Privacy 'locked': 'locked', 'acceptChatMessages': 'pleroma.accepts_chat_messages', @@ -22,7 +22,7 @@ export const settingsMapGet = { export const settingsMapSet = { 'defaultScope': 'source.privacy', 'defaultNSFW': 'source.sensitive', - 'stripRichContent': 'source.pleroma.no_rich_content', + 'stripRichContent': 'no_rich_text', // Privacy 'locked': 'locked', 'acceptChatMessages': 'accepts_chat_messages', -- cgit v1.2.3-70-g09d2 From 8bb97fbfeb8f34c36aec96ee175d6eced49c1fb4 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 28 Feb 2022 18:01:41 +0200 Subject: fix settings behaving erratically and not updating properly --- src/modules/serverSideConfig.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/serverSideConfig.js b/src/modules/serverSideConfig.js index c9d148d1..2db6fc06 100644 --- a/src/modules/serverSideConfig.js +++ b/src/modules/serverSideConfig.js @@ -44,7 +44,7 @@ export const customAPIs = { 'blockNotificationsFromStrangers': 'updateNotificationSettings' } -export const defaultState = Object.fromEntries(Object.keys(settingsMapGet).map(key => [key, undefined])) +export const defaultState = Object.fromEntries(Object.keys(settingsMapGet).map(key => [key, null])) const serverSideConfig = { state: { ...defaultState }, @@ -53,7 +53,7 @@ const serverSideConfig = { set(state, name, value) }, wipeServerSideOption (state, { name }) { - set(state, name, undefined) + set(state, name, null) }, // Set the settings based on their path location setCurrentUser (state, user) { -- cgit v1.2.3-70-g09d2 From cf58df17f6624362ea51f8813874250eff6d185a Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 28 Feb 2022 18:04:13 +0200 Subject: hidden away more settings when logged out --- src/components/settings_modal/tabs/filtering_tab.vue | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/components/settings_modal/tabs/filtering_tab.vue b/src/components/settings_modal/tabs/filtering_tab.vue index cd7f0bc4..0352e887 100644 --- a/src/components/settings_modal/tabs/filtering_tab.vue +++ b/src/components/settings_modal/tabs/filtering_tab.vue @@ -22,6 +22,7 @@
    • {{ $t('settings.hide_muted_threads') }} @@ -30,6 +31,7 @@
    • {{ $t('settings.hide_muted_posts') }} @@ -46,6 +48,7 @@ id="replyVisibility" path="replyVisibility" :options="replyVisibilityOptions" + v-if="user" > {{ $t('settings.replies_in_timeline') }} -- cgit v1.2.3-70-g09d2 From 67319d0e5b0b36a440dcaf35119e41046cc6e3fd Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 28 Feb 2022 18:15:07 +0200 Subject: fix typos in profile page --- src/components/settings_modal/tabs/profile_tab.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/components/settings_modal/tabs/profile_tab.vue b/src/components/settings_modal/tabs/profile_tab.vue index 2cf3e8be..699fdcf4 100644 --- a/src/components/settings_modal/tabs/profile_tab.vue +++ b/src/components/settings_modal/tabs/profile_tab.vue @@ -242,7 +242,7 @@
    • {{ $t('settings.hide_followers_count_description') }} @@ -260,7 +260,7 @@
    • {{ $t('settings.hide_follows_count_description') }} -- cgit v1.2.3-70-g09d2 From f4b36a9ebf99cc69ab93c148e488401daf3713b7 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 28 Feb 2022 18:15:21 +0200 Subject: fix errors in choicesetting --- src/components/settings_modal/helpers/choice_setting.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/settings_modal/helpers/choice_setting.js b/src/components/settings_modal/helpers/choice_setting.js index 07d0f76d..4677d4c1 100644 --- a/src/components/settings_modal/helpers/choice_setting.js +++ b/src/components/settings_modal/helpers/choice_setting.js @@ -1,10 +1,12 @@ import { get, set } from 'lodash' import Select from 'src/components/select/select.vue' import ModifiedIndicator from './modified_indicator.vue' +import ServerSideIndicator from './server_side_indicator.vue' export default { components: { Select, - ModifiedIndicator + ModifiedIndicator, + ServerSideIndicator }, props: [ 'path', @@ -28,6 +30,9 @@ export default { defaultState () { return get(this.$parent, this.pathDefault) }, + isServerSide () { + return this.path.startsWith('serverSide_') + }, isChanged () { return !this.path.startsWith('serverSide_') && this.state !== this.defaultState }, -- cgit v1.2.3-70-g09d2 From 39909c8a8590e866082da5d2528b4df2898f2bf5 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 28 Feb 2022 18:17:13 +0200 Subject: pre-emptively wipe serverside settings on logout --- src/modules/serverSideConfig.js | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/modules/serverSideConfig.js b/src/modules/serverSideConfig.js index 2db6fc06..4f0cd965 100644 --- a/src/modules/serverSideConfig.js +++ b/src/modules/serverSideConfig.js @@ -55,6 +55,11 @@ const serverSideConfig = { wipeServerSideOption (state, { name }) { set(state, name, null) }, + wipeAllServerSideOptions (state) { + Object.keys(settingsMapGet).forEach(key => { + set(state, key, null) + }) + }, // Set the settings based on their path location setCurrentUser (state, user) { Object.entries(settingsMapGet).forEach(([name, path]) => { @@ -104,6 +109,9 @@ const serverSideConfig = { console.warn('Error setting server-side option:', e) commit('confirmServerSideOption', { name, value: oldValue }) }) + }, + logout ({ commit }) { + commit('wipeAllServerSideOptions') } } } -- cgit v1.2.3-70-g09d2 From 77bb0b553062b91a69fbf92ce7540565f098951f Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 28 Feb 2022 18:23:32 +0200 Subject: lint --- src/components/attachment/attachment.vue | 19 ++- src/components/gallery/gallery.vue | 4 +- .../settings_modal/helpers/boolean_setting.vue | 4 +- .../settings_modal/helpers/choice_setting.vue | 4 +- src/components/settings_modal/settings_modal.vue | 4 +- .../settings_modal/tabs/filtering_tab.vue | 16 +- src/components/settings_modal/tabs/general_tab.js | 2 +- src/components/settings_modal/tabs/general_tab.vue | 167 +++++++++++++++------ .../settings_modal/tabs/notifications_tab.vue | 15 +- src/components/settings_modal/tabs/profile_tab.vue | 7 +- 10 files changed, 168 insertions(+), 74 deletions(-) (limited to 'src') diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue index 59173759..c4399f30 100644 --- a/src/components/attachment/attachment.vue +++ b/src/components/attachment/attachment.vue @@ -81,56 +81,56 @@ @@ -160,7 +160,10 @@ :href="attachment.url" target="_blank" > - +

      {{ localDescription }}

      diff --git a/src/components/gallery/gallery.vue b/src/components/gallery/gallery.vue index f9cad8a9..f2e1b5ce 100644 --- a/src/components/gallery/gallery.vue +++ b/src/components/gallery/gallery.vue @@ -26,8 +26,8 @@ :size="size" :editable="editable" :remove="removeAttachment" - :shiftUp="!(attachmentIndex === 0 && rowIndex === 0) && shiftUpAttachment" - :shiftDn="!(attachmentIndex === row.items.length - 1 && rowIndex === rows.length - 1) && shiftDnAttachment" + :shift-up="!(attachmentIndex === 0 && rowIndex === 0) && shiftUpAttachment" + :shift-dn="!(attachmentIndex === row.items.length - 1 && rowIndex === rows.length - 1) && shiftDnAttachment" :edit="editAttachment" :description="descriptions && descriptions[attachment.id]" :hide-description="size === 'small' || tooManyAttachments && hidingLong" diff --git a/src/components/settings_modal/helpers/boolean_setting.vue b/src/components/settings_modal/helpers/boolean_setting.vue index 3a7bd805..e0d825f2 100644 --- a/src/components/settings_modal/helpers/boolean_setting.vue +++ b/src/components/settings_modal/helpers/boolean_setting.vue @@ -1,7 +1,7 @@ diff --git a/src/components/settings_modal/helpers/choice_setting.vue b/src/components/settings_modal/helpers/choice_setting.vue index 845886ca..54f5d0a7 100644 --- a/src/components/settings_modal/helpers/choice_setting.vue +++ b/src/components/settings_modal/helpers/choice_setting.vue @@ -1,7 +1,7 @@ diff --git a/src/components/settings_modal/settings_modal.vue b/src/components/settings_modal/settings_modal.vue index 0aad1abb..1805c77f 100644 --- a/src/components/settings_modal/settings_modal.vue +++ b/src/components/settings_modal/settings_modal.vue @@ -109,8 +109,8 @@ - - {{ $t("settings.expert_mode")}} + + {{ $t("settings.expert_mode") }}
  • diff --git a/src/components/settings_modal/tabs/filtering_tab.vue b/src/components/settings_modal/tabs/filtering_tab.vue index 0352e887..e60a8a85 100644 --- a/src/components/settings_modal/tabs/filtering_tab.vue +++ b/src/components/settings_modal/tabs/filtering_tab.vue @@ -21,8 +21,8 @@
  • {{ $t('settings.hide_muted_threads') }} @@ -30,8 +30,8 @@
  • {{ $t('settings.hide_muted_posts') }} @@ -40,15 +40,18 @@
  • - + {{ $t('settings.hide_post_stats') }}
  • {{ $t('settings.replies_in_timeline') }} @@ -87,7 +90,10 @@ -
    +

    {{ $t('settings.user_profiles') }}

    • diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js index 9e4e282f..fe7deb6e 100644 --- a/src/components/settings_modal/tabs/general_tab.js +++ b/src/components/settings_modal/tabs/general_tab.js @@ -41,7 +41,7 @@ const GeneralTab = { ChoiceSetting, InterfaceLanguageSwitcher, ScopeSelector, - ServerSideIndicator, + ServerSideIndicator }, computed: { postFormats () { diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index 7944b03c..d4196c3d 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -27,7 +27,7 @@
    • - + {{ $t('settings.streaming') }}
      • - + {{ $t('settings.useStreamingApi') }}
        @@ -54,22 +57,34 @@
      • - + {{ $t('settings.virtual_scrolling') }}
      • - + {{ $t('settings.always_show_post_button') }}
      • - + {{ $t('settings.autohide_floating_post_button') }}
      • - + {{ $t('settings.hide_shoutbox') }}
      • @@ -84,18 +99,28 @@
      • - + {{ $t('settings.emoji_reactions_on_timeline') }}
      • - + {{ $t('settings.no_rich_text_description') }}
      • {{ $t('settings.attachments') }}

      • - + {{ $t('settings.use_contain_fit') }}
      • @@ -107,7 +132,8 @@
        • {{ $t('settings.preload_images') }} @@ -115,7 +141,8 @@
        • {{ $t('settings.use_one_click_nsfw') }} @@ -123,7 +150,10 @@
      • - + {{ $t('settings.loop_video') }}
        • {{ $t('settings.loop_video_silent_only') }} @@ -147,7 +178,10 @@
      • - + {{ $t('settings.play_videos_in_modal') }}
      • @@ -165,51 +199,74 @@ class="setting-list suboptions" >
      • - + {{ $t('settings.mention_link_show_tooltip') }}
      -
    • - - {{ $t('settings.use_at_icon') }} - -
    • -
    • - - {{ $t('settings.mention_link_show_avatar') }} - -
    • -
    • - - {{ $t('settings.mention_link_fade_domain') }} - -
    • -
    • - - {{ $t('settings.mention_link_bolden_you') }} - -
    • -

      {{ $t('settings.fun') }}

    • - + + {{ $t('settings.use_at_icon') }} + +
    • +
    • + + {{ $t('settings.mention_link_show_avatar') }} + +
    • +
    • + + {{ $t('settings.mention_link_fade_domain') }} + +
    • +
    • + + {{ $t('settings.mention_link_bolden_you') }} + +
    • +

      + {{ $t('settings.fun') }} +

      +
    • + {{ $t('settings.greentext') }}
    • - + {{ $t('settings.show_yous') }}
    -
    +

    {{ $t('settings.composing') }}

    • - + {{ $t('settings.scope_copy') }}
    • - + {{ $t('settings.subject_input_always_show') }}
    • @@ -255,22 +318,34 @@
    • - + {{ $t('settings.minimal_scopes_mode') }}
    • - + {{ $t('settings.always_show_post_button') }}
    • - + {{ $t('settings.autohide_floating_post_button') }}
    • - + {{ $t('settings.pad_emoji') }}
    • diff --git a/src/components/settings_modal/tabs/notifications_tab.vue b/src/components/settings_modal/tabs/notifications_tab.vue index 5e9ce91e..86be6095 100644 --- a/src/components/settings_modal/tabs/notifications_tab.vue +++ b/src/components/settings_modal/tabs/notifications_tab.vue @@ -46,16 +46,25 @@
    -
    +

    {{ $t('settings.notification_setting_privacy') }}

    • - + {{ $t('settings.enable_web_push_notifications') }}
    • - + {{ $t('settings.notification_setting_hide_notification_contents') }}
    • diff --git a/src/components/settings_modal/tabs/profile_tab.vue b/src/components/settings_modal/tabs/profile_tab.vue index 699fdcf4..e00f6e5b 100644 --- a/src/components/settings_modal/tabs/profile_tab.vue +++ b/src/components/settings_modal/tabs/profile_tab.vue @@ -101,7 +101,8 @@

      {{ $t('settings.avatar_size_instruction') }}

      -
      + @@ -243,7 +244,7 @@ + > {{ $t('settings.hide_followers_count_description') }} @@ -261,7 +262,7 @@ + > {{ $t('settings.hide_follows_count_description') }} -- cgit v1.2.3-70-g09d2 From 77b55a559be26e431f68188058c7900c2e16682c Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 28 Feb 2022 19:42:02 +0200 Subject: fix placeholder attachments opening new tab --- src/components/attachment/attachment.vue | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue index 59173759..d1d43ac3 100644 --- a/src/components/attachment/attachment.vue +++ b/src/components/attachment/attachment.vue @@ -12,6 +12,7 @@ :href="attachment.url" :alt="attachment.description" :title="attachment.description" + @click.prevent > {{ nsfw ? "NSFW / " : "" }}{{ edit ? '' : placeholderName }} -- cgit v1.2.3-70-g09d2 From fe0ed7e8f0941195547b924f99f6c0be707bf964 Mon Sep 17 00:00:00 2001 From: Alexander Tumin Date: Mon, 28 Feb 2022 23:07:20 +0300 Subject: Mute bot posts --- src/components/settings_modal/tabs/filtering_tab.vue | 5 +++++ src/components/status/status.js | 10 +++++++++- src/components/timeline/timeline_quick_settings.js | 7 +++++++ src/components/timeline/timeline_quick_settings.vue | 9 +++++++++ src/i18n/en.json | 1 + src/modules/config.js | 1 + src/modules/instance.js | 1 + 7 files changed, 33 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/settings_modal/tabs/filtering_tab.vue b/src/components/settings_modal/tabs/filtering_tab.vue index 50ee20e0..87567bef 100644 --- a/src/components/settings_modal/tabs/filtering_tab.vue +++ b/src/components/settings_modal/tabs/filtering_tab.vue @@ -37,6 +37,11 @@
    +
  • + + {{ $t('settings.mute_bot_posts') }} + +
  • {{ $t('settings.hide_post_stats') }} diff --git a/src/components/status/status.js b/src/components/status/status.js index d8f94926..ba85114a 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -166,6 +166,9 @@ const Status = { muteWordHits () { return muteWordHits(this.status, this.muteWords) }, + botStatus () { + return this.status.user.bot + }, mentionsLine () { if (!this.headTailLinks) return [] const writtenSet = new Set(this.headTailLinks.writtenMentions.map(_ => _.url)) @@ -191,7 +194,9 @@ const Status = { // Thread is muted status.thread_muted || // Wordfiltered - this.muteWordHits.length > 0 + this.muteWordHits.length > 0 || + // bot status + (this.muteBotStatuses && this.botStatus) return !this.unmuted && !this.shouldNotMute && reasonsToMute }, userIsMuted () { @@ -293,6 +298,9 @@ const Status = { hidePostStats () { return this.mergedConfig.hidePostStats }, + muteBotStatuses () { + return this.mergedConfig.muteBotStatuses + }, currentUser () { return this.$store.state.users.currentUser }, diff --git a/src/components/timeline/timeline_quick_settings.js b/src/components/timeline/timeline_quick_settings.js index 7b4931ce..92d5ac14 100644 --- a/src/components/timeline/timeline_quick_settings.js +++ b/src/components/timeline/timeline_quick_settings.js @@ -53,6 +53,13 @@ const TimelineQuickSettings = { const value = !this.hideMutedPosts this.$store.dispatch('setOption', { name: 'hideFilteredStatuses', value }) } + }, + muteBotStatuses: { + get () { return this.mergedConfig.muteBotStatuses }, + set () { + const value = !this.muteBotStatuses + this.$store.dispatch('setOption', { name: 'muteBotStatuses', value }) + } } } } diff --git a/src/components/timeline/timeline_quick_settings.vue b/src/components/timeline/timeline_quick_settings.vue index 98996ebd..4d67e06b 100644 --- a/src/components/timeline/timeline_quick_settings.vue +++ b/src/components/timeline/timeline_quick_settings.vue @@ -39,6 +39,15 @@ class="dropdown-divider" />
  • + @@ -161,7 +161,10 @@ :href="attachment.url" target="_blank" > - +

    {{ localDescription }}

    diff --git a/src/components/gallery/gallery.vue b/src/components/gallery/gallery.vue index f9cad8a9..f2e1b5ce 100644 --- a/src/components/gallery/gallery.vue +++ b/src/components/gallery/gallery.vue @@ -26,8 +26,8 @@ :size="size" :editable="editable" :remove="removeAttachment" - :shiftUp="!(attachmentIndex === 0 && rowIndex === 0) && shiftUpAttachment" - :shiftDn="!(attachmentIndex === row.items.length - 1 && rowIndex === rows.length - 1) && shiftDnAttachment" + :shift-up="!(attachmentIndex === 0 && rowIndex === 0) && shiftUpAttachment" + :shift-dn="!(attachmentIndex === row.items.length - 1 && rowIndex === rows.length - 1) && shiftDnAttachment" :edit="editAttachment" :description="descriptions && descriptions[attachment.id]" :hide-description="size === 'small' || tooManyAttachments && hidingLong" -- cgit v1.2.3-70-g09d2 From 0582f19e7c2c6f916b427d5ecfbbb571178ce841 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 6 Aug 2021 20:18:27 -0400 Subject: Add tree-style thread display --- src/components/conversation/conversation.js | 60 +++++++++++++++++++++- src/components/conversation/conversation.vue | 59 ++++++++++++++------- src/components/settings_modal/tabs/general_tab.js | 5 ++ src/components/settings_modal/tabs/general_tab.vue | 9 ++++ src/components/thread_tree/thread_tree.js | 52 +++++++++++++++++++ src/components/thread_tree/thread_tree.vue | 55 ++++++++++++++++++++ src/modules/config.js | 4 +- src/modules/instance.js | 1 + 8 files changed, 224 insertions(+), 21 deletions(-) create mode 100644 src/components/thread_tree/thread_tree.js create mode 100644 src/components/thread_tree/thread_tree.vue (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 069c0b40..e663ba15 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -1,5 +1,8 @@ import { reduce, filter, findIndex, clone, get } from 'lodash' import Status from '../status/status.vue' +import ThreadTree from '../thread_tree/thread_tree.vue' + +const debug = console.log const sortById = (a, b) => { const idA = a.type === 'retweet' ? a.retweeted_status.id : a.id @@ -53,6 +56,15 @@ const conversation = { } }, computed: { + displayStyle () { + return this.$store.state.config.conversationDisplay + }, + isTreeView () { + return this.displayStyle === 'tree' + }, + isLinearView () { + return this.displayStyle === 'linear' + }, hideStatus () { if (this.$refs.statusComponent && this.$refs.statusComponent[0]) { return this.virtualHidden && this.$refs.statusComponent[0].suspendable @@ -90,6 +102,49 @@ const conversation = { return sortAndFilterConversation(conversation, this.status) }, + threadTree () { + const reverseLookupTable = this.conversation.reduce((table, status, index) => { + table[status.id] = index + return table + }, {}) + + const threads = this.conversation.reduce((a, cur) => { + const id = cur.id + a.forest[id] = this.getReplies(id) + .map(s => s.id) + .sort((a, b) => reverseLookupTable[a] - reverseLookupTable[b]) + + a.topLevel = a.topLevel.filter(k => a.forest[id].contains(k)) + return a + }, { + forest: {}, + topLevel: this.conversation.map(s => s.id) + }) + + const walk = (forest, topLevel, depth = 0, processed = {}) => topLevel.map(id => { + if (processed[id]) { + return [] + } + + processed[id] = true + return [{ + status: this.conversation[reverseLookupTable[id]], + id, + depth + }, walk(forest, forest[child], depth + 1, processed)].reduce((a, b) => a.concat(b), []) + }).reduce((a, b) => a.concat(b), []) + + const linearized = walk(threads.forest, threads.topLevel) + + return linearized + }, + topLevel () { + const topLevel = this.conversation.reduce((tl, cur) => + tl.filter(k => this.getReplies(cur.id).map(v => v.id).indexOf(k.id) === -1), this.conversation) + debug("toplevel =", topLevel) + debug("toplevel =", topLevel) + return topLevel + }, replies () { let i = 1 // eslint-disable-next-line camelcase @@ -109,7 +164,7 @@ const conversation = { }, {}) }, isExpanded () { - return this.expanded || this.isPage + return !!(this.expanded || this.isPage) }, hiddenStyle () { const height = (this.status && this.status.virtualHeight) || '120px' @@ -117,7 +172,8 @@ const conversation = { } }, components: { - Status + Status, + ThreadTree }, watch: { statusId (newVal, oldVal) { diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 3fb26d92..cea5f88f 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -18,24 +18,47 @@ {{ $t('timeline.collapse') }}
    - +
    + +
    +
    + +
    ({ + key: mode, + value: mode, + label: this.$t(`settings.conversation_display_${mode}`) + })), mentionLinkDisplayOptions: ['short', 'full_for_remote', 'full'].map(mode => ({ key: mode, value: mode, diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index eba3b268..8951c021 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -152,6 +152,15 @@ {{ $t('settings.show_yous') }} +
  • + + {{ $t('settings.conversation_display') }} + +
  • { + table[status.id] = index + return table + }, {}) + }, + currentReplies () { + debug('status:', this.status) + debug('getReplies:', this.getReplies(this.status.id)) + return this.getReplies(this.status.id).map(({ id }) => this.statusById(id)) + }, + }, + methods: { + statusById (id) { + return this.conversation[this.reverseLookupTable[id]] + }, + collapseThread () { + }, + showThread () { + }, + showAllSubthreads () { + } + } +} + +export default ThreadTree diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue new file mode 100644 index 00000000..8256eee6 --- /dev/null +++ b/src/components/thread_tree/thread_tree.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/src/modules/config.js b/src/modules/config.js index 20979174..ec75dbfb 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -12,6 +12,7 @@ const browserLocale = (window.navigator.language || 'en').split('-')[0] export const multiChoiceProperties = [ 'postContentType', 'subjectLineBehavior', + 'conversationDisplay', // tree | linear 'mentionLinkDisplay' // short | full_for_remote | full ] @@ -81,7 +82,8 @@ export const defaultState = { hidePostStats: undefined, // instance default hideUserStats: undefined, // instance default virtualScrolling: undefined, // instance default - sensitiveByDefault: undefined // instance default + sensitiveByDefault: undefined, // instance default + conversationDisplay: undefined // instance default } // caching the instance default properties diff --git a/src/modules/instance.js b/src/modules/instance.js index 1abd784f..a160a557 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -53,6 +53,7 @@ const defaultState = { theme: 'pleroma-dark', virtualScrolling: true, sensitiveByDefault: false, + conversationDisplay: 'tree', // Nasty stuff customEmoji: [], -- cgit v1.2.3-70-g09d2 From 0f2fd8a3523e9e2cd1ca6fe287eb7304895f2cba Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 7 Aug 2021 00:33:06 -0400 Subject: Implement thread folding/expanding --- src/components/conversation/conversation.js | 105 +++++++++++++++++++++++++-- src/components/conversation/conversation.vue | 7 ++ src/components/status/status.js | 22 +++++- src/components/status/status.vue | 13 ++++ src/components/thread_tree/thread_tree.js | 12 ++- src/components/thread_tree/thread_tree.vue | 35 ++++++++- 6 files changed, 180 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index e663ba15..0abb7abd 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -38,7 +38,8 @@ const conversation = { data () { return { highlight: null, - expanded: false + expanded: false, + threadDisplayStatusObject: {} // id => 'showing' | 'hidden' } }, props: [ @@ -56,6 +57,9 @@ const conversation = { } }, computed: { + maxDepthToShowByDefault () { + return 4 + }, displayStyle () { return this.$store.state.config.conversationDisplay }, @@ -112,15 +116,14 @@ const conversation = { const id = cur.id a.forest[id] = this.getReplies(id) .map(s => s.id) - .sort((a, b) => reverseLookupTable[a] - reverseLookupTable[b]) - a.topLevel = a.topLevel.filter(k => a.forest[id].contains(k)) return a }, { forest: {}, - topLevel: this.conversation.map(s => s.id) }) + debug('threads = ', threads) + const walk = (forest, topLevel, depth = 0, processed = {}) => topLevel.map(id => { if (processed[id]) { return [] @@ -131,18 +134,63 @@ const conversation = { status: this.conversation[reverseLookupTable[id]], id, depth - }, walk(forest, forest[child], depth + 1, processed)].reduce((a, b) => a.concat(b), []) + }, walk(forest, forest[id], depth + 1, processed)].reduce((a, b) => a.concat(b), []) }).reduce((a, b) => a.concat(b), []) - const linearized = walk(threads.forest, threads.topLevel) + const linearized = walk(threads.forest, this.topLevel.map(k => k.id)) return linearized }, + replyIds () { + return this.conversation.map(k => k.id) + .reduce((res, id) => { + res[id] = (this.replies[id] || []).map(k => k.id) + return res + }, {}) + }, + totalReplyCount () { + debug('replyIds=', this.replyIds) + const sizes = {} + const subTreeSizeFor = (id) => { + if (sizes[id]) { + return sizes[id] + } + sizes[id] = 1 + this.replyIds[id].map(cid => subTreeSizeFor(cid)).reduce((a, b) => a + b, 0) + return sizes[id] + } + this.conversation.map(k => k.id).map(subTreeSizeFor) + debug('totalReplyCount=', sizes) + return Object.keys(sizes).reduce((res, id) => { + res[id] = sizes[id] - 1 // exclude itself + return res + }, {}) + }, + totalReplyDepth () { + const depths = {} + const subTreeDepthFor = (id) => { + if (depths[id]) { + return depths[id] + } + depths[id] = 1 + this.replyIds[id].map(cid => subTreeDepthFor(cid)).reduce((a, b) => a > b ? a : b, 0) + return depths[id] + } + this.conversation.map(k => k.id).map(subTreeDepthFor) + return Object.keys(depths).reduce((res, id) => { + res[id] = depths[id] - 1 // exclude itself + return res + }, {}) + }, + depths () { + debug('threadTree', this.threadTree) + return this.threadTree.reduce((a, k) => { + a[k.id] = k.depth + return a + }, {}) + }, topLevel () { const topLevel = this.conversation.reduce((tl, cur) => tl.filter(k => this.getReplies(cur.id).map(v => v.id).indexOf(k.id) === -1), this.conversation) debug("toplevel =", topLevel) - debug("toplevel =", topLevel) return topLevel }, replies () { @@ -169,6 +217,25 @@ const conversation = { hiddenStyle () { const height = (this.status && this.status.virtualHeight) || '120px' return this.virtualHidden ? { height } : {} + }, + threadDisplayStatus () { + return this.conversation.reduce((a, k) => { + const id = k.id + const depth = this.depths[id] + const status = (() => { + if (this.threadDisplayStatusObject[id]) { + return this.threadDisplayStatusObject[id] + } + if (depth <= this.maxDepthToShowByDefault) { + return 'showing' + } else { + return 'hidden' + } + })() + + a[id] = status + return a + }, {}) } }, components: { @@ -235,6 +302,30 @@ const conversation = { getConversationId (statusId) { const status = this.$store.state.statuses.allStatusesObject[statusId] return get(status, 'retweeted_status.statusnet_conversation_id', get(status, 'statusnet_conversation_id')) + }, + setThreadDisplay (id, nextStatus) { + this.threadDisplayStatusObject = { + ...this.threadDisplayStatusObject, + [id]: nextStatus + } + }, + toggleThreadDisplay (id) { + const depth = this.depths[id] + debug('depth = ', depth) + debug( + 'threadDisplayStatus = ', this.threadDisplayStatus, + 'threadDisplayStatusObject = ', this.threadDisplayStatusObject) + const curStatus = this.threadDisplayStatus[id] + const nextStatus = curStatus === 'showing' ? 'hidden' : 'showing' + debug('toggling', id, 'to', nextStatus) + this.setThreadDisplay(id, nextStatus) + }, + setThreadDisplayRecursively (id, nextStatus) { + this.setThreadDisplay(id, nextStatus) + this.getReplies(id).map(k => k.id).map(id => this.setThreadDisplayRecursively(id, nextStatus)) + }, + showThreadRecursively (id) { + this.setThreadDisplayRecursively(id, 'showing') } } } diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index cea5f88f..783cc894 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -23,6 +23,7 @@ v-for="status in topLevel" :key="status.id" ref="statusComponent" + :depth="0" :status="status" :in-profile="inProfile" @@ -37,6 +38,12 @@ :get-highlight="getHighlight" :set-highlight="setHighlight" :toggle-expanded="toggleExpanded" + + :toggle-thread-display="toggleThreadDisplay" + :thread-display-status="threadDisplayStatus" + :show-thread-recursively="showThreadRecursively" + :total-reply-count="totalReplyCount" + :total-reply-depth="totalReplyDepth" />
  • diff --git a/src/components/status/status.js b/src/components/status/status.js index d8f94926..9d423631 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -35,7 +35,9 @@ import { faStar, faEyeSlash, faEye, - faThumbtack + faThumbtack, + faAngleDoubleUp, + faAngleDoubleDown } from '@fortawesome/free-solid-svg-icons' library.add( @@ -52,7 +54,9 @@ library.add( faEllipsisH, faEyeSlash, faEye, - faThumbtack + faThumbtack, + faAngleDoubleUp, + faAngleDoubleDown ) const Status = { @@ -89,7 +93,10 @@ const Status = { 'inlineExpanded', 'showPinned', 'inProfile', - 'profileUserId' + 'profileUserId', + + 'controlledThreadDisplayStatus', + 'controlledToggleThreadDisplay' ], data () { return { @@ -304,6 +311,12 @@ const Status = { }, isSuspendable () { return !this.replying && this.mediaPlaying.length === 0 + }, + inThreadForest () { + return !!this.controlledThreadDisplayStatus + }, + threadShowing () { + return this.controlledThreadDisplayStatus === 'showing' } }, methods: { @@ -353,6 +366,9 @@ const Status = { }, setHeadTailLinks (headTailLinks) { this.headTailLinks = headTailLinks + }, + toggleThreadDisplay () { + this.controlledToggleThreadDisplay() } }, watch: { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 3bb29db6..2ebf5638 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -219,6 +219,19 @@ class="fa-scale-110" /> +
    this.statusById(id)) }, + threadShowing () { + return this.threadDisplayStatus[this.status.id] === 'showing' + } }, methods: { statusById (id) { diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue index 8256eee6..9f591585 100644 --- a/src/components/thread_tree/thread_tree.vue +++ b/src/components/thread_tree/thread_tree.vue @@ -13,18 +13,23 @@ :replies="getReplies(status.id)" :in-profile="inProfile" :profile-user-id="profileUserId" - class="conversation-status status-fadein panel-body" + class="conversation-status conversation-status-treeview status-fadein panel-body" + + :controlled-thread-display-status="threadDisplayStatus[status.id]" + :controlled-toggle-thread-display="() => toggleThreadDisplay(status.id)" + @goto="setHighlight" @toggleExpanded="toggleExpanded" />
    +
    + +
    -- cgit v1.2.3-70-g09d2 From 414ee55957851a30b9455e47e1e6d258743953a3 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 7 Aug 2021 01:05:26 -0400 Subject: Make show full thread message account for numbers --- src/components/thread_tree/thread_tree.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue index 9f591585..bbdda6fb 100644 --- a/src/components/thread_tree/thread_tree.vue +++ b/src/components/thread_tree/thread_tree.vue @@ -60,7 +60,7 @@ class="button-unstyled -link thread-tree-show-replies-button" @click="showThreadRecursively(status.id)" > - {{ $t('status.thread_show_full', { numStatus: totalReplyCount[status.id], depth: totalReplyDepth[status.id] }) }} + {{ $tc('status.thread_show_full', totalReplyCount[status.id], { numStatus: totalReplyCount[status.id], depth: totalReplyDepth[status.id] }) }}
    -- cgit v1.2.3-70-g09d2 From cd0f6a4f7820b27e3d776e598c842328ad64ab18 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 7 Aug 2021 01:06:16 -0400 Subject: Add English translations for message threading --- src/i18n/en.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/i18n/en.json b/src/i18n/en.json index 8eb7fcc6..6be2d9aa 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -465,6 +465,9 @@ "subject_line_email": "Like email: \"re: subject\"", "subject_line_mastodon": "Like mastodon: copy as is", "subject_line_noop": "Do not copy", + "conversation_display": "Conversation display style", + "conversation_display_tree": "Tree-style", + "conversation_display_linear": "Linear-style", "post_status_content_type": "Post status content type", "sensitive_by_default": "Mark posts as sensitive by default", "stop_gifs": "Pause animated images until you hover on them", @@ -747,7 +750,10 @@ "attachment_stop_flash": "Stop Flash player", "move_up": "Shift attachment left", "move_down": "Shift attachment right", - "open_gallery": "Open gallery" + "open_gallery": "Open gallery", + "thread_hide": "Hide this thread", + "thread_show": "Show this thread", + "thread_show_full": "Show everything under this thread ({numStatus} status in total, max depth {depth}) | Show everything under this thread ({numStatus} statuses in total, max depth {depth})" }, "user_card": { "approve": "Approve", -- cgit v1.2.3-70-g09d2 From ace1f5067c90be2fa0b8da22d39b0e2c88f590fb Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 7 Aug 2021 10:28:45 -0400 Subject: Make status display controlled --- src/components/conversation/conversation.js | 37 +++++++++++++++- src/components/conversation/conversation.vue | 3 ++ src/components/status/status.js | 9 +++- src/components/status/status.vue | 6 +++ src/components/status_content/status_content.js | 59 ++++++++++++++++++++++++- src/components/thread_tree/thread_tree.js | 11 ++++- src/components/thread_tree/thread_tree.vue | 10 +++++ 7 files changed, 130 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 0abb7abd..6fc86b2c 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -2,7 +2,8 @@ import { reduce, filter, findIndex, clone, get } from 'lodash' import Status from '../status/status.vue' import ThreadTree from '../thread_tree/thread_tree.vue' -const debug = console.log +// const debug = console.log +const debug = () => {} const sortById = (a, b) => { const idA = a.type === 'retweet' ? a.retweeted_status.id : a.id @@ -39,7 +40,8 @@ const conversation = { return { highlight: null, expanded: false, - threadDisplayStatusObject: {} // id => 'showing' | 'hidden' + threadDisplayStatusObject: {}, // id => 'showing' | 'hidden' + statusContentPropertiesObject: {} } }, props: [ @@ -236,6 +238,25 @@ const conversation = { a[id] = status return a }, {}) + }, + statusContentProperties () { + return this.conversation.reduce((a, k) => { + const id = k.id + const depth = this.depths[id] + const props = (() => { + if (this.statusContentPropertiesObject[id]) { + return this.statusContentPropertiesObject[id] + } + return { + showingTall: false, + expandingSubject: false, + showingLongSubject: false, + } + })() + + a[id] = props + return a + }, {}) } }, components: { @@ -326,6 +347,18 @@ const conversation = { }, showThreadRecursively (id) { this.setThreadDisplayRecursively(id, 'showing') + }, + setStatusContentProperty (id, name, value) { + this.statusContentPropertiesObject = { + ...this.statusContentPropertiesObject, + [id]: { + ...this.statusContentPropertiesObject[id], + [name]: value + } + } + }, + toggleStatusContentProperty (id, name) { + this.setStatusContentProperty(id, name, !this.statusContentProperties[id][name]) } } } diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 783cc894..08cb72d0 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -44,6 +44,9 @@ :show-thread-recursively="showThreadRecursively" :total-reply-count="totalReplyCount" :total-reply-depth="totalReplyDepth" + :status-content-properties="statusContentProperties" + :set-status-content-property="setStatusContentProperty" + :toggle-status-content-property="toggleStatusContentProperty" />
    diff --git a/src/components/status/status.js b/src/components/status/status.js index 9d423631..d5ee7d4e 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -96,7 +96,14 @@ const Status = { 'profileUserId', 'controlledThreadDisplayStatus', - 'controlledToggleThreadDisplay' + 'controlledToggleThreadDisplay', + + 'controlledShowingTall', + 'controlledToggleShowingTall', + 'controlledExpandingSubject', + 'controlledToggleExpandingSubject', + 'controlledShowingLongSubject', + 'controlledToggleShowingLongSubject' ], data () { return { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 2ebf5638..8fdebe44 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -319,6 +319,12 @@ :no-heading="noHeading" :highlight="highlight" :focused="isFocused" + :controlled-showing-tall="controlledShowingTall" + :controlled-expanding-subject="controlledExpandingSubject" + :controlled-showing-long-subject="controlledShowingLongSubject" + :controlled-toggle-showing-tall="controlledToggleShowingTall" + :controlled-toggle-expanding-subject="controlledToggleExpandingSubject" + :controlled-toggle-showing-long-subject="controlledToggleShowingLongSubject" @mediaplay="addMediaPlaying($event)" @mediapause="removeMediaPlaying($event)" @parseReady="setHeadTailLinks" diff --git a/src/components/status_content/status_content.js b/src/components/status_content/status_content.js index dec8914a..65ec85c4 100644 --- a/src/components/status_content/status_content.js +++ b/src/components/status_content/status_content.js @@ -23,6 +23,31 @@ library.add( faPollH ) +const camelCase = name => name.charAt(0).toUpperCase() + name.slice(1) + +const controlledOrUncontrolledGetters = list => list.reduce((res, name) => { + const camelized = camelCase(name) + const toggle = `controlledToggle${camelized}` + const controlledName = `controlled${camelized}` + const uncontrolledName = `uncontrolled${camelized}` + res[name] = function () { + return this[toggle] ? this[controlledName] : this[uncontrolledName] + } + return res +}, {}) + +const controlledOrUncontrolledToggle = (obj, name) => { + const camelized = camelCase(name) + const toggle = `controlledToggle${camelized}` + const controlledName = `controlled${camelized}` + const uncontrolledName = `uncontrolled${camelized}` + if (obj[toggle]) { + obj[toggle]() + } else { + obj[uncontrolledName] = !obj[uncontrolledName] + } +} + const StatusContent = { name: 'StatusContent', props: [ @@ -31,9 +56,22 @@ const StatusContent = { 'focused', 'noHeading', 'fullContent', - 'singleLine' + 'singleLine', + 'controlledShowingTall', + 'controlledExpandingSubject', + 'controlledToggleShowingTall', + 'controlledToggleExpandingSubject' ], + data () { + return { + uncontrolledShowingTall: this.fullContent || (this.inConversation && this.focused), + uncontrolledShowingLongSubject: false, + // not as computed because it sets the initial state which will be changed later + uncontrolledExpandingSubject: !this.$store.getters.mergedConfig.collapseMessageWithSubject + } + }, computed: { + ...controlledOrUncontrolledGetters(['showingTall', 'expandingSubject', 'showingLongSubject']), hideAttachments () { return (this.mergedConfig.hideAttachments && !this.inConversation) || (this.mergedConfig.hideAttachmentsInConv && this.inConversation) @@ -71,6 +109,25 @@ const StatusContent = { Gallery, LinkPreview, StatusBody + }, + methods: { + toggleShowingTall () { + controlledOrUncontrolledToggle(this, 'showingTall') + }, + toggleExpandingSubject () { + controlledOrUncontrolledToggle(this, 'expandingSubject') + }, + toggleShowMore () { + if (this.mightHideBecauseTall) { + this.toggleShowingTall() + } else if (this.mightHideBecauseSubject) { + this.toggleExpandingSubject() + } + }, + setMedia () { + const attachments = this.attachmentSize === 'hide' ? this.status.attachments : this.galleryAttachments + return () => this.$store.dispatch('setMedia', attachments) + } } } diff --git a/src/components/thread_tree/thread_tree.js b/src/components/thread_tree/thread_tree.js index 88b60109..46245bdf 100644 --- a/src/components/thread_tree/thread_tree.js +++ b/src/components/thread_tree/thread_tree.js @@ -28,7 +28,10 @@ const ThreadTree = { threadDisplayStatus: Object, showThreadRecursively: Function, totalReplyCount: Object, - totalReplyDepth: Object + totalReplyDepth: Object, + statusContentProperties: Object, + setStatusContentProperty: Function, + toggleStatusContentProperty: Function }, computed: { reverseLookupTable () { @@ -44,6 +47,9 @@ const ThreadTree = { }, threadShowing () { return this.threadDisplayStatus[this.status.id] === 'showing' + }, + currentProp () { + return this.statusContentProperties[this.status.id] } }, methods: { @@ -55,6 +61,9 @@ const ThreadTree = { showThread () { }, showAllSubthreads () { + }, + toggleCurrentProp (name) { + this.toggleStatusContentProperty(this.status.id, name) } } } diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue index bbdda6fb..d7077bfd 100644 --- a/src/components/thread_tree/thread_tree.vue +++ b/src/components/thread_tree/thread_tree.vue @@ -18,6 +18,13 @@ :controlled-thread-display-status="threadDisplayStatus[status.id]" :controlled-toggle-thread-display="() => toggleThreadDisplay(status.id)" + :controlled-showing-tall="currentProp.showingTall" + :controlled-expanding-subject="currentProp.expandingSubject" + :controlled-showing-long-subject="currentProp.showingLongSubject" + :controlled-toggle-showing-tall="() => toggleCurrentProp('ShowingTall')" + :controlled-toggle-expanding-subject="() => toggleCurrentProp('expandingSubject')" + :controlled-toggle-showing-long-subject="() => toggleCurrentProp('showingLongSubject')" + @goto="setHighlight" @toggleExpanded="toggleExpanded" /> @@ -50,6 +57,9 @@ :show-thread-recursively="showThreadRecursively" :total-reply-count="totalReplyCount" :total-reply-depth="totalReplyDepth" + :status-content-properties="statusContentProperties" + :set-status-content-property="setStatusContentProperty" + :toggle-status-content-property="toggleStatusContentProperty" />
    Date: Sat, 7 Aug 2021 11:59:10 -0400 Subject: Support diving into one status in a conversation --- src/components/conversation/conversation.js | 32 +++++++++++++++++++++++++++- src/components/conversation/conversation.vue | 30 +++++++++++++++++++++++++- src/components/status/status.js | 13 ++++++----- src/components/status/status.vue | 14 +++++++++++- src/components/thread_tree/thread_tree.js | 3 ++- src/components/thread_tree/thread_tree.vue | 15 +++++++++---- 6 files changed, 94 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 6fc86b2c..584f310c 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -2,6 +2,17 @@ import { reduce, filter, findIndex, clone, get } from 'lodash' import Status from '../status/status.vue' import ThreadTree from '../thread_tree/thread_tree.vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faAngleDoubleDown, + faAngleDoubleLeft +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faAngleDoubleDown, + faAngleDoubleLeft +) + // const debug = console.log const debug = () => {} @@ -41,7 +52,8 @@ const conversation = { highlight: null, expanded: false, threadDisplayStatusObject: {}, // id => 'showing' | 'hidden' - statusContentPropertiesObject: {} + statusContentPropertiesObject: {}, + diveRoot: null } }, props: [ @@ -195,6 +207,18 @@ const conversation = { debug("toplevel =", topLevel) return topLevel }, + showingTopLevel () { + if (this.diveRoot) { + return [this.conversation.filter(k => this.diveRoot === k.id)[0]] + } + return this.topLevel + }, + diveDepth () { + return this.diveRoot ? this.depths[this.diveRoot] : 0 + }, + diveMode () { + return !!this.diveRoot + }, replies () { let i = 1 // eslint-disable-next-line camelcase @@ -359,6 +383,12 @@ const conversation = { }, toggleStatusContentProperty (id, name) { this.setStatusContentProperty(id, name, !this.statusContentProperties[id][name]) + }, + diveIntoStatus (id) { + this.diveRoot = id + }, + undive () { + this.diveRoot = null } } } diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 08cb72d0..84e8d8b2 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -18,9 +18,22 @@ {{ $t('timeline.collapse') }}
    +
    + + + +
    @@ -65,6 +79,16 @@ :in-profile="inProfile" :profile-user-id="profileUserId" class="conversation-status status-fadein panel-body" + + :toggle-thread-display="toggleThreadDisplay" + :thread-display-status="threadDisplayStatus" + :show-thread-recursively="showThreadRecursively" + :total-reply-count="totalReplyCount" + :total-reply-depth="totalReplyDepth" + :status-content-properties="statusContentProperties" + :set-status-content-property="setStatusContentProperty" + :toggle-status-content-property="toggleStatusContentProperty" + @goto="setHighlight" @toggleExpanded="toggleExpanded" /> @@ -82,6 +106,10 @@ @import '../../_variables.scss'; .Conversation { + .conversation-undive-box { + padding: 1em; + } + .conversation-undive-box, .conversation-status { border-bottom-width: 1px; border-bottom-style: solid; diff --git a/src/components/status/status.js b/src/components/status/status.js index d5ee7d4e..f119f42e 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -36,8 +36,9 @@ import { faEyeSlash, faEye, faThumbtack, - faAngleDoubleUp, - faAngleDoubleDown + faChevronUp, + faChevronDown, + faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons' library.add( @@ -55,8 +56,9 @@ library.add( faEyeSlash, faEye, faThumbtack, - faAngleDoubleUp, - faAngleDoubleDown + faChevronUp, + faChevronDown, + faAngleDoubleRight ) const Status = { @@ -103,7 +105,8 @@ const Status = { 'controlledExpandingSubject', 'controlledToggleExpandingSubject', 'controlledShowingLongSubject', - 'controlledToggleShowingLongSubject' + 'controlledToggleShowingLongSubject', + 'dive' ], data () { return { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 8fdebe44..c2df6021 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -229,7 +229,19 @@ + + diff --git a/src/components/thread_tree/thread_tree.js b/src/components/thread_tree/thread_tree.js index 46245bdf..3e8eedb1 100644 --- a/src/components/thread_tree/thread_tree.js +++ b/src/components/thread_tree/thread_tree.js @@ -31,7 +31,8 @@ const ThreadTree = { totalReplyDepth: Object, statusContentProperties: Object, setStatusContentProperty: Function, - toggleStatusContentProperty: Function + toggleStatusContentProperty: Function, + dive: Function }, computed: { reverseLookupTable () { diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue index d7077bfd..adf7bcdf 100644 --- a/src/components/thread_tree/thread_tree.vue +++ b/src/components/thread_tree/thread_tree.vue @@ -24,6 +24,7 @@ :controlled-toggle-showing-tall="() => toggleCurrentProp('ShowingTall')" :controlled-toggle-expanding-subject="() => toggleCurrentProp('expandingSubject')" :controlled-toggle-showing-long-subject="() => toggleCurrentProp('showingLongSubject')" + :dive="dive ? () => dive(status.id) : undefined" @goto="setHighlight" @toggleExpanded="toggleExpanded" @@ -60,18 +61,24 @@ :status-content-properties="statusContentProperties" :set-status-content-property="setStatusContentProperty" :toggle-status-content-property="toggleStatusContentProperty" + :dive="dive" />
    - + + + {{ $tc('status.thread_show_full', totalReplyCount[status.id], { numStatus: totalReplyCount[status.id], depth: totalReplyDepth[status.id] }) }} + +
    -- cgit v1.2.3-70-g09d2 From 31c4300456192582786a7f5da420f7ce834a3e2b Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 7 Aug 2021 11:59:41 -0400 Subject: Add English translations for diving --- src/i18n/en.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/i18n/en.json b/src/i18n/en.json index 6be2d9aa..7f92e95a 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -753,7 +753,10 @@ "open_gallery": "Open gallery", "thread_hide": "Hide this thread", "thread_show": "Show this thread", - "thread_show_full": "Show everything under this thread ({numStatus} status in total, max depth {depth}) | Show everything under this thread ({numStatus} statuses in total, max depth {depth})" + "thread_show_full": "Show everything under this thread ({numStatus} status in total, max depth {depth}) | Show everything under this thread ({numStatus} statuses in total, max depth {depth})", + "thread_show_full_with_icon": "{icon} {text}", + "show_all_conversation": "{0} Show full conversation", + "show_only_conversation_under_this": "Only show replies to this status" }, "user_card": { "approve": "Approve", -- cgit v1.2.3-70-g09d2 From d15d24c11c57ecfc49705af648b1e8f73caec51e Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 7 Aug 2021 14:11:34 -0400 Subject: Add dive functionality --- src/components/conversation/conversation.js | 69 ++++++++++++++++++++++++---- src/components/conversation/conversation.vue | 15 +++++- src/components/status/status.vue | 2 +- src/components/thread_tree/thread_tree.js | 3 +- src/components/thread_tree/thread_tree.vue | 5 +- 5 files changed, 80 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 584f310c..b2af1d6c 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -5,12 +5,14 @@ import ThreadTree from '../thread_tree/thread_tree.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { faAngleDoubleDown, - faAngleDoubleLeft + faAngleDoubleLeft, + faChevronLeft } from '@fortawesome/free-solid-svg-icons' library.add( faAngleDoubleDown, - faAngleDoubleLeft + faAngleDoubleLeft, + faChevronLeft ) // const debug = console.log @@ -53,7 +55,7 @@ const conversation = { expanded: false, threadDisplayStatusObject: {}, // id => 'showing' | 'hidden' statusContentPropertiesObject: {}, - diveRoot: null + diveHistory: [] } }, props: [ @@ -120,6 +122,14 @@ const conversation = { return sortAndFilterConversation(conversation, this.status) }, + conversationDive () { + }, + statusMap () { + return this.conversation.reduce((res, s) => { + res[s.id] = s + return res + }, {}) + }, threadTree () { const reverseLookupTable = this.conversation.reduce((table, status, index) => { table[status.id] = index @@ -208,16 +218,19 @@ const conversation = { return topLevel }, showingTopLevel () { - if (this.diveRoot) { - return [this.conversation.filter(k => this.diveRoot === k.id)[0]] + if (this.canDive && this.diveRoot) { + return [this.statusMap[this.diveRoot]] } return this.topLevel }, + diveRoot () { + return this.diveHistory[this.diveHistory.length - 1] + }, diveDepth () { - return this.diveRoot ? this.depths[this.diveRoot] : 0 + return this.canDive && this.diveRoot ? this.depths[this.diveRoot] : 0 }, diveMode () { - return !!this.diveRoot + return this.canDive && !!this.diveRoot }, replies () { let i = 1 @@ -252,7 +265,7 @@ const conversation = { if (this.threadDisplayStatusObject[id]) { return this.threadDisplayStatusObject[id] } - if (depth <= this.maxDepthToShowByDefault) { + if ((depth - this.diveDepth) <= this.maxDepthToShowByDefault) { return 'showing' } else { return 'hidden' @@ -281,6 +294,9 @@ const conversation = { a[id] = props return a }, {}) + }, + canDive () { + return this.isTreeView && this.isExpanded } }, components: { @@ -310,6 +326,25 @@ const conversation = { } }, methods: { + conversationFetched () { + if (!this.isExpanded) { + return + } + + if (!this._diven) { + if (!this.threadDisplayStatus[this.statusId]) { + return + } + this._diven = true + const parentOrSelf = this.parentOrSelf(this.originalStatusId) + console.log( + 'this.threadDisplayStatus ', this.threadDisplayStatus, + 'this.statusId', this.statusId) + if (this.threadDisplayStatus[this.statusId] === 'hidden') { + this.diveIntoStatus(parentOrSelf) + } + } + }, fetchConversation () { if (this.status) { this.$store.state.api.backendInteractor.fetchConversation({ id: this.statusId }) @@ -318,6 +353,7 @@ const conversation = { this.$store.dispatch('addNewStatuses', { statuses: descendants }) this.setHighlight(this.originalStatusId) }) + .then(this.conversationFetched) } else { this.$store.state.api.backendInteractor.fetchStatus({ id: this.statusId }) .then((status) => { @@ -385,10 +421,23 @@ const conversation = { this.setStatusContentProperty(id, name, !this.statusContentProperties[id][name]) }, diveIntoStatus (id) { - this.diveRoot = id + this.diveHistory = [...this.diveHistory, id] + }, + diveBack () { + this.diveHistory = [...this.diveHistory.slice(0, this.diveHistory.length - 1)] }, undive () { - this.diveRoot = null + this.diveHistory = [] + }, + statusById (id) { + return this.statusMap[id] + }, + parentOf (id) { + const { in_reply_to_status_id: parentId } = this.statusById(id) + return parentId + }, + parentOrSelf (id) { + return this.parentOf(id) || id } } } diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 84e8d8b2..99bc7bcc 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -31,6 +31,19 @@ +
    + + + +
    diff --git a/src/components/status/status.vue b/src/components/status/status.vue index c2df6021..47d35de8 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -220,7 +220,7 @@ />
    -
    - +
    - - -
    -
    - + + +
    +
    - - -
    -
    - + + +
    +
    + -
    -
    - +
    +
    + + @goto="setHighlight" + @toggleExpanded="toggleExpanded" + /> +
    .conversation-status { + border-top-left-radius: $fallback--panelRadius; + border-top-left-radius: var(--panelRadius, $fallback--panelRadius); + } + + /* first element in conversation body */ + &.-expanded .conversation-body { + .conversation-undive-box:nth-child(1), + & > .conversation-status:nth-child(1), + & > .thread-body:nth-child(1) > .thread-tree:nth-child(1) > .conversation-status:nth-child(1), { + border-top: none; + } + } + + /* first unexpanded statuses in timeline */ + &:first-child:not(.-expanded) { + .conversation-body { + .conversation-status { + border-top: none; + } + } + } + + /* expanded conversation in timeline */ + &.status-fadein.-expanded .thread-body { + border-left-width: 4px; + border-left-style: solid; + border-left-color: $fallback--cRed; + border-left-color: var(--cRed, $fallback--cRed); + border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius; + border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius); + border-bottom: 1px solid var(--border, $fallback--border); + } &.-expanded { .conversation-status:last-child { border-bottom: none; - border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius; - border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius); } } } diff --git a/src/components/status/status.scss b/src/components/status/status.scss index 2028ade9..80bc392d 100644 --- a/src/components/status/status.scss +++ b/src/components/status/status.scss @@ -1,7 +1,5 @@ @import '../../_variables.scss'; -$status-margin: 0.75em; - .Status { min-width: 0; white-space: normal; @@ -28,13 +26,6 @@ $status-margin: 0.75em; --icon: var(--selectedPostIcon, $fallback--icon); } - &.-conversation { - border-left-width: 4px; - border-left-style: solid; - border-left-color: $fallback--cRed; - border-left-color: var(--cRed, $fallback--cRed); - } - .gravestone { padding: $status-margin; color: $fallback--faint; diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue index fa1e5f86..aafad66e 100644 --- a/src/components/thread_tree/thread_tree.vue +++ b/src/components/thread_tree/thread_tree.vue @@ -109,14 +109,16 @@ -- cgit v1.2.3-70-g09d2 From 8780246ce5566e60520354f5a3de92eacd059f61 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 8 Aug 2021 12:55:04 -0400 Subject: Optimize thread border radius --- src/components/conversation/conversation.vue | 12 +++++++++--- src/components/thread_tree/thread_tree.vue | 3 +-- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index cd108f69..11b5b3d8 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -130,10 +130,13 @@ .Conversation { .conversation-undive-box { padding: $status-margin; + border-bottom-width: 1px; + border-bottom-style: solid; + border-bottom-color: var(--border, $fallback--border); + border-radius: 0; } /* HACK: we want the border width to scale with the status *below it* */ - .conversation-undive-box, .conversation-status { border-top-width: 1px; border-top-style: solid; @@ -146,11 +149,14 @@ border-top-left-radius: var(--panelRadius, $fallback--panelRadius); } - /* first element in conversation body */ + /* first element in a reply tree, the border is supplied by reply tree instead + for radius to display properly + */ &.-expanded .conversation-body { .conversation-undive-box:nth-child(1), & > .conversation-status:nth-child(1), - & > .thread-body:nth-child(1) > .thread-tree:nth-child(1) > .conversation-status:nth-child(1), { + & > .thread-body:nth-child(1) > .thread-tree:nth-child(1) > .conversation-status:nth-child(1), + .thread-tree:nth-child(1) > .conversation-status:nth-child(1) { border-top: none; } } diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue index aafad66e..79ba0cc5 100644 --- a/src/components/thread_tree/thread_tree.vue +++ b/src/components/thread_tree/thread_tree.vue @@ -111,10 +111,9 @@ .thread-tree-replies { margin-left: $status-margin; border-left: 1px solid var(--border, $fallback--border); + border-top: 1px solid var(--border, $fallback--border); border-top-left-radius: $fallback--panelRadius; border-top-left-radius: var(--panelRadius, $fallback--panelRadius); - border-bottom-left-radius: $fallback--panelRadius; - border-bottom-left-radius: var(--panelRadius, $fallback--panelRadius); } .thread-tree-replies-hidden { -- cgit v1.2.3-70-g09d2 From 0e4a7c3d05333d1e3c86b26b4d6b7cd296ff2582 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 8 Aug 2021 13:29:49 -0400 Subject: Make dive/undive button clickable along the whole row --- src/components/conversation/conversation.vue | 4 ++++ src/components/thread_tree/thread_tree.vue | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'src') diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 11b5b3d8..86a227ce 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -134,6 +134,10 @@ border-bottom-style: solid; border-bottom-color: var(--border, $fallback--border); border-radius: 0; + /* Make the button stretch along the whole row */ + display: flex; + align-items: stretch; + flex-direction: column; } /* HACK: we want the border width to scale with the status *below it* */ diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue index 79ba0cc5..46d65101 100644 --- a/src/components/thread_tree/thread_tree.vue +++ b/src/components/thread_tree/thread_tree.vue @@ -119,5 +119,9 @@ .thread-tree-replies-hidden { padding: $status-margin; border-top: 1px solid var(--border, $fallback--border); + /* Make the button stretch along the whole row */ + display: flex; + align-items: stretch; + flex-direction: column; } -- cgit v1.2.3-70-g09d2 From 4adffb483579108c0bfe7593157e9bed3571903f Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 10 Aug 2021 21:28:13 -0400 Subject: Remove horizontal border and thicken vertical border in a thread tree --- src/components/conversation/conversation.vue | 32 +++++----------------------- src/components/thread_tree/thread_tree.vue | 7 ++---- 2 files changed, 7 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 86a227ce..c866b983 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -142,36 +142,14 @@ /* HACK: we want the border width to scale with the status *below it* */ .conversation-status { - border-top-width: 1px; - border-top-style: solid; - border-top-color: var(--border, $fallback--border); + border-bottom-width: 1px; + border-bottom-style: solid; + border-bottom-color: var(--border, $fallback--border); border-radius: 0; } - &.-expanded .conversation-body .thread-tree:nth-child(1) > .conversation-status { - border-top-left-radius: $fallback--panelRadius; - border-top-left-radius: var(--panelRadius, $fallback--panelRadius); - } - - /* first element in a reply tree, the border is supplied by reply tree instead - for radius to display properly - */ - &.-expanded .conversation-body { - .conversation-undive-box:nth-child(1), - & > .conversation-status:nth-child(1), - & > .thread-body:nth-child(1) > .thread-tree:nth-child(1) > .conversation-status:nth-child(1), - .thread-tree:nth-child(1) > .conversation-status:nth-child(1) { - border-top: none; - } - } - - /* first unexpanded statuses in timeline */ - &:first-child:not(.-expanded) { - .conversation-body { - .conversation-status { - border-top: none; - } - } + &.-expanded .thread-tree .conversation-status { + border-bottom: none; } /* expanded conversation in timeline */ diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue index 46d65101..dce03f27 100644 --- a/src/components/thread_tree/thread_tree.vue +++ b/src/components/thread_tree/thread_tree.vue @@ -110,15 +110,12 @@ @import '../../_variables.scss'; .thread-tree-replies { margin-left: $status-margin; - border-left: 1px solid var(--border, $fallback--border); - border-top: 1px solid var(--border, $fallback--border); - border-top-left-radius: $fallback--panelRadius; - border-top-left-radius: var(--panelRadius, $fallback--panelRadius); + border-left: 2px solid var(--border, $fallback--border); } .thread-tree-replies-hidden { padding: $status-margin; - border-top: 1px solid var(--border, $fallback--border); + //border-top: 1px solid var(--border, $fallback--border); /* Make the button stretch along the whole row */ display: flex; align-items: stretch; -- cgit v1.2.3-70-g09d2 From e560fbc9352f9f8754451f38c5e3ecef6da96686 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 10 Aug 2021 23:58:27 -0400 Subject: Implement Misskey-style tree view Now the tree will be always rooted at the highlighted status, and all its ancestors shown linearly on the top. Enhancement: If an ancestor has more than one reply (i.e. it has a child that is not on current status's ancestor chain), we are given a link to root the thread at that status. --- src/components/conversation/conversation.js | 61 ++++++-------- src/components/conversation/conversation.vue | 118 ++++++++++++++++++++++----- 2 files changed, 124 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index bd8315b8..817b9bda 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -55,7 +55,7 @@ const conversation = { expanded: false, threadDisplayStatusObject: {}, // id => 'showing' | 'hidden' statusContentPropertiesObject: {}, - diveHistory: [] + inlineDivePosition: null } }, props: [ @@ -231,7 +231,10 @@ const conversation = { return this.topLevel }, diveRoot () { - return this.diveHistory[this.diveHistory.length - 1] + (() => {})(this.conversation) + const statusId = this.inlineDivePosition || this.statusId + const isTopLevel = !this.parentOf(statusId) + return isTopLevel ? null : statusId }, diveDepth () { return this.canDive && this.diveRoot ? this.depths[this.diveRoot] : 0 @@ -332,7 +335,6 @@ const conversation = { this.fetchConversation() } else { // if we collapse it, we should reset the dive - this._diven = false this.undive() } }, @@ -348,19 +350,6 @@ const conversation = { if (!this.isExpanded) { return } - - if (!this._diven) { - if (!this.threadDisplayStatus[this.statusId]) { - return - } - this._diven = true - const parentOrSelf = this.parentOrSelf(this.originalStatusId) - // If current status is not visible - if (this.threadDisplayStatus[parentOrSelf] === 'hidden') { - this.diveIntoStatus(parentOrSelf, /* preventScroll */ true) - this.tryScrollTo(this.statusId) - } - } }, fetchConversation () { if (this.status) { @@ -449,26 +438,15 @@ const conversation = { return this.topLevel[0] ? this.topLevel[0].id : undefined }, diveIntoStatus (id, preventScroll) { - this.diveHistory = [...this.diveHistory, id] - if (!preventScroll) { - this.goToCurrent() - } + this.tryScrollTo(id) }, - diveBack () { - const oldHighlight = this.highlight - this.diveHistory = [...this.diveHistory.slice(0, this.diveHistory.length - 1)] - if (oldHighlight) { - this.tryScrollTo(this.leastVisibleAncestor(oldHighlight)) - } + diveToTopLevel () { + this.tryScrollTo(this.topLevel[0].id) }, + // only used when we are not on a page undive () { - const oldHighlight = this.highlight - this.diveHistory = [] - if (oldHighlight) { - this.tryScrollTo(this.leastVisibleAncestor(oldHighlight)) - } else { - this.goToCurrent() - } + this.inlineDivePosition = null + this.setHighlight(this.statusId) }, tryScrollTo (id) { if (!id) { @@ -477,8 +455,9 @@ const conversation = { if (this.isPage) { // set statusId this.$router.push({ name: 'conversation', params: { id } }) + } else { + this.inlineDivePosition = id } - this.setHighlight(id) }, goToCurrent () { @@ -493,10 +472,24 @@ const conversation = { return undefined } const { in_reply_to_status_id: parentId } = status + if (!this.statusMap[parentId]) { + return undefined + } return parentId }, parentOrSelf (id) { return this.parentOf(id) || id + }, + // Ancestors of some status, from top to bottom + ancestorsOf (id) { + const ancestors = [] + let cur = this.parentOf(id) + while (cur) { + ancestors.unshift(this.statusMap[cur]) + cur = this.parentOf(cur) + } + // console.log('ancestors = ', ancestors, 'conversation = ', this.conversation.map(k => k.id), 'statusContentProperties=', this.statusContentProperties) + return ancestors } } } diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index c866b983..20ce54a6 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -21,34 +21,88 @@
    -
    - - - -
    +
    +
    + +
    +
    + + + + {{ $tc('status.ancestor_follow', getReplies(status.id).length - 1, { numReplies: getReplies(status.id).length - 1 }) }} + + +
    +
    +
    +
    -- cgit v1.2.3-70-g09d2 From d78c8e8ea4c1b5a9801552b519573037564a8f66 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 10 Aug 2021 23:59:51 -0400 Subject: Add English translation for Misskey-style tree view --- src/i18n/en.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/i18n/en.json b/src/i18n/en.json index b8ddc3d2..02dd7200 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -759,8 +759,9 @@ "thread_show_full_with_icon": "{icon} {text}", "thread_follow": "See the remaining part of this thread ({numStatus} status in total) | See the remaining part of this thread ({numStatus} statuses in total)", "thread_follow_with_icon": "{icon} {text}", + "ancestor_follow": "See {numReplies} other reply under this status | See {numReplies} other replies under this status", + "ancestor_follow_with_icon": "{icon} {text}", "show_all_conversation": "{0} Show full conversation", - "return_to_last_showing": "{0} Return to last position", "show_only_conversation_under_this": "Only show replies to this status" }, "user_card": { -- cgit v1.2.3-70-g09d2 From f1db5e8f4bfc8d43eb74d0e3f784c0aa8b06bf3f Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 11 Aug 2021 00:12:16 -0400 Subject: Highlight ancestor of the current status when diving back to top --- src/components/conversation/conversation.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 817b9bda..e9bbca18 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -441,7 +441,7 @@ const conversation = { this.tryScrollTo(id) }, diveToTopLevel () { - this.tryScrollTo(this.topLevel[0].id) + this.tryScrollTo(this.topLevelAncestorOrSelfId(this.diveRoot) || this.topLevel[0].id) }, // only used when we are not on a page undive () { @@ -490,6 +490,15 @@ const conversation = { } // console.log('ancestors = ', ancestors, 'conversation = ', this.conversation.map(k => k.id), 'statusContentProperties=', this.statusContentProperties) return ancestors + }, + topLevelAncestorOrSelfId (id) { + let cur = id + let parent = this.parentOf(id) + while (parent) { + cur = this.parentOf(cur) + parent = this.parentOf(parent) + } + return cur } } } -- cgit v1.2.3-70-g09d2 From 10cd03c7186fa57e8cbdd22c4523c98e4ea53c47 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 11 Aug 2021 00:17:17 -0400 Subject: Clean up --- src/components/conversation/conversation.js | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index e9bbca18..3cc5f886 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -346,11 +346,6 @@ const conversation = { } }, methods: { - conversationFetched () { - if (!this.isExpanded) { - return - } - }, fetchConversation () { if (this.status) { this.$store.state.api.backendInteractor.fetchConversation({ id: this.statusId }) @@ -359,7 +354,6 @@ const conversation = { this.$store.dispatch('addNewStatuses', { statuses: descendants }) this.setHighlight(this.originalStatusId) }) - .then(this.conversationFetched) } else { this.$store.state.api.backendInteractor.fetchStatus({ id: this.statusId }) .then((status) => { @@ -488,7 +482,6 @@ const conversation = { ancestors.unshift(this.statusMap[cur]) cur = this.parentOf(cur) } - // console.log('ancestors = ', ancestors, 'conversation = ', this.conversation.map(k => k.id), 'statusContentProperties=', this.statusContentProperties) return ancestors }, topLevelAncestorOrSelfId (id) { -- cgit v1.2.3-70-g09d2 From 26670e90035104fbd24e0884c00b17c6266ba354 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 11 Aug 2021 00:22:47 -0400 Subject: Reset thread open state when collapsed --- src/components/conversation/conversation.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 3cc5f886..4c429161 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -334,8 +334,7 @@ const conversation = { if (value) { this.fetchConversation() } else { - // if we collapse it, we should reset the dive - this.undive() + this.resetDisplayState() } }, virtualHidden (value) { @@ -492,6 +491,10 @@ const conversation = { parent = this.parentOf(parent) } return cur + }, + resetDisplayState () { + this.undive() + this.threadDisplayStatusObject = {} } } } -- cgit v1.2.3-70-g09d2 From 17863f54fef4203365aa2b7ce58da3bb9bb3cc8c Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 11 Aug 2021 00:30:27 -0400 Subject: Optimise thread ancestor display style --- src/components/conversation/conversation.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 20ce54a6..f0e118e5 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -194,7 +194,12 @@ flex-direction: column; } - .thread-ancestor { + .thread-ancestors { + margin-left: $status-margin; + border-left: 2px solid var(--border, $fallback--border); + } + + .thread-ancestor .StatusContent { --link: var(--faintLink); --text: var(--faint); color: var(--text); -- cgit v1.2.3-70-g09d2 From ba8598858b4a90d25b76a515dc6a9125d2809f9d Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 11 Aug 2021 00:49:38 -0400 Subject: Optimise thread ancestor borders --- src/components/conversation/conversation.vue | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index f0e118e5..9aea7b20 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -220,7 +220,6 @@ //border-left: 2px solid var(--border, $fallback--border); } - /* HACK: we want the border width to scale with the status *below it* */ .conversation-status { border-bottom-width: 1px; border-bottom-style: solid; @@ -229,10 +228,18 @@ } .thread-ancestor-has-other-replies .conversation-status, + .thread-ancestor:last-child .conversation-status, + .thread-ancestor:last-child .thread-ancestor-dive-box, &.-expanded .thread-tree .conversation-status { border-bottom: none; } + .thread-ancestors + .thread-tree > .conversation-status { + border-top-width: 1px; + border-top-style: solid; + border-top-color: var(--border, $fallback--border); + } + /* expanded conversation in timeline */ &.status-fadein.-expanded .thread-body { border-left-width: 4px; -- cgit v1.2.3-70-g09d2 From 22bdcda9c0a9869f8a09507bb60215b8a5af709a Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 13 Aug 2021 18:53:31 -0400 Subject: Make other replies button stretch along the row --- src/components/conversation/conversation.vue | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 9aea7b20..6c8c6ef0 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -211,9 +211,11 @@ border-bottom-color: var(--border, $fallback--border); border-radius: 0; /* Make the button stretch along the whole row */ - display: flex; - align-items: stretch; - flex-direction: column; + &, &-inner { + display: flex; + align-items: stretch; + flex-direction: column; + } } .thread-ancestor-dive-box-inner { padding: $status-margin; -- cgit v1.2.3-70-g09d2 From 244174a32b94c1373847f0ea20bb6127de5ef222 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 5 Sep 2021 11:16:48 -0400 Subject: Improve "show full conversation" interaction Now we only show that button when there are other statuses out of sight (other toplevel statuses exist outside of the current thread tree). --- src/components/conversation/conversation.js | 8 ++++++++ src/components/conversation/conversation.vue | 12 +++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 4c429161..423930af 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -224,6 +224,9 @@ const conversation = { debug('toplevel =', topLevel) return topLevel }, + otherTopLevelCount () { + return this.topLevel.length - 1 + }, showingTopLevel () { if (this.canDive && this.diveRoot) { return [this.statusMap[this.diveRoot]] @@ -242,6 +245,11 @@ const conversation = { diveMode () { return this.canDive && !!this.diveRoot }, + shouldShowAllConversationButton () { + // The "show all conversation" button tells the user that there exist + // other toplevel statuses, so do not show it if there is only a single root + return this.diveMode && this.topLevel.length > 1 + }, replies () { let i = 1 // eslint-disable-next-line camelcase diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 6c8c6ef0..f0eb88c1 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -20,16 +20,22 @@
    - + + + {{ $tc('status.show_all_conversation', otherTopLevelCount, { numStatus: otherTopLevelCount }) }} +
    Date: Sun, 5 Sep 2021 11:19:43 -0400 Subject: Add English translation for show all conversation button improvement --- src/i18n/en.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/i18n/en.json b/src/i18n/en.json index 02dd7200..ef96e0c5 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -761,7 +761,8 @@ "thread_follow_with_icon": "{icon} {text}", "ancestor_follow": "See {numReplies} other reply under this status | See {numReplies} other replies under this status", "ancestor_follow_with_icon": "{icon} {text}", - "show_all_conversation": "{0} Show full conversation", + "show_all_conversation_with_icon": "{icon} {text}", + "show_all_conversation": "Show full conversation ({numStatus} other status) | Show full conversation ({numStatus} other statuses)", "show_only_conversation_under_this": "Only show replies to this status" }, "user_card": { -- cgit v1.2.3-70-g09d2 From 863255d52fdcbbabe45c86c7e36ebafc0f7e1c53 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 5 Sep 2021 16:35:47 -0400 Subject: Make position of other replies button a pref --- src/components/conversation/conversation.js | 9 +++++ src/components/conversation/conversation.vue | 7 ++-- src/components/settings_modal/tabs/general_tab.js | 5 +++ src/components/settings_modal/tabs/general_tab.vue | 40 +++++++++++++++------- src/components/status/status.js | 1 + src/components/status/status.vue | 15 +++++++- src/modules/config.js | 2 ++ src/modules/instance.js | 1 + 8 files changed, 63 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 423930af..d4972fbc 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -92,6 +92,15 @@ const conversation = { isLinearView () { return this.displayStyle === 'linear' }, + otherRepliesButtonPosition () { + return this.$store.getters.mergedConfig.conversationOtherRepliesButton + }, + showOtherRepliesButtonBelowStatus () { + return this.otherRepliesButtonPosition === 'below' + }, + showOtherRepliesButtonInsideStatus () { + return this.otherRepliesButtonPosition === 'inside' + }, hideStatus () { if (this.$refs.statusComponent && this.$refs.statusComponent[0]) { return this.virtualHidden && this.$refs.statusComponent[0].suspendable diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index f0eb88c1..b3d97075 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -66,13 +66,14 @@ :profile-user-id="profileUserId" class="conversation-status status-fadein panel-body" - :simple="treeViewIsSimple" + :simple-tree="treeViewIsSimple" :toggle-thread-display="toggleThreadDisplay" :thread-display-status="threadDisplayStatus" :show-thread-recursively="showThreadRecursively" :total-reply-count="totalReplyCount" :total-reply-depth="totalReplyDepth" - :dive="(!treeViewIsSimple) ? () => diveIntoStatus(status.id) : null" + :show-other-replies-as-button="showOtherRepliesButtonInsideStatus" + :dive="() => diveIntoStatus(status.id)" :controlled-showing-tall="statusContentProperties[status.id].showingTall" :controlled-expanding-subject="statusContentProperties[status.id].expandingSubject" @@ -85,7 +86,7 @@ @toggleExpanded="toggleExpanded" />
    ({ + key: mode, + value: mode, + label: this.$t(`settings.conversation_other_replies_button_${mode}`) + })), mentionLinkDisplayOptions: ['short', 'full_for_remote', 'full'].map(mode => ({ key: mode, value: mode, diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index f97d92c3..d5ae7810 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -161,19 +161,33 @@ {{ $t('settings.conversation_display') }} -
  • - - -
  • +
      +
    • + + +
    • +
    • + + {{ $t('settings.conversation_other_replies_button') }} + +
    • +
  • - {{ $t('status.replies_list') }} + + + {{ $t('status.replies_list') }} + Date: Sun, 5 Sep 2021 16:36:27 -0400 Subject: Add English translation for position of other replies button pref --- src/i18n/en.json | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/i18n/en.json b/src/i18n/en.json index ef96e0c5..7b37357a 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -469,6 +469,9 @@ "conversation_display_tree": "Tree-style", "conversation_display_simple_tree": "Simplified tree-style", "conversation_display_linear": "Linear-style", + "conversation_other_replies_button": "Show the \"other replies\" button", + "conversation_other_replies_button_below": "Below statuses", + "conversation_other_replies_button_inside": "Inside statuses", "max_depth_in_thread": "Maximum number of levels in thread to display by default", "post_status_content_type": "Post status content type", "sensitive_by_default": "Mark posts as sensitive by default", -- cgit v1.2.3-70-g09d2 From cebb4224ac0143f6969c7d3e907a7d25eb38b4c7 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 8 Sep 2021 23:22:11 -0400 Subject: Do not display replies inside status as link if there are no other replies --- src/components/status/status.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/status/status.vue b/src/components/status/status.vue index bc0aeaf0..31908815 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -347,7 +347,7 @@ class="replies" > Date: Wed, 8 Sep 2021 23:29:17 -0400 Subject: Add English translations for other replies count --- src/i18n/en.json | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/i18n/en.json b/src/i18n/en.json index 7b37357a..b185dcab 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -729,6 +729,7 @@ "reply_to": "Reply to", "mentions": "Mentions", "replies_list": "Replies:", + "replies_list_with_others": "Replies (+{numReplies} other): | Replies (+{numReplies} others):", "mute_conversation": "Mute conversation", "unmute_conversation": "Unmute conversation", "status_unavailable": "Status unavailable", -- cgit v1.2.3-70-g09d2 From 0db5a5a581aa6560637dd85886dfd9d7934f40fa Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 9 Sep 2021 00:03:10 -0400 Subject: Fix controlled status display toggles --- src/components/status_body/status_body.js | 16 +++++++++------- src/components/status_content/status_content.js | 8 ++------ src/components/status_content/status_content.vue | 6 ++++++ 3 files changed, 17 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/components/status_body/status_body.js b/src/components/status_body/status_body.js index 91c33135..b8f6f9a0 100644 --- a/src/components/status_body/status_body.js +++ b/src/components/status_body/status_body.js @@ -26,14 +26,16 @@ const StatusContent = { 'focused', 'noHeading', 'fullContent', - 'singleLine' + 'singleLine', + 'showingTall', + 'expandingSubject', + 'showingLongSubject', + 'toggleShowingTall', + 'toggleExpandingSubject', + 'toggleShowingLongSubject' ], data () { return { - showingTall: this.fullContent || (this.inConversation && this.focused), - showingLongSubject: false, - // not as computed because it sets the initial state which will be changed later - expandingSubject: !this.$store.getters.mergedConfig.collapseMessageWithSubject, postLength: this.status.text.length, parseReadyDone: false } @@ -115,9 +117,9 @@ const StatusContent = { }, toggleShowMore () { if (this.mightHideBecauseTall) { - this.showingTall = !this.showingTall + this.toggleShowingTall() } else if (this.mightHideBecauseSubject) { - this.expandingSubject = !this.expandingSubject + this.toggleExpandingSubject() } }, generateTagLink (tag) { diff --git a/src/components/status_content/status_content.js b/src/components/status_content/status_content.js index 527a4cf5..cf72ccb8 100644 --- a/src/components/status_content/status_content.js +++ b/src/components/status_content/status_content.js @@ -116,12 +116,8 @@ const StatusContent = { toggleExpandingSubject () { controlledOrUncontrolledToggle(this, 'expandingSubject') }, - toggleShowMore () { - if (this.mightHideBecauseTall) { - this.toggleShowingTall() - } else if (this.mightHideBecauseSubject) { - this.toggleExpandingSubject() - } + toggleShowingLongSubject () { + controlledOrUncontrolledToggle(this, 'showingLongSubject') }, setMedia () { const attachments = this.attachmentSize === 'hide' ? this.status.attachments : this.galleryAttachments diff --git a/src/components/status_content/status_content.vue b/src/components/status_content/status_content.vue index 69635aad..0a09cda4 100644 --- a/src/components/status_content/status_content.vue +++ b/src/components/status_content/status_content.vue @@ -8,6 +8,12 @@ :status="status" :compact="compact" :single-line="singleLine" + :showing-tall="showingTall" + :expanding-subject="expandingSubject" + :showing-long-subject="showingLongSubject" + :toggle-showing-tall="toggleShowingTall" + :toggle-expanding-subject="toggleExpandingSubject" + :toggle-showing-long-subject="toggleShowingLongSubject" @parseReady="$emit('parseReady', $event)" >
    -- cgit v1.2.3-70-g09d2 From 2a510205c3e18bc1c3ff253dc4521909857cd530 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 15 Sep 2021 23:35:17 -0400 Subject: Fix virtual scrolling for tree threading Ref: tree-threading --- src/components/conversation/conversation.js | 15 ++++++++++----- src/components/conversation/conversation.vue | 2 +- src/components/thread_tree/thread_tree.js | 7 +++++++ 3 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index d4972fbc..1e97bbf0 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -101,13 +101,16 @@ const conversation = { showOtherRepliesButtonInsideStatus () { return this.otherRepliesButtonPosition === 'inside' }, - hideStatus () { + suspendable () { if (this.$refs.statusComponent && this.$refs.statusComponent[0]) { - return this.virtualHidden && this.$refs.statusComponent[0].suspendable + return this.$refs.statusComponent.every(s => s.suspendable) } else { - return this.virtualHidden + return true } }, + hideStatus () { + return this.virtualHidden && this.suspendable + }, status () { return this.$store.state.statuses.allStatusesObject[this.statusId] }, @@ -243,7 +246,6 @@ const conversation = { return this.topLevel }, diveRoot () { - (() => {})(this.conversation) const statusId = this.inlineDivePosition || this.statusId const isTopLevel = !this.parentOf(statusId) return isTopLevel ? null : statusId @@ -257,7 +259,10 @@ const conversation = { shouldShowAllConversationButton () { // The "show all conversation" button tells the user that there exist // other toplevel statuses, so do not show it if there is only a single root - return this.diveMode && this.topLevel.length > 1 + return this.isTreeView && this.isExpanded && this.diveMode && this.topLevel.length > 1 + }, + shouldShowAncestors () { + return this.isTreeView && this.isExpanded && this.ancestorsOf(this.diveRoot).length }, replies () { let i = 1 diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index b3d97075..0cd74539 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -43,7 +43,7 @@ class="thread-body" >
    s.suspendable) + } + return selfSuspendable + }, reverseLookupTable () { return this.conversation.reduce((table, status, index) => { table[status.id] = index -- cgit v1.2.3-70-g09d2 From cc5cff2038c067ceacd98f218bbcffa2a50069eb Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 10 Sep 2021 15:24:23 -0400 Subject: Clean up debug code for tree threading --- src/components/conversation/conversation.js | 15 --------------- src/components/thread_tree/thread_tree.js | 5 ----- 2 files changed, 20 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 1e97bbf0..7f9f24b5 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -15,9 +15,6 @@ library.add( faChevronLeft ) -// const debug = console.log -const debug = () => {} - const sortById = (a, b) => { const idA = a.type === 'retweet' ? a.retweeted_status.id : a.id const idB = b.type === 'retweet' ? b.retweeted_status.id : b.id @@ -165,8 +162,6 @@ const conversation = { forest: {} }) - debug('threads = ', threads) - const walk = (forest, topLevel, depth = 0, processed = {}) => topLevel.map(id => { if (processed[id]) { return [] @@ -192,7 +187,6 @@ const conversation = { }, {}) }, totalReplyCount () { - debug('replyIds=', this.replyIds) const sizes = {} const subTreeSizeFor = (id) => { if (sizes[id]) { @@ -202,7 +196,6 @@ const conversation = { return sizes[id] } this.conversation.map(k => k.id).map(subTreeSizeFor) - debug('totalReplyCount=', sizes) return Object.keys(sizes).reduce((res, id) => { res[id] = sizes[id] - 1 // exclude itself return res @@ -224,7 +217,6 @@ const conversation = { }, {}) }, depths () { - debug('threadTree', this.threadTree) return this.threadTree.reduce((a, k) => { a[k.id] = k.depth return a @@ -233,7 +225,6 @@ const conversation = { topLevel () { const topLevel = this.conversation.reduce((tl, cur) => tl.filter(k => this.getReplies(cur.id).map(v => v.id).indexOf(k.id) === -1), this.conversation) - debug('toplevel =', topLevel) return topLevel }, otherTopLevelCount () { @@ -409,14 +400,8 @@ const conversation = { } }, toggleThreadDisplay (id) { - const depth = this.depths[id] - debug('depth = ', depth) - debug( - 'threadDisplayStatus = ', this.threadDisplayStatus, - 'threadDisplayStatusObject = ', this.threadDisplayStatusObject) const curStatus = this.threadDisplayStatus[id] const nextStatus = curStatus === 'showing' ? 'hidden' : 'showing' - debug('toggling', id, 'to', nextStatus) this.setThreadDisplay(id, nextStatus) }, setThreadDisplayRecursively (id, nextStatus) { diff --git a/src/components/thread_tree/thread_tree.js b/src/components/thread_tree/thread_tree.js index fd21c5bc..0e499b85 100644 --- a/src/components/thread_tree/thread_tree.js +++ b/src/components/thread_tree/thread_tree.js @@ -11,9 +11,6 @@ library.add( faAngleDoubleRight ) -// const debug = console.log -const debug = () => {} - const ThreadTree = { components: { Status @@ -62,8 +59,6 @@ const ThreadTree = { }, {}) }, currentReplies () { - debug('status:', this.status) - debug('getReplies:', this.getReplies(this.status.id)) return this.getReplies(this.status.id).map(({ id }) => this.statusById(id)) }, threadShowing () { -- cgit v1.2.3-70-g09d2 From 20880cdf0bd33d6c189549441ab0ee26b59abf6d Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 16 Sep 2021 00:29:14 -0400 Subject: Make replying and mediaPlaying controlled $refs is not a reliable way to deal with child components under tree threading as it is not reactive, but the children may change at any time. The only good way seems to be making these states aggregated on the conversation component. Ref: tree-threading --- src/components/conversation/conversation.js | 21 +++++++++--- src/components/conversation/conversation.vue | 4 +++ src/components/status/status.js | 50 +++++++++++++++++++++++++--- src/components/thread_tree/thread_tree.js | 3 ++ src/components/thread_tree/thread_tree.vue | 4 +++ 5 files changed, 72 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 7f9f24b5..9aa7b183 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -99,6 +99,10 @@ const conversation = { return this.otherRepliesButtonPosition === 'inside' }, suspendable () { + if (this.isTreeView) { + return Object.entries(this.statusContentProperties) + .every(([k, prop]) => !prop.replying && prop.mediaPlaying.length === 0) + } if (this.$refs.statusComponent && this.$refs.statusComponent[0]) { return this.$refs.statusComponent.every(s => s.suspendable) } else { @@ -303,14 +307,21 @@ const conversation = { return this.conversation.reduce((a, k) => { const id = k.id const props = (() => { - if (this.statusContentPropertiesObject[id]) { - return this.statusContentPropertiesObject[id] - } - return { + const def = { showingTall: false, expandingSubject: false, - showingLongSubject: false + showingLongSubject: false, + isReplying: false, + mediaPlaying: [] + } + + if (this.statusContentPropertiesObject[id]) { + return { + ...def, + ...this.statusContentPropertiesObject[id] + } } + return def })() a[id] = props diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 0cd74539..4d64cf08 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -78,9 +78,13 @@ :controlled-showing-tall="statusContentProperties[status.id].showingTall" :controlled-expanding-subject="statusContentProperties[status.id].expandingSubject" :controlled-showing-long-subject="statusContentProperties[status.id].showingLongSubject" + :controlled-replying="statusContentProperties[status.id].replying" + :controlled-media-playing="statusContentProperties[status.id].mediaPlaying" :controlled-toggle-showing-tall="() => toggleStatusContentProperty(status.id, 'showingTall')" :controlled-toggle-expanding-subject="() => toggleStatusContentProperty(status.id, 'expandingSubject')" :controlled-toggle-showing-long-subject="() => toggleStatusContentProperty(status.id, 'showingLongSubject')" + :controlled-toggle-replying="() => toggleStatusContentProperty(status.id, 'replying')" + :controlled-set-media-playing="(newVal) => toggleStatusContentProperty(status.id, 'mediaPlaying', newVal)" @goto="setHighlight" @toggleExpanded="toggleExpanded" diff --git a/src/components/status/status.js b/src/components/status/status.js index 700b9764..73fad45f 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -61,6 +61,41 @@ library.add( faAngleDoubleRight ) +const camelCase = name => name.charAt(0).toUpperCase() + name.slice(1) + +const controlledOrUncontrolledGetters = list => list.reduce((res, name) => { + const camelized = camelCase(name) + const toggle = `controlledToggle${camelized}` + const controlledName = `controlled${camelized}` + const uncontrolledName = `uncontrolled${camelized}` + res[name] = function () { + return this[toggle] ? this[controlledName] : this[uncontrolledName] + } + return res +}, {}) + +const controlledOrUncontrolledToggle = (obj, name) => { + const camelized = camelCase(name) + const toggle = `controlledToggle${camelized}` + const uncontrolledName = `uncontrolled${camelized}` + if (obj[toggle]) { + obj[toggle]() + } else { + obj[uncontrolledName] = !obj[uncontrolledName] + } +} + +const controlledOrUncontrolledSet = (obj, name, val) => { + const camelized = camelCase(name) + const set = `controlledSet${camelized}` + const uncontrolledName = `uncontrolled${camelized}` + if (obj[set]) { + obj[set](val) + } else { + obj[uncontrolledName] = val + } +} + const Status = { name: 'Status', components: { @@ -108,20 +143,25 @@ const Status = { 'controlledToggleExpandingSubject', 'controlledShowingLongSubject', 'controlledToggleShowingLongSubject', + 'controlledReplying', + 'controlledToggleReplying', + 'controlledMediaPlaying', + 'controlledSetMediaPlaying', 'dive' ], data () { return { - replying: false, + uncontrolledReplying: false, unmuted: false, userExpanded: false, - mediaPlaying: [], + uncontrolledMediaPlaying: [], suspendable: true, error: null, headTailLinks: null } }, computed: { + ...controlledOrUncontrolledGetters(['replying', 'mediaPlaying']), muteWords () { return this.mergedConfig.muteWords }, @@ -351,7 +391,7 @@ const Status = { this.error = undefined }, toggleReplying () { - this.replying = !this.replying + controlledOrUncontrolledToggle(this, 'replying') }, gotoOriginal (id) { if (this.inConversation) { @@ -371,10 +411,10 @@ const Status = { return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames) }, addMediaPlaying (id) { - this.mediaPlaying.push(id) + controlledOrUncontrolledSet(this, 'mediaPlaying', this.mediaPlaying.concat(id)) }, removeMediaPlaying (id) { - this.mediaPlaying = this.mediaPlaying.filter(mediaId => mediaId !== id) + controlledOrUncontrolledSet(this, 'mediaPlaying', this.mediaPlaying.filter(mediaId => mediaId !== id)) }, setHeadTailLinks (headTailLinks) { this.headTailLinks = headTailLinks diff --git a/src/components/thread_tree/thread_tree.js b/src/components/thread_tree/thread_tree.js index 0e499b85..71e63725 100644 --- a/src/components/thread_tree/thread_tree.js +++ b/src/components/thread_tree/thread_tree.js @@ -80,6 +80,9 @@ const ThreadTree = { }, toggleCurrentProp (name) { this.toggleStatusContentProperty(this.status.id, name) + }, + setCurrentProp (name, newVal) { + this.setStatusContentProperty(this.status.id, name) } } } diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue index dce03f27..cee223e8 100644 --- a/src/components/thread_tree/thread_tree.vue +++ b/src/components/thread_tree/thread_tree.vue @@ -22,9 +22,13 @@ :controlled-showing-tall="currentProp.showingTall" :controlled-expanding-subject="currentProp.expandingSubject" :controlled-showing-long-subject="currentProp.showingLongSubject" + :controlled-replying="currentProp.replying" + :controlled-media-playing="currentProp.mediaPlaying" :controlled-toggle-showing-tall="() => toggleCurrentProp('showingTall')" :controlled-toggle-expanding-subject="() => toggleCurrentProp('expandingSubject')" :controlled-toggle-showing-long-subject="() => toggleCurrentProp('showingLongSubject')" + :controlled-toggle-replying="() => toggleCurrentProp('replying')" + :controlled-set-media-playing="(newVal) => setCurrentProp('mediaPlaying', newVal)" :dive="dive ? () => dive(status.id) : undefined" @goto="setHighlight" -- cgit v1.2.3-70-g09d2 From f8c5cbcd0d5d092c1264032a1be003f828dfc499 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 16 Sep 2021 09:22:49 -0400 Subject: Fix timeline jump when scrolling Ref: tree-threading --- src/components/conversation/conversation.js | 19 ++++++++++++++++++- src/components/status/status.js | 3 --- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 9aa7b183..b9ebe7eb 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -469,7 +469,24 @@ const conversation = { } else { this.inlineDivePosition = id } - this.setHighlight(id) + // Because the conversation can be unmounted when out of sight + // and mounted again when it comes into sight, + // the `mounted` or `created` function in `status` should not + // contain scrolling calls, as we do not want the page to jump + // when we scroll with an expanded conversation. + // + // Now the method is to rely solely on the `highlight` watcher + // in `status` components. + // In linear views, all statuses are rendered at all times, but + // in tree views, it is possible that a change in active status + // removes and adds status components (e.g. an originally child + // status becomes an ancestor status, and thus they will be + // different). + // Here, let the components be rendered first, in order to trigger + // the `highlight` watcher. + this.$nextTick(() => { + this.setHighlight(id) + }) }, goToCurrent () { this.tryScrollTo(this.diveRoot || this.topLevel[0].id) diff --git a/src/components/status/status.js b/src/components/status/status.js index 73fad45f..7bdcb665 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -439,9 +439,6 @@ const Status = { } } }, - mounted () { - this.scrollIfHighlighted(this.highlight) - }, watch: { 'highlight': function (id) { this.scrollIfHighlighted(id) -- cgit v1.2.3-70-g09d2 From 5768806d1ba65bf49e4313f4a7ace602ae456a89 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Mon, 22 Nov 2021 11:20:22 -0500 Subject: Fix showingLongSubject not correctly propagated --- src/components/status_body/status_body.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/components/status_body/status_body.vue b/src/components/status_body/status_body.vue index a088e6bc..24d842c2 100644 --- a/src/components/status_body/status_body.vue +++ b/src/components/status_body/status_body.vue @@ -17,14 +17,14 @@ -- cgit v1.2.3-70-g09d2 From 9432fcec7ddfce7fd52ee2ba3f0ef531d61d9b46 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 6 Mar 2022 13:50:15 -0500 Subject: Make 'Show full conversation' button have left border in embbeded mode --- src/components/conversation/conversation.vue | 38 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 4d64cf08..73c613b9 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -19,29 +19,29 @@
    -
    - - - - {{ $tc('status.show_all_conversation', otherTopLevelCount, { numStatus: otherTopLevelCount }) }} - - -
    +
    + + + + {{ $tc('status.show_all_conversation', otherTopLevelCount, { numStatus: otherTopLevelCount }) }} + + +
    Date: Sun, 6 Mar 2022 13:57:48 -0500 Subject: Split conversation display style into two different settings linear => linear (now default) simple_tree => tree / conversationTreeAdvanced=false tree => tree / conversationTreeAdvanced=true --- src/components/conversation/conversation.js | 4 ++-- src/components/settings_modal/tabs/general_tab.js | 2 +- src/components/settings_modal/tabs/general_tab.vue | 5 +++++ src/modules/config.js | 1 + src/modules/instance.js | 3 ++- 5 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index b9ebe7eb..46228e37 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -81,10 +81,10 @@ const conversation = { return this.$store.getters.mergedConfig.conversationDisplay }, isTreeView () { - return this.displayStyle === 'tree' || this.displayStyle === 'simple_tree' + return !this.isLinearView }, treeViewIsSimple () { - return this.displayStyle === 'simple_tree' + return !this.$store.getters.mergedConfig.conversationTreeAdvanced }, isLinearView () { return this.displayStyle === 'linear' diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js index a963d204..8ae0021c 100644 --- a/src/components/settings_modal/tabs/general_tab.js +++ b/src/components/settings_modal/tabs/general_tab.js @@ -20,7 +20,7 @@ const GeneralTab = { value: mode, label: this.$t(`settings.subject_line_${mode === 'masto' ? 'mastodon' : mode}`) })), - conversationDisplayOptions: ['tree', 'simple_tree', 'linear'].map(mode => ({ + conversationDisplayOptions: ['tree', 'linear'].map(mode => ({ key: mode, value: mode, label: this.$t(`settings.conversation_display_${mode}`) diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index d5ae7810..28b39d7b 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -165,6 +165,11 @@ v-if="conversationDisplay !== 'linear'" class="setting-list suboptions" > +
  • + + {{ $t('settings.tree_advanced') }} + +
  • +
  • + + {{ $t('settings.tree_fade_ancestors') }} + +
  • -- cgit v1.2.3-70-g09d2 From 7a17eb7fec4e8f7dbe0a288a22498b800886ac01 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 21 Mar 2022 22:00:25 +0200 Subject: fix selects --- src/components/select/select.js | 7 ++----- src/components/select/select.vue | 5 ++--- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/components/select/select.js b/src/components/select/select.js index 49535d07..ec571a14 100644 --- a/src/components/select/select.js +++ b/src/components/select/select.js @@ -8,12 +8,9 @@ library.add( ) export default { - model: { - prop: 'value', - event: 'change' - }, + emits: ['update:modelValue'], props: [ - 'value', + 'modelValue', 'disabled', 'unstyled', 'kind' diff --git a/src/components/select/select.vue b/src/components/select/select.vue index 56e651e3..08c88979 100644 --- a/src/components/select/select.vue +++ b/src/components/select/select.vue @@ -1,4 +1,3 @@ - - @@ -13,7 +13,7 @@ import localeService from 'src/services/locale/locale.service.js' export default { name: 'Timeago', - props: ['time', 'autoUpdate', 'longFormat', 'nowThreshold'], + props: ['time', 'autoUpdate', 'longFormat', 'nowThreshold', 'templateKey'], data () { return { relativeTime: { key: 'time.now', num: 0 }, @@ -26,21 +26,31 @@ export default { return typeof this.time === 'string' ? new Date(Date.parse(this.time)).toLocaleString(browserLocale) : this.time.toLocaleString(browserLocale) + }, + relativeTimeString () { + const timeString = this.$i18n.tc(this.relativeTime.key, this.relativeTime.num, [this.relativeTime.num]) + + if (typeof this.templateKey === 'string' && this.relativeTime.key !== 'time.now') { + return this.$i18n.t(this.templateKey, [timeString]) + } + + return timeString } }, - created () { - this.refreshRelativeTimeObject() - }, - unmounted () { - clearTimeout(this.interval) - }, watch: { time (newVal, oldVal) { if (oldVal !== newVal) { + clearTimeout(this.interval) this.refreshRelativeTimeObject() } } }, + created () { + this.refreshRelativeTimeObject() + }, + unmounted () { + clearTimeout(this.interval) + }, methods: { refreshRelativeTimeObject () { const nowThreshold = typeof this.nowThreshold === 'number' ? this.nowThreshold : 1 -- cgit v1.2.3-70-g09d2 From dbfca224d812c2ba80a48852ba047bb65c4c6dd9 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 4 Aug 2022 01:56:52 +0300 Subject: server-side storage for flags --- .../update_notification/update_notification.js | 40 +++++- .../update_notification/update_notification.scss | 95 +++++++++++-- .../update_notification/update_notification.vue | 52 ++++--- src/lib/persisted_state.js | 1 + src/main.js | 3 + src/modules/serverSideStorage.js | 158 +++++++++++++++++++++ src/modules/users.js | 2 + .../entity_normalizer/entity_normalizer.service.js | 3 + 8 files changed, 323 insertions(+), 31 deletions(-) create mode 100644 src/modules/serverSideStorage.js (limited to 'src') diff --git a/src/components/update_notification/update_notification.js b/src/components/update_notification/update_notification.js index 6b8665dd..1dd771eb 100644 --- a/src/components/update_notification/update_notification.js +++ b/src/components/update_notification/update_notification.js @@ -10,15 +10,49 @@ library.add( faTimes ) -const SettingsModal = { +const CURRENT_UPDATE_COUNTER = 1 + +const UpdateNotification = { data () { return { - pleromaTanVariant: Math.random() > 0.5 ? pleromaTan : pleromaTanFox + pleromaTanVariant: Math.random() > 0.5 ? pleromaTan : pleromaTanFox, + showingMore: true, + contentHeight: 0 } }, components: { Modal + }, + computed: { + pleromaTanStyles () { + return { + 'shape-outside': 'url(' + this.pleromaTanVariant + ')' + } + }, + shouldShow () { + return this.$store.state.serverSideStorage.flagStorage.updateCounter < CURRENT_UPDATE_COUNTER && + !this.$store.state.serverSideStorage.flagStorage.dontShowUpdateNotifs + } + }, + methods: { + toggleShow () { + this.showingMore = !this.showingMore + }, + neverShowAgain () { + this.$store.commit('setFlag', { flag: 'updateCounter', value: CURRENT_UPDATE_COUNTER }) + this.$store.commit('setFlag', { flag: 'dontShowUpdateNotifs', value: 1 }) + this.$store.dispatch('pushServerSideStorage') + }, + dismiss () { + this.$store.commit('setFlag', { flag: 'updateCounter', value: CURRENT_UPDATE_COUNTER }) + this.$store.dispatch('pushServerSideStorage') + } + }, + mounted () { + setTimeout(() => { + this.contentHeight = this.$refs.content.offsetHeight + }, 10) } } -export default SettingsModal +export default UpdateNotification diff --git a/src/components/update_notification/update_notification.scss b/src/components/update_notification/update_notification.scss index 5fd9eb9b..594f4c6b 100644 --- a/src/components/update_notification/update_notification.scss +++ b/src/components/update_notification/update_notification.scss @@ -1,5 +1,13 @@ @import 'src/_variables.scss'; +.UpdateNotification { + overflow: hidden; +} .UpdateNotificationModal { + --__top-fringe: 18em; // how much pleroma-tan should stick her head above + --__bottom-fringe: 80em; // just reserving as much as we can, number is mostly irrelevant + --__right-fringe: 8em; + + font-size: 15px; /* Explanation: * Modal is positioned vertically centered. * 100vh - 100% = Distance between modal's top+bottom boundaries and screen @@ -8,27 +16,90 @@ * bottom of the screen * - 50px - leaving tiny amount of space so that titlebar + tiny amount of modal is visible */ - transform: translateY(calc(((100vh - 100%) / 2 + 5%))); - max-width: 90vh; - width: 30em; position: relative; + transition: transform; + transition-timing-function: ease-in-out; + transition-duration: 500ms; + + .text { + width: 40em; + padding-left: 1em; + } @media all and (max-width: 800px) { /* For mobile, the modal takes 100% of the available screen. This ensures the minimized modal is always 50px above the browser bottom bar regardless of whether or not it is visible. */ - transform: translateY(calc(100% - 50px)); + width: 100vw; + } + + @media all and (max-height: 600px) { + display: none; } - .panel-body > p { - width: calc(100% - 10em) + + .content { + overflow: hidden; + margin-top: calc(-1 * var(--__top-fringe)); + margin-bottom: calc(-1 * var(--__bottom-fringe)); + margin-right: calc(-1 * var(--__right-fringe)); + } + + .panel-body { + border-width: 0 0 1px 0; + border-style: solid; + border-color: var(--border, $fallback--border); + } + + .panel-footer { + z-index: 22; + position: relative; + border-width: 0; + grid-template-columns: auto; } .pleroma-tan { - max-width: 20em; - max-height: 40em; - position: absolute; - right: -5em; - top: -10em; - z-index: 10; + object-fit: cover; + object-position: top; + transition: position, left, right, top, bottom, max-width, max-height; + transition-timing-function: ease-in-out; + transition-duration: 500ms; + width: 25em; + float: right; + z-index: 20; + position: relative; + shape-margin: 0.5em; + } + + .spacer-top { + min-height: var(--__top-fringe); + } + + .spacer-bottom { + min-height: var(--__bottom-fringe); + } + + .extra-info { + transition: max-height, padding, height; + transition-timing-function: ease-in-out; + transition-duration: 500ms; + max-height: auto; + height: auto; + } + + &.-peek { + transform: translateY(calc(((100vh - 100%) / 2))); + + .pleroma-tan { + float: right; + z-index: 10; + shape-image-threshold: 0.7; + } + + .extra-info { + max-height: 0; + height: 0; + display: none; + overflow: hidden; + } } } diff --git a/src/components/update_notification/update_notification.vue b/src/components/update_notification/update_notification.vue index e7118d81..793966eb 100644 --- a/src/components/update_notification/update_notification.vue +++ b/src/components/update_notification/update_notification.vue @@ -1,36 +1,56 @@ -- cgit v1.2.3-70-g09d2 From 17aa503106f129e391f8478ade6821f09ef7494a Mon Sep 17 00:00:00 2001 From: tusooa Date: Tue, 8 Nov 2022 00:43:33 -0500 Subject: Make notification panel a list of articles --- src/components/notification/notification.vue | 17 ++++++++++------- src/components/notifications/notifications.vue | 6 +++++- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index 26b174ff..84f3f7de 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -1,11 +1,14 @@ diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index 7ed419d1..02a87fcc 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -50,10 +50,14 @@
    -
    +
    -- cgit v1.2.3-70-g09d2 From b718c0c77d16bf917dc564404cb0fa61a2c535b3 Mon Sep 17 00:00:00 2001 From: tusooa Date: Tue, 8 Nov 2022 10:34:38 -0500 Subject: Use feed role for notifs and timelines --- src/components/notifications/notifications.vue | 2 +- src/components/timeline/timeline.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index 02a87fcc..3d5878d4 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -52,7 +52,7 @@
    Date: Wed, 9 Nov 2022 19:32:49 +0000 Subject: Apply 1 suggestion(s) to 1 file(s) --- src/components/staff_panel/staff_panel.js | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/components/staff_panel/staff_panel.js b/src/components/staff_panel/staff_panel.js index 91f5e910..46a92ac7 100644 --- a/src/components/staff_panel/staff_panel.js +++ b/src/components/staff_panel/staff_panel.js @@ -14,7 +14,6 @@ const StaffPanel = { computed: { groupedStaffAccounts () { const staffAccounts = map(this.staffAccounts, this.findUserByName).filter(_ => _) - console.log(staffAccounts) const groupedStaffAccounts = groupBy(staffAccounts, 'role') return [ -- cgit v1.2.3-70-g09d2 From 96d45617e24980dd60798bcd5bbf9dd67d72c20e Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 21 Nov 2022 21:44:03 +0200 Subject: make better defaults for user popovers, closer to OG behavior --- src/modules/config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modules/config.js b/src/modules/config.js index c966602e..3cd6888f 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -83,8 +83,8 @@ export const defaultState = { useContainFit: true, disableStickyHeaders: false, showScrollbars: false, - userPopoverAvatarAction: 'close', - userPopoverOverlay: true, + userPopoverAvatarAction: 'open', + userPopoverOverlay: false, sidebarColumnWidth: '25rem', contentColumnWidth: '45rem', notifsColumnWidth: '25rem', -- cgit v1.2.3-70-g09d2 From 3c0e7882b10989424c3ec98413b555373efa1719 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 21 Nov 2022 22:17:33 +0200 Subject: lint --- src/components/emoji_input/emoji_input.vue | 13 ++++++++++--- src/components/emoji_picker/emoji_picker.vue | 4 ++-- src/components/mobile_nav/mobile_nav.vue | 6 +++--- src/components/notifications/notifications.vue | 2 +- src/components/popover/popover.vue | 5 ++++- .../quick_filter_settings/quick_filter_settings.vue | 2 +- src/components/quick_view_settings/quick_view_settings.vue | 2 +- src/components/search/search.js | 4 ++-- src/components/timeline/timeline.vue | 14 ++++++++++---- 9 files changed, 34 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue index 63bf856e..c9bbc18f 100644 --- a/src/components/emoji_input/emoji_input.vue +++ b/src/components/emoji_input/emoji_input.vue @@ -6,9 +6,16 @@ > -
    +
    {{ preText }} - x + x {{ postText }}