Merge pull request #4848 from h3poteto/iss-4796/filter
refs #4796 Apply filters in timelines
This commit is contained in:
commit
0e7713895f
|
@ -20,6 +20,8 @@
|
|||
"hide_media": "Hide media",
|
||||
"report": "Report {user}",
|
||||
"open_original": "Open original page",
|
||||
"filtered": "Filtered",
|
||||
"show_anyway": "Show anyway",
|
||||
"actions": {
|
||||
"reply": "Reply",
|
||||
"reblog": "reblog",
|
||||
|
|
|
@ -59,6 +59,7 @@ export default function Reply(props: Props) {
|
|||
key={status.id}
|
||||
onRefresh={() => {}}
|
||||
openMedia={props.openMedia}
|
||||
filters={[]}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -38,6 +38,7 @@ export default function Tag(props: Props) {
|
|||
key={status.id}
|
||||
onRefresh={() => {}}
|
||||
openMedia={props.openMedia}
|
||||
filters={[]}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -43,6 +43,7 @@ export default function Thread(props: Props) {
|
|||
key={status.id}
|
||||
onRefresh={() => {}}
|
||||
openMedia={props.openMedia}
|
||||
filters={[]}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -50,6 +50,7 @@ export default function Timeline(props: Props) {
|
|||
key={index}
|
||||
onRefresh={status => setStatuses(current => updateStatus(current, status))}
|
||||
openMedia={props.openMedia}
|
||||
filters={[]}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
|
|
|
@ -27,6 +27,7 @@ export default function Notifications(props: Props) {
|
|||
const [firstItemIndex, setFirstItemIndex] = useState(TIMELINE_MAX_STATUSES)
|
||||
const [marker, setMarker] = useState<Marker | null>(null)
|
||||
const [pleromaUnreads, setPleromaUnreads] = useState<Array<string>>([])
|
||||
const [filters, setFilters] = useState<Array<Entity.Filter>>([])
|
||||
|
||||
const scrollerRef = useRef<HTMLElement | null>(null)
|
||||
const streaming = useRef<WebSocketInterface | null>(null)
|
||||
|
@ -37,6 +38,8 @@ export default function Notifications(props: Props) {
|
|||
|
||||
useEffect(() => {
|
||||
const f = async () => {
|
||||
const f = await loadFilter(props.client)
|
||||
setFilters(f)
|
||||
const res = await loadNotifications(props.client)
|
||||
setNotifications(res)
|
||||
const instance = await props.client.getInstance()
|
||||
|
@ -80,6 +83,11 @@ export default function Notifications(props: Props) {
|
|||
}
|
||||
}, [marker, unreadNotifications, notifications])
|
||||
|
||||
const loadFilter = async (client: MegalodonInterface): Promise<Array<Entity.Filter>> => {
|
||||
const res = await client.getFilters()
|
||||
return res.data.filter(f => f.context.includes('notifications'))
|
||||
}
|
||||
|
||||
const loadNotifications = async (client: MegalodonInterface, maxId?: string): Promise<Array<Entity.Notification>> => {
|
||||
let options = { limit: 30 }
|
||||
if (maxId) {
|
||||
|
@ -209,6 +217,7 @@ export default function Notifications(props: Props) {
|
|||
onRefresh={updateStatus}
|
||||
key={notification.id}
|
||||
openMedia={media => props.setAttachment(media)}
|
||||
filters={filters}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -26,6 +26,7 @@ export default function Timeline(props: Props) {
|
|||
const [firstItemIndex, setFirstItemIndex] = useState(TIMELINE_MAX_STATUSES)
|
||||
const [composeHeight, setComposeHeight] = useState(120)
|
||||
const [list, setList] = useState<Entity.List | null>(null)
|
||||
const [filters, setFilters] = useState<Array<Entity.Filter>>([])
|
||||
|
||||
const router = useRouter()
|
||||
const { formatMessage } = useIntl()
|
||||
|
@ -50,6 +51,8 @@ export default function Timeline(props: Props) {
|
|||
|
||||
useEffect(() => {
|
||||
const f = async () => {
|
||||
const f = await loadFilter(props.timeline, props.client)
|
||||
setFilters(f)
|
||||
const res = await loadTimeline(props.timeline, props.client)
|
||||
setStatuses(res)
|
||||
const instance = await props.client.getInstance()
|
||||
|
@ -106,6 +109,24 @@ export default function Timeline(props: Props) {
|
|||
}
|
||||
}, [props.timeline, props.client, props.account])
|
||||
|
||||
const loadFilter = async (tl: string, client: MegalodonInterface): Promise<Array<Entity.Filter>> => {
|
||||
const res = await client.getFilters()
|
||||
let context = 'home'
|
||||
switch (tl) {
|
||||
case 'home':
|
||||
context = 'home'
|
||||
break
|
||||
case 'local':
|
||||
case 'public':
|
||||
context = 'public'
|
||||
break
|
||||
default:
|
||||
context = 'home'
|
||||
break
|
||||
}
|
||||
return res.data.filter(f => f.context.includes(context))
|
||||
}
|
||||
|
||||
const loadTimeline = async (tl: string, client: MegalodonInterface, maxId?: string): Promise<Array<Entity.Status>> => {
|
||||
let options = { limit: 30 }
|
||||
if (maxId) {
|
||||
|
@ -223,6 +244,7 @@ export default function Timeline(props: Props) {
|
|||
key={status.id}
|
||||
onRefresh={status => setStatuses(current => updateStatus(current, status))}
|
||||
openMedia={media => props.setAttachment(media)}
|
||||
filters={filters}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -10,6 +10,7 @@ type Props = {
|
|||
client: MegalodonInterface
|
||||
onRefresh: (status: Entity.Status) => void
|
||||
openMedia: (media: Entity.Attachment) => void
|
||||
filters: Array<Entity.Filter>
|
||||
}
|
||||
|
||||
export default function Notification(props: Props) {
|
||||
|
@ -23,6 +24,7 @@ export default function Notification(props: Props) {
|
|||
status={props.notification.status}
|
||||
onRefresh={props.onRefresh}
|
||||
openMedia={props.openMedia}
|
||||
filters={props.filters}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -19,11 +19,13 @@ type Props = {
|
|||
client: MegalodonInterface
|
||||
onRefresh: (status: Entity.Status) => void
|
||||
openMedia: (media: Entity.Attachment) => void
|
||||
filters: Array<Entity.Filter>
|
||||
}
|
||||
|
||||
export default function Status(props: Props) {
|
||||
const status = originalStatus(props.status)
|
||||
const [spoilered, setSpoilered] = useState(status.spoiler_text.length > 0)
|
||||
const [ignoreFilter, setIgnoreFilter] = useState(false)
|
||||
const router = useRouter()
|
||||
const { formatMessage } = useIntl()
|
||||
|
||||
|
@ -71,6 +73,20 @@ export default function Status(props: Props) {
|
|||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!ignoreFilter &&
|
||||
props.filters.map(f => f.phrase).filter(keyword => props.status.content.toLowerCase().includes(keyword.toLowerCase())).length > 0
|
||||
) {
|
||||
return (
|
||||
<div className="border-b mr-2 py-2 text-center">
|
||||
<FormattedMessage id="timeline.status.filtered" />
|
||||
<span className="text-blue-700 cursor-pointer pl-4" onClick={() => setIgnoreFilter(true)}>
|
||||
<FormattedMessage id="timeline.status.show_anyway" />
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="border-b mr-2 py-1">
|
||||
{rebloggedHeader(
|
||||
|
|
|
@ -64,15 +64,19 @@ export const AccountsProvider: React.FC<Props> = ({ children }) => {
|
|||
const client = generator(account.sns, account.url, account.access_token, 'Whalebird')
|
||||
const instance = await client.getInstance()
|
||||
const notifications = (await client.getNotifications()).data
|
||||
const res = await client.getMarkers(['notifications'])
|
||||
const marker = res.data as Entity.Marker
|
||||
if (marker.notifications) {
|
||||
const count = unreadCount(marker.notifications, notifications)
|
||||
setUnreads(current =>
|
||||
Object.assign({}, current, {
|
||||
[account.id?.toString()]: count
|
||||
})
|
||||
)
|
||||
try {
|
||||
const res = await client.getMarkers(['notifications'])
|
||||
const marker = res.data as Entity.Marker
|
||||
if (marker.notifications) {
|
||||
const count = unreadCount(marker.notifications, notifications)
|
||||
setUnreads(current =>
|
||||
Object.assign({}, current, {
|
||||
[account.id?.toString()]: count
|
||||
})
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
||||
const ws = generator(account.sns, instance.data.urls.streaming_api, account.access_token, 'Whalebird')
|
||||
|
|
Loading…
Reference in New Issue