やった

This commit is contained in:
syuilo 2018-06-07 06:13:57 +09:00
parent 818bc96aab
commit be9f836b21
13 changed files with 159 additions and 16 deletions

View File

@ -87,6 +87,7 @@ common:
swap-right: "右に移動" swap-right: "右に移動"
remove: "カラムを削除" remove: "カラムを削除"
add-column: "カラムを追加" add-column: "カラムを追加"
rename: "名前を変更"
common/views/components/connect-failed.vue: common/views/components/connect-failed.vue:
title: "サーバーに接続できません" title: "サーバーに接続できません"

View File

@ -20,6 +20,10 @@ export default Vue.extend({
type: String, type: String,
required: false required: false
}, },
name: {
type: String,
required: false
},
menu: { menu: {
type: Array, type: Array,
required: false required: false
@ -75,6 +79,17 @@ export default Vue.extend({
showMenu() { showMenu() {
const items = [{ const items = [{
content: '%fa:pencil-alt% %i18n:common.deck.rename%',
onClick: () => {
(this as any).apis.input({
title: '%i18n:common.deck.rename%',
default: this.name,
allowEmpty: false
}).then(name => {
this.$store.dispatch('settings/renameDeckColumn', { id: this.id, name });
});
}
}, null, {
content: '%fa:arrow-left% %i18n:common.deck.swap-left%', content: '%fa:arrow-left% %i18n:common.deck.swap-left%',
onClick: () => { onClick: () => {
this.$store.dispatch('settings/swapLeftDeckColumn', this.id); this.$store.dispatch('settings/swapLeftDeckColumn', this.id);
@ -84,7 +99,7 @@ export default Vue.extend({
onClick: () => { onClick: () => {
this.$store.dispatch('settings/swapRightDeckColumn', this.id); this.$store.dispatch('settings/swapRightDeckColumn', this.id);
} }
}, { }, null, {
content: '%fa:trash-alt R% %i18n:common.deck.remove%', content: '%fa:trash-alt R% %i18n:common.deck.remove%',
onClick: () => { onClick: () => {
this.$store.dispatch('settings/removeDeckColumn', this.id); this.$store.dispatch('settings/removeDeckColumn', this.id);

View File

@ -18,6 +18,11 @@ export default Vue.extend({
list: { list: {
type: Object, type: Object,
required: true required: true
},
mediaOnly: {
type: Boolean,
required: false,
default: false
} }
}, },
@ -30,6 +35,12 @@ export default Vue.extend({
}; };
}, },
watch: {
mediaOnly() {
this.fetch();
}
},
mounted() { mounted() {
if (this.connection) this.connection.close(); if (this.connection) this.connection.close();
this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id); this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id);
@ -52,6 +63,7 @@ export default Vue.extend({
(this as any).api('notes/user-list-timeline', { (this as any).api('notes/user-list-timeline', {
listId: this.list.id, listId: this.list.id,
limit: fetchLimit + 1, limit: fetchLimit + 1,
mediaOnly: this.mediaOnly,
includeMyRenotes: this.$store.state.settings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}).then(notes => { }).then(notes => {
@ -72,6 +84,7 @@ export default Vue.extend({
listId: this.list.id, listId: this.list.id,
limit: fetchLimit + 1, limit: fetchLimit + 1,
untilId: (this.$refs.timeline as any).tail().id, untilId: (this.$refs.timeline as any).tail().id,
mediaOnly: this.mediaOnly,
includeMyRenotes: this.$store.state.settings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}); });
@ -89,6 +102,8 @@ export default Vue.extend({
return promise; return promise;
}, },
onNote(note) { onNote(note) {
if (this.mediaOnly && note.media.length == 0) return;
// Prepend a note // Prepend a note
(this.$refs.timeline as any).prepend(note); (this.$refs.timeline as any).prepend(note);
}, },

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<x-column :id="id"> <x-column :id="column.id" :name="name">
<span slot="header">%fa:bell R%%i18n:common.deck.notifications%</span> <span slot="header">%fa:bell R%{{ name }}</span>
<x-notifications/> <x-notifications/>
</x-column> </x-column>
@ -20,10 +20,17 @@ export default Vue.extend({
}, },
props: { props: {
id: { column: {
type: String, type: Object,
required: true required: true
} }
} },
computed: {
name(): string {
if (this.column.name) return this.column.name;
return '%i18n:common.deck.notifications%';
}
},
}); });
</script> </script>

View File

@ -1,15 +1,20 @@
<template> <template>
<div> <div>
<x-column :id="column.id"> <x-column :id="column.id" :menu="menu" :name="name">
<span slot="header"> <span slot="header">
<template v-if="column.type == 'home'">%fa:home%%i18n:common.deck.home%</template> <template v-if="column.type == 'home'">%fa:home%</template>
<template v-if="column.type == 'local'">%fa:R comments%%i18n:common.deck.local%</template> <template v-if="column.type == 'local'">%fa:R comments%</template>
<template v-if="column.type == 'global'">%fa:globe%%i18n:common.deck.global%</template> <template v-if="column.type == 'global'">%fa:globe%</template>
<template v-if="column.type == 'list'">%fa:list%{{ column.list.title }}</template> <template v-if="column.type == 'list'">%fa:list%</template>
<span>{{ name }}</span>
</span> </span>
<x-list-tl v-if="column.type == 'list'" :list="column.list"/> <div class="editor" v-if="edit">
<x-tl v-else :src="column.type"/> <mk-switch v-model="column.isMediaOnly" @change="onChangeSettings" text="%i18n:@is-media-only%"/>
<mk-switch v-model="column.isMediaView" @change="onChangeSettings" text="%i18n:@is-media-view%"/>
</div>
<x-list-tl v-if="column.type == 'list'" :list="column.list" :media-only="column.isMediaOnly"/>
<x-tl v-else :src="column.type" :media-only="column.isMediaOnly"/>
</x-column> </x-column>
</div> </div>
</template> </template>
@ -32,6 +37,37 @@ export default Vue.extend({
type: Object, type: Object,
required: true required: true
} }
},
data() {
return {
edit: false,
menu: [{
content: '%fa:cog% %i18n:@edit%',
onClick: () => {
this.edit = !this.edit;
}
}]
}
},
computed: {
name(): string {
if (this.column.name) return this.column.name;
switch (this.column.type) {
case 'home': return '%i18n:common.deck.home%';
case 'local': return '%i18n:common.deck.local%';
case 'global': return '%i18n:common.deck.global%';
case 'list': return this.column.list.title;
}
}
},
methods: {
onChangeSettings(v) {
this.$store.dispatch('settings/saveDeck');
}
} }
}); });
</script> </script>

View File

@ -18,6 +18,11 @@ export default Vue.extend({
type: String, type: String,
required: false, required: false,
default: 'home' default: 'home'
},
mediaOnly: {
type: Boolean,
required: false,
default: false
} }
}, },
@ -31,6 +36,12 @@ export default Vue.extend({
}; };
}, },
watch: {
mediaOnly() {
this.fetch();
}
},
computed: { computed: {
stream(): any { stream(): any {
return this.src == 'home' return this.src == 'home'
@ -78,6 +89,7 @@ export default Vue.extend({
(this.$refs.timeline as any).init(() => new Promise((res, rej) => { (this.$refs.timeline as any).init(() => new Promise((res, rej) => {
(this as any).api(this.endpoint, { (this as any).api(this.endpoint, {
limit: fetchLimit + 1, limit: fetchLimit + 1,
mediaOnly: this.mediaOnly,
includeMyRenotes: this.$store.state.settings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}).then(notes => { }).then(notes => {
@ -97,6 +109,7 @@ export default Vue.extend({
const promise = (this as any).api(this.endpoint, { const promise = (this as any).api(this.endpoint, {
limit: fetchLimit + 1, limit: fetchLimit + 1,
mediaOnly: this.mediaOnly,
untilId: (this.$refs.timeline as any).tail().id, untilId: (this.$refs.timeline as any).tail().id,
includeMyRenotes: this.$store.state.settings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
@ -116,6 +129,8 @@ export default Vue.extend({
}, },
onNote(note) { onNote(note) {
if (this.mediaOnly && note.media.length == 0) return;
// Prepend a note // Prepend a note
(this.$refs.timeline as any).prepend(note); (this.$refs.timeline as any).prepend(note);
}, },

View File

@ -3,7 +3,7 @@
<div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode"> <div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode">
<template v-for="column in columns"> <template v-for="column in columns">
<x-widgets-column v-if="column.type == 'widgets'" :key="column.id" :column="column"/> <x-widgets-column v-if="column.type == 'widgets'" :key="column.id" :column="column"/>
<x-notifications-column v-if="column.type == 'notifications'" :key="column.id" :id="column.id"/> <x-notifications-column v-if="column.type == 'notifications'" :key="column.id" :column="column"/>
<x-tl-column v-if="column.type == 'home'" :key="column.id" :column="column"/> <x-tl-column v-if="column.type == 'home'" :key="column.id" :column="column"/>
<x-tl-column v-if="column.type == 'local'" :key="column.id" :column="column"/> <x-tl-column v-if="column.type == 'local'" :key="column.id" :column="column"/>
<x-tl-column v-if="column.type == 'global'" :key="column.id" :column="column"/> <x-tl-column v-if="column.type == 'global'" :key="column.id" :column="column"/>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="wtdtxvecapixsepjtcupubtsmometobz"> <div class="wtdtxvecapixsepjtcupubtsmometobz">
<x-column :id="column.id" :menu="menu" :naked="true" :narrow="true"> <x-column :id="column.id" :menu="menu" :naked="true" :narrow="true" :name="name">
<span slot="header">%fa:calculator%%i18n:common.deck.widgets%</span> <span slot="header">%fa:calculator%{{ name }}</span>
<div class="gqpwvtwtprsbmnssnbicggtwqhmylhnq"> <div class="gqpwvtwtprsbmnssnbicggtwqhmylhnq">
<template v-if="edit"> <template v-if="edit">
@ -81,6 +81,13 @@ export default Vue.extend({
} }
}, },
computed: {
name(): string {
if (this.column.name) return this.column.name;
return '%i18n:common.deck.widgets%';
}
},
created() { created() {
this.menu = [{ this.menu = [{
content: '%fa:cog% %i18n:@edit%', content: '%fa:cog% %i18n:@edit%',

View File

@ -222,6 +222,12 @@ export default (os: MiOS) => new Vuex.Store({
const column = state.deck.columns.find(c => c.id == x.id); const column = state.deck.columns.find(c => c.id == x.id);
if (column == null) return; if (column == null) return;
column.widgets = column.widgets.filter(w => w.id != x.widget.id); column.widgets = column.widgets.filter(w => w.id != x.widget.id);
},
renameDeckColumn(state, x) {
const column = state.deck.columns.find(c => c.id == x.id);
if (column == null) return;
column.name = x.name;
} }
}, },
@ -281,6 +287,11 @@ export default (os: MiOS) => new Vuex.Store({
ctx.dispatch('saveDeck'); ctx.dispatch('saveDeck');
}, },
renameDeckColumn(ctx, x) {
ctx.commit('renameDeckColumn', x);
ctx.dispatch('saveDeck');
},
addHomeWidget(ctx, widget) { addHomeWidget(ctx, widget) {
ctx.commit('addHomeWidget', widget); ctx.commit('addHomeWidget', widget);

View File

@ -35,6 +35,10 @@ module.exports = async (params, user) => {
throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
} }
// Get 'mediaOnly' parameter
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
if (mediaOnlyErr) throw 'invalid mediaOnly param';
// ミュートしているユーザーを取得 // ミュートしているユーザーを取得
const mutedUserIds = user ? (await Mute.find({ const mutedUserIds = user ? (await Mute.find({
muterId: user._id muterId: user._id
@ -64,6 +68,10 @@ module.exports = async (params, user) => {
}; };
} }
if (mediaOnly) {
query.mediaIds = { $exists: true, $ne: [] };
}
if (sinceId) { if (sinceId) {
sort._id = 1; sort._id = 1;
query._id = { query._id = {

View File

@ -35,6 +35,10 @@ module.exports = async (params, user) => {
throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified'; throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
} }
// Get 'mediaOnly' parameter
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
if (mediaOnlyErr) throw 'invalid mediaOnly param';
// ミュートしているユーザーを取得 // ミュートしているユーザーを取得
const mutedUserIds = user ? (await Mute.find({ const mutedUserIds = user ? (await Mute.find({
muterId: user._id muterId: user._id
@ -67,6 +71,10 @@ module.exports = async (params, user) => {
}; };
} }
if (mediaOnly) {
query.mediaIds = { $exists: true, $ne: [] };
}
if (sinceId) { if (sinceId) {
sort._id = 1; sort._id = 1;
query._id = { query._id = {

View File

@ -44,6 +44,10 @@ module.exports = async (params, user, app) => {
const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes); const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param'; if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
// Get 'mediaOnly' parameter
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
if (mediaOnlyErr) throw 'invalid mediaOnly param';
const [followings, mutedUserIds] = await Promise.all([ const [followings, mutedUserIds] = await Promise.all([
// フォローを取得 // フォローを取得
// Fetch following // Fetch following
@ -137,6 +141,12 @@ module.exports = async (params, user, app) => {
}); });
} }
if (mediaOnly) {
query.$and.push({
mediaIds: { $exists: true, $ne: [] }
});
}
if (sinceId) { if (sinceId) {
sort._id = 1; sort._id = 1;
query._id = { query._id = {

View File

@ -44,6 +44,10 @@ module.exports = async (params, user, app) => {
const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes); const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param'; if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
// Get 'mediaOnly' parameter
const [mediaOnly, mediaOnlyErr] = $.bool.optional().get(params.mediaOnly);
if (mediaOnlyErr) throw 'invalid mediaOnly param';
// Get 'listId' parameter // Get 'listId' parameter
const [listId, listIdErr] = $.type(ID).get(params.listId); const [listId, listIdErr] = $.type(ID).get(params.listId);
if (listIdErr) throw 'invalid listId param'; if (listIdErr) throw 'invalid listId param';
@ -146,6 +150,12 @@ module.exports = async (params, user, app) => {
}); });
} }
if (mediaOnly) {
query.$and.push({
mediaIds: { $exists: true, $ne: [] }
});
}
if (sinceId) { if (sinceId) {
sort._id = 1; sort._id = 1;
query._id = { query._id = {