summaryrefslogtreecommitdiff
path: root/src/client/app/mobile
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/app/mobile')
-rw-r--r--src/client/app/mobile/api/post.ts49
-rw-r--r--src/client/app/mobile/script.ts2
-rw-r--r--src/client/app/mobile/views/components/drive.file-detail.vue2
-rw-r--r--src/client/app/mobile/views/components/drive.file.vue2
-rw-r--r--src/client/app/mobile/views/components/media-image.vue2
-rw-r--r--src/client/app/mobile/views/components/note-preview.vue3
-rw-r--r--src/client/app/mobile/views/components/note.vue16
-rw-r--r--src/client/app/mobile/views/components/notes.vue19
-rw-r--r--src/client/app/mobile/views/components/post-form.vue12
-rw-r--r--src/client/app/mobile/views/components/ui.header.vue5
-rw-r--r--src/client/app/mobile/views/components/ui.nav.vue1
-rw-r--r--src/client/app/mobile/views/components/widget-container.vue22
-rw-r--r--src/client/app/mobile/views/pages/user.vue2
-rw-r--r--src/client/app/mobile/views/pages/widgets.vue (renamed from src/client/app/mobile/views/pages/dashboard.vue)69
14 files changed, 108 insertions, 98 deletions
diff --git a/src/client/app/mobile/api/post.ts b/src/client/app/mobile/api/post.ts
index 72919c6505..0634c52642 100644
--- a/src/client/app/mobile/api/post.ts
+++ b/src/client/app/mobile/api/post.ts
@@ -1,43 +1,24 @@
import PostForm from '../views/components/post-form.vue';
-//import RenoteForm from '../views/components/renote-form.vue';
-import getNoteSummary from '../../../../renderers/get-note-summary';
export default (os) => (opts) => {
const o = opts || {};
- if (o.renote) {
- /*const vm = new RenoteForm({
- propsData: {
- renote: o.renote
- }
- }).$mount();
- vm.$once('cancel', recover);
- vm.$once('note', recover);
- document.body.appendChild(vm.$el);*/
+ const app = document.getElementById('app');
+ app.style.display = 'none';
- const text = window.prompt(`「${getNoteSummary(o.renote)}」をRenote`);
- if (text == null) return;
- os.api('notes/create', {
- renoteId: o.renote.id,
- text: text == '' ? undefined : text
- });
- } else {
- const app = document.getElementById('app');
- app.style.display = 'none';
+ function recover() {
+ app.style.display = 'block';
+ }
- function recover() {
- app.style.display = 'block';
+ const vm = new PostForm({
+ parent: os.app,
+ propsData: {
+ reply: o.reply,
+ renote: o.renote
}
-
- const vm = new PostForm({
- parent: os.app,
- propsData: {
- reply: o.reply
- }
- }).$mount();
- vm.$once('cancel', recover);
- vm.$once('note', recover);
- document.body.appendChild(vm.$el);
- (vm as any).focus();
- }
+ }).$mount();
+ vm.$once('cancel', recover);
+ vm.$once('note', recover);
+ document.body.appendChild(vm.$el);
+ (vm as any).focus();
};
diff --git a/src/client/app/mobile/script.ts b/src/client/app/mobile/script.ts
index 2e9805e0d0..1405139be6 100644
--- a/src/client/app/mobile/script.ts
+++ b/src/client/app/mobile/script.ts
@@ -23,6 +23,7 @@ import MkUser from './views/pages/user.vue';
import MkSelectDrive from './views/pages/selectdrive.vue';
import MkDrive from './views/pages/drive.vue';
import MkNotifications from './views/pages/notifications.vue';
+import MkWidgets from './views/pages/widgets.vue';
import MkMessaging from './views/pages/messaging.vue';
import MkMessagingRoom from './views/pages/messaging-room.vue';
import MkNote from './views/pages/note.vue';
@@ -56,6 +57,7 @@ init((launch) => {
{ path: '/i/settings', component: MkSettings },
{ path: '/i/settings/profile', component: MkProfileSetting },
{ path: '/i/notifications', name: 'notifications', component: MkNotifications },
+ { path: '/i/widgets', name: 'widgets', component: MkWidgets },
{ path: '/i/messaging', name: 'messaging', component: MkMessaging },
{ path: '/i/messaging/:user', component: MkMessagingRoom },
{ path: '/i/drive', name: 'drive', component: MkDrive },
diff --git a/src/client/app/mobile/views/components/drive.file-detail.vue b/src/client/app/mobile/views/components/drive.file-detail.vue
index 764822e98c..ddf17d2723 100644
--- a/src/client/app/mobile/views/components/drive.file-detail.vue
+++ b/src/client/app/mobile/views/components/drive.file-detail.vue
@@ -86,7 +86,7 @@ export default Vue.extend({
return this.file.type.split('/')[0];
},
style(): any {
- return this.file.properties.avgColor ? {
+ return this.file.properties.avgColor && this.file.properties.avgColor.length == 3 ? {
'background-color': `rgb(${ this.file.properties.avgColor.join(',') })`
} : {};
}
diff --git a/src/client/app/mobile/views/components/drive.file.vue b/src/client/app/mobile/views/components/drive.file.vue
index 7d1957042b..94c8ae3535 100644
--- a/src/client/app/mobile/views/components/drive.file.vue
+++ b/src/client/app/mobile/views/components/drive.file.vue
@@ -42,7 +42,7 @@ export default Vue.extend({
},
thumbnail(): any {
return {
- 'background-color': this.file.properties.avgColor ? `rgb(${this.file.properties.avgColor.join(',')})` : 'transparent',
+ 'background-color': this.file.properties.avgColor && this.file.properties.avgColor.length == 3 ? `rgb(${this.file.properties.avgColor.join(',')})` : 'transparent',
'background-image': `url(${this.file.url}?thumbnail&size=128)`
};
}
diff --git a/src/client/app/mobile/views/components/media-image.vue b/src/client/app/mobile/views/components/media-image.vue
index 92d1cdc6f5..9e0f8e5f7e 100644
--- a/src/client/app/mobile/views/components/media-image.vue
+++ b/src/client/app/mobile/views/components/media-image.vue
@@ -18,7 +18,7 @@ export default Vue.extend({
computed: {
style(): any {
return {
- 'background-color': this.image.properties.avgColor ? `rgb(${this.image.properties.avgColor.join(',')})` : 'transparent',
+ 'background-color': this.image.properties.avgColor && this.image.properties.avgColor.length == 3 ? `rgb(${this.image.properties.avgColor.join(',')})` : 'transparent',
'background-image': this.raw ? `url(${this.image.url})` : `url(${this.image.url}?thumbnail&size=512)`
};
}
diff --git a/src/client/app/mobile/views/components/note-preview.vue b/src/client/app/mobile/views/components/note-preview.vue
index ec11f23315..b3ab088ffe 100644
--- a/src/client/app/mobile/views/components/note-preview.vue
+++ b/src/client/app/mobile/views/components/note-preview.vue
@@ -69,8 +69,9 @@ root(isDark)
text-decoration underline
> .username
- text-align left
margin 0 .5em 0 0
+ overflow hidden
+ text-overflow ellipsis
color isDark ? #606984 : #d1d8da
> .time
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index d66f5a1016..77a766f327 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -41,7 +41,7 @@
<div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
<a class="reply" v-if="p.reply">%fa:reply%</a>
- <mk-note-html v-if="p.text" :text="p.text" :i="os.i" :class="$style.text"/>
+ <mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="os.i" :class="$style.text"/>
<a class="rp" v-if="p.renote != null">RP:</a>
</div>
<div class="media" v-if="p.media.length > 0">
@@ -85,6 +85,7 @@
<script lang="ts">
import Vue from 'vue';
import parse from '../../../../../text/parse';
+import canHideText from '../../../common/scripts/can-hide-text';
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
@@ -112,9 +113,11 @@ export default Vue.extend({
this.note.mediaIds.length == 0 &&
this.note.poll == null);
},
+
p(): any {
return this.isRenote ? this.note.renote : this.note;
},
+
reactionsCount(): number {
return this.p.reactionCounts
? Object.keys(this.p.reactionCounts)
@@ -122,6 +125,7 @@ export default Vue.extend({
.reduce((a, b) => a + b)
: 0;
},
+
urls(): string[] {
if (this.p.text) {
const ast = parse(this.p.text);
@@ -177,6 +181,8 @@ export default Vue.extend({
},
methods: {
+ canHideText,
+
capture(withHandler = false) {
if ((this as any).os.isSignedIn) {
this.connection.send({
@@ -186,6 +192,7 @@ export default Vue.extend({
if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
}
},
+
decapture(withHandler = false) {
if ((this as any).os.isSignedIn) {
this.connection.send({
@@ -195,9 +202,11 @@ export default Vue.extend({
if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
}
},
+
onStreamConnected() {
this.capture();
},
+
onStreamNoteUpdated(data) {
const note = data.note;
if (note.id == this.note.id) {
@@ -206,16 +215,19 @@ export default Vue.extend({
this.note.renote = note;
}
},
+
reply() {
(this as any).apis.post({
reply: this.p
});
},
+
renote() {
(this as any).apis.post({
renote: this.p
});
},
+
react() {
(this as any).os.new(MkReactionPicker, {
source: this.$refs.reactButton,
@@ -223,6 +235,7 @@ export default Vue.extend({
compact: true
});
},
+
menu() {
(this as any).os.new(MkNoteMenu, {
source: this.$refs.menuButton,
@@ -255,6 +268,7 @@ root(isDark)
align-items center
padding 8px 16px
line-height 28px
+ white-space pre
color #9dbb00
background isDark ? linear-gradient(to bottom, #314027 0%, #282c37 100%) : linear-gradient(to bottom, #edfde2 0%, #fff 100%)
diff --git a/src/client/app/mobile/views/components/notes.vue b/src/client/app/mobile/views/components/notes.vue
index 53e232e521..e77698dea9 100644
--- a/src/client/app/mobile/views/components/notes.vue
+++ b/src/client/app/mobile/views/components/notes.vue
@@ -1,7 +1,5 @@
<template>
<div class="mk-notes">
- <div class="newer-indicator" :style="{ top: $store.state.uiHeaderHeight + 'px' }" v-show="queue.length > 0"></div>
-
<slot name="head"></slot>
<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>
@@ -71,6 +69,16 @@ export default Vue.extend({
}
},
+ watch: {
+ queue(x) {
+ if (x.length > 0) {
+ this.$store.commit('indicate', true);
+ } else {
+ this.$store.commit('indicate', false);
+ }
+ }
+ },
+
mounted() {
document.addEventListener('visibilitychange', this.onVisibilitychange, false);
window.addEventListener('scroll', this.onScroll);
@@ -238,13 +246,6 @@ root(isDark)
[data-fa]
margin-right 8px
- > .newer-indicator
- position -webkit-sticky
- position sticky
- z-index 100
- height 3px
- background $theme-color
-
> .init
padding 64px 0
text-align center
diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue
index 6d80b3046b..0bb498e5d7 100644
--- a/src/client/app/mobile/views/components/post-form.vue
+++ b/src/client/app/mobile/views/components/post-form.vue
@@ -5,17 +5,22 @@
<div>
<span class="text-count" :class="{ over: text.length > 1000 }">{{ 1000 - text.length }}</span>
<span class="geo" v-if="geo">%fa:map-marker-alt%</span>
- <button class="submit" :disabled="posting" @click="post">{{ reply ? '返信' : '%i18n:!@submit%' }}</button>
+ <button class="submit" :disabled="posting" @click="post">
+ <template v-if="reply">%i18n:@reply%</template>
+ <template v-else-if="renote">%i18n:@renote%</template>
+ <template v-else>%i18n:@submit%</template>
+ </button>
</div>
</header>
<div class="form">
<mk-note-preview v-if="reply" :note="reply"/>
+ <mk-note-preview v-if="renote" :note="renote"/>
<div v-if="visibility == 'specified'" class="visibleUsers">
<span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span>
<a @click="addVisibleUser">+ユーザーを追加</a>
</div>
<input v-show="useCw" v-model="cw" placeholder="内容への注釈 (オプション)">
- <textarea v-model="text" ref="text" :disabled="posting" :placeholder="reply ? '%i18n:!@reply-placeholder%' : '%i18n:!@note-placeholder%'"></textarea>
+ <textarea v-model="text" ref="text" :disabled="posting" :placeholder="reply ? '%i18n:!@reply-placeholder%' : renote ? '%i18n:!@renote-placeholder%' : '%i18n:!@note-placeholder%'"></textarea>
<div class="attaches" v-show="files.length != 0">
<x-draggable class="files" :list="files" :options="{ animation: 150 }">
<div class="file" v-for="file in files" :key="file.id">
@@ -51,7 +56,7 @@ export default Vue.extend({
MkVisibilityChooser
},
- props: ['reply'],
+ props: ['reply', 'renote'],
data() {
return {
@@ -177,6 +182,7 @@ export default Vue.extend({
text: this.text == '' ? undefined : this.text,
mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
replyId: this.reply ? this.reply.id : undefined,
+ renoteId: this.renote ? this.renote.id : undefined,
poll: this.poll ? (this.$refs.poll as any).get() : undefined,
cw: this.useCw ? this.cw || '' : undefined,
geo: this.geo ? {
diff --git a/src/client/app/mobile/views/components/ui.header.vue b/src/client/app/mobile/views/components/ui.header.vue
index 509463333d..a49462b159 100644
--- a/src/client/app/mobile/views/components/ui.header.vue
+++ b/src/client/app/mobile/views/components/ui.header.vue
@@ -13,6 +13,7 @@
<slot name="func"></slot>
</div>
</div>
+ <div class="indicator" v-show="$store.state.indicate"></div>
</div>
</template>
@@ -156,6 +157,10 @@ root(isDark)
&, *
user-select none
+ > .indicator
+ height 3px
+ background $theme-color
+
> .main
color rgba(#fff, 0.9)
diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue
index 5c65d52237..ec42dbc99d 100644
--- a/src/client/app/mobile/views/components/ui.nav.vue
+++ b/src/client/app/mobile/views/components/ui.nav.vue
@@ -21,6 +21,7 @@
<li><router-link to="/othello" :data-active="$route.name == 'othello'">%fa:gamepad%ゲーム<template v-if="hasGameInvitations">%fa:circle%</template>%fa:angle-right%</router-link></li>
</ul>
<ul>
+ <li><router-link to="/i/widgets" :data-active="$route.name == 'widgets'">%fa:quidditch%%i18n:@widgets%%fa:angle-right%</router-link></li>
<li><router-link to="/i/drive" :data-active="$route.name == 'drive'">%fa:cloud%%i18n:@drive%%fa:angle-right%</router-link></li>
</ul>
<ul>
diff --git a/src/client/app/mobile/views/components/widget-container.vue b/src/client/app/mobile/views/components/widget-container.vue
index 1bdc875763..a713a10621 100644
--- a/src/client/app/mobile/views/components/widget-container.vue
+++ b/src/client/app/mobile/views/components/widget-container.vue
@@ -25,27 +25,27 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
-.mk-widget-container
- background #eee
+root(isDark)
+ background isDark ? #21242f : #eee
border-radius 8px
- box-shadow 0 0 0 1px rgba(#000, 0.2)
+ box-shadow 0 4px 16px rgba(#000, 0.1)
overflow hidden
- &.hideHeader
- background #fff
-
&.naked
background transparent !important
box-shadow none !important
+ &.hideHeader
+ background isDark ? #21242f : #fff
+
> header
> .title
margin 0
padding 8px 10px
font-size 15px
font-weight normal
- color #465258
- background #fff
+ color isDark ? #b8c5cc : #465258
+ background isDark ? #282c37 : #fff
border-radius 8px 8px 0 0
> [data-fa]
@@ -65,4 +65,10 @@ export default Vue.extend({
font-size 15px
color #465258
+.mk-widget-container[data-darkmode]
+ root(true)
+
+.mk-widget-container:not([data-darkmode])
+ root(false)
+
</style>
diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue
index 27482dc215..f43454f9db 100644
--- a/src/client/app/mobile/views/pages/user.vue
+++ b/src/client/app/mobile/views/pages/user.vue
@@ -84,7 +84,7 @@ export default Vue.extend({
style(): any {
if (this.user.bannerUrl == null) return {};
return {
- backgroundColor: this.user.bannerColor ? `rgb(${ this.user.bannerColor.join(',') })` : null,
+ backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
backgroundImage: `url(${ this.user.bannerUrl })`
};
}
diff --git a/src/client/app/mobile/views/pages/dashboard.vue b/src/client/app/mobile/views/pages/widgets.vue
index a5ca6cb4a2..509ce16eef 100644
--- a/src/client/app/mobile/views/pages/dashboard.vue
+++ b/src/client/app/mobile/views/pages/widgets.vue
@@ -40,7 +40,7 @@
</x-draggable>
</template>
<template v-else>
- <component class="widget" v-for="widget in widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" :is-mobile="true" @chosen="warp"/>
+ <component class="widget" v-for="widget in widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" :is-mobile="true"/>
</template>
</main>
</mk-ui>
@@ -55,17 +55,24 @@ export default Vue.extend({
components: {
XDraggable
},
+
data() {
return {
showNav: false,
- widgets: [],
customizing: false,
widgetAdderSelected: null
};
},
+
+ computed: {
+ widgets(): any[] {
+ return this.$store.state.settings.data.mobileHome;
+ }
+ },
+
created() {
- if ((this as any).clientSettings.mobileHome == null) {
- Vue.set((this as any).clientSettings, 'mobileHome', [{
+ if (this.widgets.length == 0) {
+ this.widgets = [{
name: 'calendar',
id: 'a', data: {}
}, {
@@ -86,18 +93,9 @@ export default Vue.extend({
}, {
name: 'version',
id: 'g', data: {}
- }]);
- this.widgets = (this as any).clientSettings.mobileHome;
+ }];
this.saveHome();
- } else {
- this.widgets = (this as any).clientSettings.mobileHome;
}
-
- this.$watch('clientSettings', i => {
- this.widgets = (this as any).clientSettings.mobileHome;
- }, {
- deep: true
- });
},
mounted() {
@@ -105,46 +103,33 @@ export default Vue.extend({
},
methods: {
- onHomeUpdated(data) {
- if (data.home) {
- (this as any).clientSettings.mobileHome = data.home;
- this.widgets = data.home;
- } else {
- const w = (this as any).clientSettings.mobileHome.find(w => w.id == data.id);
- if (w != null) {
- w.data = data.data;
- this.$refs[w.id][0].preventSave = true;
- this.$refs[w.id][0].props = w.data;
- this.widgets = (this as any).clientSettings.mobileHome;
- }
- }
- },
hint() {
alert('ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。');
},
+
widgetFunc(id) {
const w = this.$refs[id][0];
if (w.func) w.func();
},
+
onWidgetSort() {
this.saveHome();
},
+
addWidget() {
- const widget = {
+ this.$store.dispatch('settings/addMobileHomeWidget', {
name: this.widgetAdderSelected,
id: uuid(),
data: {}
- };
-
- this.widgets.unshift(widget);
- this.saveHome();
+ });
},
+
removeWidget(widget) {
- this.widgets = this.widgets.filter(w => w.id != widget.id);
- this.saveHome();
+ this.$store.dispatch('settings/removeMobileHomeWidget', widget);
},
+
saveHome() {
- (this as any).clientSettings.mobileHome = this.widgets;
+ this.$store.commit('settings/setMobileHome', this.widgets);
(this as any).api('i/update_mobile_home', {
home: this.widgets
});
@@ -156,17 +141,25 @@ export default Vue.extend({
<style lang="stylus" scoped>
main
margin 0 auto
+ padding 8px
max-width 500px
+ width 100%
@media (min-width 500px)
- padding 8px
+ padding 16px 8px
+
+ @media (min-width 600px)
+ padding 32px 8px
> header
padding 8px
background #fff
.widget
- margin 8px
+ margin-bottom 8px
+
+ @media (min-width 600px)
+ margin-bottom 16px
.customize-container
margin 8px