From a2ed259501f58008af4c61321549c83b9b5358e7 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 24 Feb 2018 07:49:03 +0900
Subject: [PATCH] :v:

---
 src/api/endpoints/i/update_home.ts            |  9 ++++++
 src/api/endpoints/i/update_mobile_home.ts     |  9 ++++++
 src/web/app/common/define-widget.ts           | 24 ++++++++++++---
 src/web/app/desktop/views/components/home.vue | 30 ++++++++++++++++++-
 src/web/app/desktop/views/components/index.ts |  2 ++
 src/web/app/mobile/views/pages/home.vue       | 18 ++++++++++-
 6 files changed, 86 insertions(+), 6 deletions(-)

diff --git a/src/api/endpoints/i/update_home.ts b/src/api/endpoints/i/update_home.ts
index 5dfb7d791..394686cbd 100644
--- a/src/api/endpoints/i/update_home.ts
+++ b/src/api/endpoints/i/update_home.ts
@@ -3,6 +3,7 @@
  */
 import $ from 'cafy';
 import User from '../../models/user';
+import event from '../../event';
 
 module.exports = async (params, user) => new Promise(async (res, rej) => {
 	// Get 'home' parameter
@@ -30,6 +31,10 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
 		});
 
 		res();
+
+		event(user._id, 'home_updated', {
+			home
+		});
 	} else {
 		if (id == null && data == null) return rej('you need to set id and data params if home param unset');
 
@@ -47,5 +52,9 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
 		});
 
 		res();
+
+		event(user._id, 'home_updated', {
+			id, data
+		});
 	}
 });
diff --git a/src/api/endpoints/i/update_mobile_home.ts b/src/api/endpoints/i/update_mobile_home.ts
index a87d89cad..70181431a 100644
--- a/src/api/endpoints/i/update_mobile_home.ts
+++ b/src/api/endpoints/i/update_mobile_home.ts
@@ -3,6 +3,7 @@
  */
 import $ from 'cafy';
 import User from '../../models/user';
+import event from '../../event';
 
 module.exports = async (params, user) => new Promise(async (res, rej) => {
 	// Get 'home' parameter
@@ -29,6 +30,10 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
 		});
 
 		res();
+
+		event(user._id, 'mobile_home_updated', {
+			home
+		});
 	} else {
 		if (id == null && data == null) return rej('you need to set id and data params if home param unset');
 
@@ -46,5 +51,9 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
 		});
 
 		res();
+
+		event(user._id, 'mobile_home_updated', {
+			id, data
+		});
 	}
 });
diff --git a/src/web/app/common/define-widget.ts b/src/web/app/common/define-widget.ts
index 21821629a..844603daa 100644
--- a/src/web/app/common/define-widget.ts
+++ b/src/web/app/common/define-widget.ts
@@ -21,7 +21,9 @@ export default function<T extends object>(data: {
 		},
 		data() {
 			return {
-				props: data.props ? data.props() : {} as T
+				props: data.props ? data.props() : {} as T,
+				bakedOldProps: null,
+				preventSave: false
 			};
 		},
 		created() {
@@ -33,26 +35,40 @@ export default function<T extends object>(data: {
 				});
 			}
 
+			this.bakeProps();
+
 			this.$watch('props', newProps => {
-				const w = (this as any).os.i.client_settings.mobile_home.find(w => w.id == this.id);
+				if (this.preventSave) {
+					this.preventSave = false;
+					return;
+				}
+				if (this.bakedOldProps == JSON.stringify(newProps)) return;
+
+				this.bakeProps();
+
 				if (this.isMobile) {
 					(this as any).api('i/update_mobile_home', {
 						id: this.id,
 						data: newProps
 					}).then(() => {
-						w.data = newProps;
+						(this as any).os.i.client_settings.mobile_home.find(w => w.id == this.id).data = newProps;
 					});
 				} else {
 					(this as any).api('i/update_home', {
 						id: this.id,
 						data: newProps
 					}).then(() => {
-						w.data = newProps;
+						(this as any).os.i.client_settings.home.find(w => w.id == this.id).data = newProps;
 					});
 				}
 			}, {
 				deep: true
 			});
+		},
+		methods: {
+			bakeProps() {
+				this.bakedOldProps = JSON.stringify(this.props);
+			}
 		}
 	});
 }
diff --git a/src/web/app/desktop/views/components/home.vue b/src/web/app/desktop/views/components/home.vue
index 8a61c378e..d64d83698 100644
--- a/src/web/app/desktop/views/components/home.vue
+++ b/src/web/app/desktop/views/components/home.vue
@@ -60,7 +60,7 @@
 		</template>
 		<template v-else>
 			<div v-for="place in ['left', 'right']" :class="place">
-				<component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :widget="widget" @chosen="warp"/>
+				<component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" @chosen="warp"/>
 			</div>
 			<div class="main">
 				<mk-post-form v-if="os.i.client_settings.showPostFormOnTopOfTl"/>
@@ -90,6 +90,8 @@ export default Vue.extend({
 	},
 	data() {
 		return {
+			connection: null,
+			connectionId: null,
 			widgetAdderSelected: null,
 			trash: [],
 			widgets: {
@@ -131,6 +133,16 @@ export default Vue.extend({
 			deep: true
 		});
 	},
+	mounted() {
+		this.connection = (this as any).os.stream.getConnection();
+		this.connectionId = (this as any).os.stream.use();
+
+		this.connection.on('home_updated', this.onHomeUpdated);
+	},
+	beforeDestroy() {
+		this.connection.off('home_updated', this.onHomeUpdated);
+		(this as any).os.stream.dispose(this.connectionId);
+	},
 	methods: {
 		hint() {
 			(this as any).apis.dialog({
@@ -147,6 +159,22 @@ export default Vue.extend({
 		onTlLoaded() {
 			this.$emit('loaded');
 		},
+		onHomeUpdated(data) {
+			if (data.home) {
+				(this as any).os.i.client_settings.home = data.home;
+				this.widgets.left = data.home.filter(w => w.place == 'left');
+				this.widgets.right = data.home.filter(w => w.place == 'right');
+			} else {
+				const w = (this as any).os.i.client_settings.home.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.left = (this as any).os.i.client_settings.home.filter(w => w.place == 'left');
+					this.widgets.right = (this as any).os.i.client_settings.home.filter(w => w.place == 'right');
+				}
+			}
+		},
 		onWidgetContextmenu(widgetId) {
 			const w = (this.$refs[widgetId] as any)[0];
 			if (w.func) w.func();
diff --git a/src/web/app/desktop/views/components/index.ts b/src/web/app/desktop/views/components/index.ts
index 7584cb498..5cb09e031 100644
--- a/src/web/app/desktop/views/components/index.ts
+++ b/src/web/app/desktop/views/components/index.ts
@@ -39,6 +39,7 @@ import wPolls from './widgets/polls.vue';
 import wPostForm from './widgets/post-form.vue';
 import wMessaging from './widgets/messaging.vue';
 import wChannel from './widgets/channel.vue';
+import wProfile from './widgets/profile.vue';
 //#endregion
 
 Vue.component('mk-ui', ui);
@@ -80,4 +81,5 @@ Vue.component('mkw-polls', wPolls);
 Vue.component('mkw-post-form', wPostForm);
 Vue.component('mkw-messaging', wMessaging);
 Vue.component('mkw-channel', wChannel);
+Vue.component('mkw-profile', wProfile);
 //#endregion
diff --git a/src/web/app/mobile/views/pages/home.vue b/src/web/app/mobile/views/pages/home.vue
index 5e80bbceb..f4f458068 100644
--- a/src/web/app/mobile/views/pages/home.vue
+++ b/src/web/app/mobile/views/pages/home.vue
@@ -51,7 +51,7 @@
 				</x-draggable>
 			</template>
 			<template v-else>
-				<component class="widget" v-for="widget in widgets" :is="`mkw-${widget.name}`" :key="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" @chosen="warp"/>
 			</template>
 		</div>
 	</main>
@@ -124,12 +124,14 @@ export default Vue.extend({
 		this.connectionId = (this as any).os.stream.use();
 
 		this.connection.on('post', this.onStreamPost);
+		this.connection.on('mobile_home_updated', this.onHomeUpdated);
 		document.addEventListener('visibilitychange', this.onVisibilitychange, false);
 
 		Progress.start();
 	},
 	beforeDestroy() {
 		this.connection.off('post', this.onStreamPost);
+		this.connection.off('mobile_home_updated', this.onHomeUpdated);
 		(this as any).os.stream.dispose(this.connectionId);
 		document.removeEventListener('visibilitychange', this.onVisibilitychange);
 	},
@@ -152,6 +154,20 @@ export default Vue.extend({
 				document.title = 'Misskey';
 			}
 		},
+		onHomeUpdated(data) {
+			if (data.home) {
+				(this as any).os.i.client_settings.mobile_home = data.home;
+				this.widgets = data.home;
+			} else {
+				const w = (this as any).os.i.client_settings.mobile_home.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).os.i.client_settings.mobile_home;
+				}
+			}
+		},
 		hint() {
 			alert('ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。');
 		},