diff --git a/Telegram/PrepareWin.bat b/Telegram/PrepareWin.bat
index b5f8e3fd9..5a6375333 100644
--- a/Telegram/PrepareWin.bat
+++ b/Telegram/PrepareWin.bat
@@ -1,8 +1,8 @@
 @echo OFF
 
-set "AppVersionStrSmall=0.6.17"
-set "AppVersionStr=0.6.17"
-set "AppVersionStrFull=0.6.17.0"
+set "AppVersionStrSmall=0.6.18"
+set "AppVersionStr=0.6.18"
+set "AppVersionStrFull=0.6.18.0"
 
 echo.
 echo Preparing version %AppVersionStr%..
diff --git a/Telegram/Resources/lang.txt b/Telegram/Resources/lang.txt
index 98ef8cd9f..39027f7b8 100644
--- a/Telegram/Resources/lang.txt
+++ b/Telegram/Resources/lang.txt
@@ -24,6 +24,8 @@ lng_menu_settings: "Settings";
 lng_menu_about: "About";
 lng_menu_update: "Update";
 lng_menu_restart: "Restart";
+lng_menu_start_messaging: "Start Messaging";
+lng_menu_conversations: "Conversations List";
 
 lng_open_from_tray: "Open Telegram";
 lng_minimize_to_tray: "Minimize to tray";
@@ -55,6 +57,14 @@ lng_weekday5: "Fri";
 lng_weekday6: "Sat";
 lng_weekday7: "Sun";
 
+lng_weekday1_full: "Monday";
+lng_weekday2_full: "Tuesday";
+lng_weekday3_full: "Wednesday";
+lng_weekday4_full: "Thursday";
+lng_weekday5_full: "Friday";
+lng_weekday6_full: "Saturday";
+lng_weekday7_full: "Sunday";
+
 lng_month_day: "{month} {day}";
 
 lng_cancel: "Cancel";
@@ -252,8 +262,8 @@ lng_connection_port_ph: "Port";
 lng_connection_user_ph: "Username";
 lng_connection_password_ph: "Password";
 lng_connection_save: "Save";
-lng_settings_reset: "Reset other sessions";
-lng_settings_reset_done: "Sessions reset done";
+lng_settings_reset: "Terminate other sessions";
+lng_settings_reset_done: "Other sessions terminated";
 lng_settings_logout: "Log Out";
 lng_sure_logout: "Are you sure you want to log out?";
 
@@ -485,6 +495,17 @@ lng_mediaview_doc_image: "Document";
 
 lng_mediaview_saved: "Image was saved to your [c]Downloads[/c] folder";
 
+lng_new_authorization: "{name},
+We detected a login into your account from a new device on {day}, {date} at {time}
+
+Device: {device}
+Location: {location}
+
+If this wasn't you, you can go to Settings — Terminate other sessions.
+
+Thanks,
+The Telegram Team";
+
 // Mac specific
 
 lng_mac_choose_app: "Choose Application";
diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt
index 4fbb25bcb..0b0ab8a7c 100644
--- a/Telegram/Resources/style.txt
+++ b/Telegram/Resources/style.txt
@@ -46,7 +46,8 @@ color6: #cd4073; // pink
 color7: #2996ad; // sea
 color8: #ce671b; // orange
 
-wndMinWidth: 640px;
+wndMinWidth: 380px;
+wideModeWidth: 640px;
 wndMinHeight: 480px;
 wndDefWidth: 800px;
 wndDefHeight: 600px;
@@ -78,6 +79,22 @@ titleTypingColor: #0080c0;
 statusFont: font(fsize);
 versionColor: #777;
 
+btnDefIconed: iconedButton {
+	color: white;
+	bgColor: white;
+	overBgColor: white;
+	font: font(fsize);
+
+	opacity: 0.78;
+	overOpacity: 1;
+
+	textPos: point(0px, 0px);
+	downTextPos: point(0px, 0px);
+
+	duration: 150;
+	cursor: cursor(pointer);
+}
+
 sysBtnDelta: 6px;
 sysUpd: sysButton {
 	size: size(31px, 39px);
@@ -99,6 +116,24 @@ sysRes: sysButton(sysUpd) {
 sysCls: sysButton(sysUpd) {
 	img: sprite(276px, 1px, 19px, 19px);
 }
+titleBackButton: iconedButton(btnDefIconed) {
+	icon: sprite(133px, 197px, 13px, 20px);
+	iconPos: point(5px, 9px);
+	downIcon: sprite(133px, 197px, 13px, 20px);
+	downIconPos: point(5px, 10px);
+
+	bgColor: #c4d8e9;
+	overBgColor: #fff;
+
+	width: -30px;
+	height: 39px;
+
+	opacity: 1;
+	cursor: cursor(default);
+
+	textPos: point(23px, 10px);
+	downTextPos: point(23px, 11px);
+}
 
 btnWhiteHover: #f5f5f5;
 btnBoxWhiteHover: #fafafa;
@@ -107,22 +142,6 @@ btnYesHover: #0073ad;
 btnNoColor: #8b8b8b;
 btnNoHover: #777;
 
-btnDefIconed: iconedButton {
-	color: white;
-	bgColor: white;
-	overBgColor: white;
-	font: font(fsize);
-
-	opacity: 0.78;
-	overOpacity: 1;
-
-	textPos: point(0px, 0px);
-	downTextPos: point(0px, 0px);
-
-	duration: 150;
-	cursor: cursor(pointer);
-}
-
 titleTextButton: flatButton {
 	color: #d4e3ef;
 	overColor: #fff;
@@ -138,8 +157,8 @@ titleTextButton: flatButton {
 	overTextTop: 10px;
 	downTextTop: 11px;
 
-	font: font(13px);
-	overFont: font(13px);
+	font: font(fsize);
+	overFont: font(fsize);
 	duration: 150;
 	cursor: cursor(default);
 }
@@ -175,6 +194,7 @@ btnDefBack: flatButton(btnDefFlat) {
 	downBgColor: #b9b9b9;
 }
 
+linkCropLimit: 360px;
 linkFont: font(fsize);
 linkOverFont: font(fsize underline);
 btnDefLink: linkButton {
diff --git a/Telegram/SourceFiles/_other/genlang.cpp b/Telegram/SourceFiles/_other/genlang.cpp
index 5a2d90157..4ce1f925f 100644
--- a/Telegram/SourceFiles/_other/genlang.cpp
+++ b/Telegram/SourceFiles/_other/genlang.cpp
@@ -251,6 +251,10 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org\n\
 			th << "\tint32 day = date.dayOfWeek();\n";
 			th << "\treturn (day > 0 && day <= 7) ? lang(LangKey(lng_weekday1 + day - 1)) : qsl(\"{err}\");\n";
 			th << "}\n\n";
+			th << "inline QString langDayOfWeekFull(const QDate &date) {\n";
+			th << "\tint32 day = date.dayOfWeek();\n";
+			th << "\treturn (day > 0 && day <= 7) ? lang(LangKey(lng_weekday1_full + day - 1)) : qsl(\"{err}\");\n";
+			th << "}\n\n";
 			th << "Qt::LayoutDirection langDir();\n\n";
 			th << "class LangLoader {\n";
 			th << "public:\n";
diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index 4ed2c6b16..aacdbd56a 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -677,13 +677,13 @@ namespace App {
 			if (user->contact > 0) {
 				if (!wasContact) {
 					App::main()->addNewContact(App::userFromPeer(user->id), false);
-					user->input = MTP_inputPeerContact(userId);
-					user->inputUser = MTP_inputUserContact(userId);
+					if (user->input.type() != mtpc_inputPeerSelf) user->input = MTP_inputPeerContact(userId);
+					if (user->inputUser.type() != mtpc_inputUserSelf) user->inputUser = MTP_inputUserContact(userId);
 				}
 			} else {
 				if (user->access) {
-					user->input = MTP_inputPeerForeign(userId, MTP_long(user->access));
-					user->inputUser = MTP_inputUserForeign(userId, MTP_long(user->access));
+					if (user->input.type() != mtpc_inputPeerSelf) user->input = MTP_inputPeerForeign(userId, MTP_long(user->access));
+					if (user->inputUser.type() != mtpc_inputUserSelf) user->inputUser = MTP_inputUserForeign(userId, MTP_long(user->access));
 				}
 				if (user->contact < 0 && !user->phone.isEmpty() && App::userFromPeer(user->id) != MTP::authedId()) {
 					user->contact = 0;
@@ -731,8 +731,8 @@ namespace App {
 			switch (i.key()) {
 			case 's': newThumbLevel = 0; newMediumLevel = 5; newFullLevel = 4; break; // box 100x100
 			case 'm': newThumbLevel = 2; newMediumLevel = 0; newFullLevel = 3; break; // box 320x320
-			case 'x': newThumbLevel = 5; newMediumLevel = 3; newFullLevel = 0; break; // box 800x800
-			case 'y': newThumbLevel = 6; newMediumLevel = 6; newFullLevel = 1; break; // box 1280x1280
+			case 'x': newThumbLevel = 5; newMediumLevel = 3; newFullLevel = 1; break; // box 800x800
+			case 'y': newThumbLevel = 6; newMediumLevel = 6; newFullLevel = 0; break; // box 1280x1280
 			case 'w': newThumbLevel = 8; newMediumLevel = 8; newFullLevel = 2; break; // box 2560x2560
 			case 'a': newThumbLevel = 1; newMediumLevel = 4; newFullLevel = 8; break; // crop 160x160
 			case 'b': newThumbLevel = 3; newMediumLevel = 1; newFullLevel = 7; break; // crop 320x320
@@ -791,8 +791,8 @@ namespace App {
 			switch (size) {
 			case 's': newThumbLevel = 0; newMediumLevel = 5; newFullLevel = 4; break; // box 100x100
 			case 'm': newThumbLevel = 2; newMediumLevel = 0; newFullLevel = 3; break; // box 320x320
-			case 'x': newThumbLevel = 5; newMediumLevel = 3; newFullLevel = 0; break; // box 800x800
-			case 'y': newThumbLevel = 6; newMediumLevel = 6; newFullLevel = 1; break; // box 1280x1280
+			case 'x': newThumbLevel = 5; newMediumLevel = 3; newFullLevel = 1; break; // box 800x800
+			case 'y': newThumbLevel = 6; newMediumLevel = 6; newFullLevel = 0; break; // box 1280x1280
 			case 'w': newThumbLevel = 8; newMediumLevel = 8; newFullLevel = 2; break; // box 2560x2560
 			case 'a': newThumbLevel = 1; newMediumLevel = 4; newFullLevel = 8; break; // crop 160x160
 			case 'b': newThumbLevel = 3; newMediumLevel = 1; newFullLevel = 7; break; // crop 320x320
diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp
index f9414e5b2..d13f0e06e 100644
--- a/Telegram/SourceFiles/application.cpp
+++ b/Telegram/SourceFiles/application.cpp
@@ -677,8 +677,14 @@ void Application::startApp() {
 	}
 
 	QNetworkProxyFactory::setUseSystemConfiguration(true);
-    if (Local::oldMapVersion() < AppVersion) {
+	if (Local::oldMapVersion() < AppVersion) {
 		psRegisterCustomScheme();
+		if (Local::oldMapVersion() && AppVersion == FeaturesNotifyVersion) {
+			QString versionFeatures(QString::fromUtf8(FeaturesNotify));
+			if (!versionFeatures.isEmpty()) {
+				window->serviceNotification(versionFeatures);
+			}
+		}
 	}
 }
 
diff --git a/Telegram/SourceFiles/art/sprite.png b/Telegram/SourceFiles/art/sprite.png
index 11be67e95..a60025e09 100644
Binary files a/Telegram/SourceFiles/art/sprite.png and b/Telegram/SourceFiles/art/sprite.png differ
diff --git a/Telegram/SourceFiles/art/sprite_200x.png b/Telegram/SourceFiles/art/sprite_200x.png
index aecf1f7b1..c6d94a8aa 100644
Binary files a/Telegram/SourceFiles/art/sprite_200x.png and b/Telegram/SourceFiles/art/sprite_200x.png differ
diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h
index 46dbebe85..4d47f1bf6 100644
--- a/Telegram/SourceFiles/config.h
+++ b/Telegram/SourceFiles/config.h
@@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
 */
 #pragma once
 
-static const int32 AppVersion = 6017;
-static const wchar_t *AppVersionStr = L"0.6.17";
+static const int32 AppVersion = 6018;
+static const wchar_t *AppVersionStr = L"0.6.18";
 
 static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
 static const wchar_t *AppName = L"Telegram Desktop";
@@ -26,6 +26,9 @@ static const wchar_t *AppName = L"Telegram Desktop";
 static const wchar_t *AppId = L"{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"; // used in updater.cpp and Setup.iss for Windows
 static const wchar_t *AppFile = L"Telegram";
 
+static const int32 FeaturesNotifyVersion = 6018;
+extern const char *FeaturesNotify;
+
 #include "settings.h"
 
 enum {
@@ -105,10 +108,12 @@ enum {
 	WriteMapTimeout = 1000,
 	SaveDraftTimeout = 1000, // save draft after 1 secs of not changing text
 	SaveDraftAnywayTimeout = 5000, // or save anyway each 5 secs
+
+	ServiceUserId = 777000,
 };
 
 inline bool isServiceUser(uint64 id) {
-	return (id == 333000) || (id == 777000);
+	return (id == 333000) || (id == ServiceUserId);
 }
 
 #ifdef Q_OS_WIN
@@ -223,8 +228,6 @@ enum {
 	MessagesFirstLoad = 30, // first history part size requested
 	MessagesPerPage = 50, // next history part size
 
-	LinkCropLimit = 360, // 360px link length max
-
 	DownloadPartSize = 64 * 1024, // 64kb for photo
 	DocumentDownloadPartSize = 128 * 1024, // 128kb for document
 	MaxUploadPhotoSize = 10 * 1024 * 1024, // 10mb photos max
diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp
index 2def85d74..457bedaa0 100644
--- a/Telegram/SourceFiles/dialogswidget.cpp
+++ b/Telegram/SourceFiles/dialogswidget.cpp
@@ -1245,41 +1245,49 @@ void DialogsWidget::setInnerFocus() {
 	_filter.setFocus();
 }
 
-void DialogsWidget::regTyping(History *history, UserData *user) {
-	uint64 ms = getms(true);
-	history->typing[user] = ms + 6000;
-
-	Histories::TypingHistories::const_iterator i = App::histories().typing.find(history);
-	if (i == App::histories().typing.cend()) {
-		App::histories().typing.insert(history, ms);
-		history->typingFrame = 0;
-	}
-
-	history->updateTyping(ms, history->typingFrame, true);
+void DialogsWidget::animShow(const QPixmap &bgAnimCache) {
+	_bgAnimCache = bgAnimCache;
+	_animCache = myGrab(this, rect());
+	scroll.hide();
+	_filter.hide();
+	_cancelSearch.hide();
+	_newGroup.hide();
+	a_coord = anim::ivalue(-st::introSlideShift, 0);
+	a_alpha = anim::fvalue(0, 1);
+	a_bgCoord = anim::ivalue(0, st::introSlideShift);
+	a_bgAlpha = anim::fvalue(1, 0);
 	anim::start(this);
 }
 
-bool DialogsWidget::animStep(float64) {
-	uint64 ms = getms(true);
-	Histories::TypingHistories &typing(App::histories().typing);
-	for (Histories::TypingHistories::iterator i = typing.begin(), e = typing.end(); i != e;) {
-		uint32 typingFrame = (ms - i.value()) / 150;
-		if (i.key()->updateTyping(ms, typingFrame)) {
-			list.dlgUpdated(i.key());
-			App::main()->topBar()->update();
-		}
-		if (i.key()->typing.isEmpty()) {
-			i = typing.erase(i);
-		} else {
-			++i;
-		}
+bool DialogsWidget::animStep(float64 ms) {
+	float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration;
+	float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0;
+	bool res = true;
+	if (dt2 >= 1) {
+		res = false;
+		a_bgCoord.finish();
+		a_bgAlpha.finish();
+		a_coord.finish();
+		a_alpha.finish();
+		_bgAnimCache = _animCache = QPixmap();
+		scroll.show();
+		_filter.show();
+		onFilterUpdate(true);
+		activate();
+	} else {
+		a_bgCoord.update(dt1, st::introHideFunc);
+		a_bgAlpha.update(dt1, st::introAlphaHideFunc);
+		a_coord.update(dt2, st::introShowFunc);
+		a_alpha.update(dt2, st::introAlphaShowFunc);
 	}
-	return !typing.isEmpty();
+	update();
+	return res;
 }
 
 void DialogsWidget::onCancel() {
-	onCancelSearch();
-	emit cancelled();
+	if (!onCancelSearch() || !App::main()->selectingPeer()) {
+		emit cancelled();
+	}
 }
 
 void DialogsWidget::itemRemoved(HistoryItem *item) {
@@ -1296,7 +1304,9 @@ void DialogsWidget::unreadCountsReceived(const QVector<MTPDialog> &dialogs) {
 		Histories::iterator j = App::histories().find(App::peerFromMTP(d.vpeer));
 		if (j != App::histories().end()) {
 			App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, j.value());
-			j.value()->setUnreadCount(d.vunread_count.v, false);
+			if (d.vunread_count.v >= j.value()->unreadCount) {
+				j.value()->setUnreadCount(d.vunread_count.v, false);
+			}
 		}
 	}
 	if (App::wnd()) App::wnd()->psUpdateCounter();
@@ -1543,17 +1553,17 @@ void DialogsWidget::onListScroll() {
 	}
 }
 
-void DialogsWidget::onFilterUpdate() {
+void DialogsWidget::onFilterUpdate(bool force) {
+	if (animating() && !force) return;
+
 	QString filterText = _filter.text();
 	list.onFilterUpdate(filterText);
 	if (filterText.isEmpty()) {
 		_searchCache.clear();
 		_searchQueries.clear();
 		_searchQuery = QString();
-		if (!_cancelSearch.isHidden()) {
-			_cancelSearch.hide();
-			_newGroup.show();
-		}
+		_cancelSearch.hide();
+		_newGroup.show();
 	} else if (_cancelSearch.isHidden()) {
 		_cancelSearch.show();
 		_newGroup.hide();
@@ -1603,8 +1613,22 @@ void DialogsWidget::keyPressEvent(QKeyEvent *e) {
 
 void DialogsWidget::paintEvent(QPaintEvent *e) {
 	QPainter p(this);
-	if (_drawShadow) {
-		p.fillRect(width() - st::dlgShadow, 0, st::dlgShadow, height(), st::dlgShadowColor->b);
+	QRect r(e->rect());
+	if (r != rect()) {
+		p.setClipRect(r);
+	}
+	if (animating()) {
+		p.setOpacity(a_bgAlpha.current());
+		p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache);
+		p.setOpacity(a_alpha.current());
+		p.drawPixmap(a_coord.current(), 0, _animCache);
+		return;
+	}
+	if (cWideMode() && _drawShadow) {
+		QRect sh(width() - st::dlgShadow, 0, st::dlgShadow, height());
+		if (r.intersects(sh)) {
+			p.fillRect(sh, st::dlgShadowColor->b);
+		}
 	}
 }
 
@@ -1648,11 +1672,13 @@ void DialogsWidget::onNewGroup() {
 	App::wnd()->showLayer(new NewGroupBox());
 }
 
-void DialogsWidget::onCancelSearch() {
+bool DialogsWidget::onCancelSearch() {
+	bool clearing = !_filter.text().isEmpty();
 	list.clearFilter();
 	_filter.clear();
 	_filter.updatePlaceholder();
 	onFilterUpdate();
+	return clearing;
 }
 
 void DialogsWidget::onDialogToTopFrom(int movedFrom) {
diff --git a/Telegram/SourceFiles/dialogswidget.h b/Telegram/SourceFiles/dialogswidget.h
index 54d0318bd..055c45839 100644
--- a/Telegram/SourceFiles/dialogswidget.h
+++ b/Telegram/SourceFiles/dialogswidget.h
@@ -167,8 +167,7 @@ public:
 
 	void dialogsToUp();
 
-	void regTyping(History *history, UserData *user);
-
+	void animShow(const QPixmap &bgAnimCache);
 	bool animStep(float64 ms);
 
 	void setInnerFocus();
@@ -201,10 +200,10 @@ public slots:
 	void onCancel();
 	void onListScroll();
 	void activate();
-	void onFilterUpdate();
+	void onFilterUpdate(bool force = false);
 	void onAddContact();
 	void onNewGroup();
-	void onCancelSearch();
+	bool onCancelSearch();
 
 	void onDialogToTopFrom(int movedFrom);
 	bool onSearchMessages(bool searchCache = false);
@@ -229,6 +228,10 @@ private:
 	ScrollArea scroll;
 	DialogsListWidget list;
 
+	QPixmap _animCache, _bgAnimCache;
+	anim::ivalue a_coord, a_bgCoord;
+	anim::fvalue a_alpha, a_bgAlpha;
+
 	QTimer _searchTimer;
 	QString _searchQuery, _peopleQuery;
 	bool _searchFull, _peopleFull;
diff --git a/Telegram/SourceFiles/gui/flatbutton.cpp b/Telegram/SourceFiles/gui/flatbutton.cpp
index 2b8f5712f..88f31d7d2 100644
--- a/Telegram/SourceFiles/gui/flatbutton.cpp
+++ b/Telegram/SourceFiles/gui/flatbutton.cpp
@@ -214,3 +214,31 @@ void IconedButton::paintEvent(QPaintEvent *e) {
 		p.drawPixmap(t, App::sprite(), i);
 	}
 }
+
+MaskedButton::MaskedButton(QWidget *parent, const style::iconedButton &st, const QString &text) : IconedButton(parent, st, text) {
+}
+
+void MaskedButton::paintEvent(QPaintEvent *e) {
+	QPainter p(this);
+
+	p.setOpacity(_opacity);
+
+	p.setOpacity(a_opacity.current() * _opacity);
+
+	if (!_text.isEmpty()) {
+		p.setFont(_st.font->f);
+		p.setRenderHint(QPainter::TextAntialiasing);
+		p.setPen(a_bg.current());
+		const QPoint &t((_state & StateDown) ? _st.downTextPos : _st.textPos);
+		p.drawText(t.x(), t.y() + _st.font->ascent, _text);
+	}
+
+	const QRect &i((_state & StateDown) ? _st.downIcon : _st.icon);
+	if (i.width()) {
+		const QPoint &t((_state & StateDown) ? _st.downIconPos : _st.iconPos);
+		QRect r(i);
+		r.moveTo(t);
+		p.fillRect(r, a_bg.current());
+		p.drawPixmap(t, App::sprite(), i);
+	}
+}
diff --git a/Telegram/SourceFiles/gui/flatbutton.h b/Telegram/SourceFiles/gui/flatbutton.h
index 854e134c7..bde084c52 100644
--- a/Telegram/SourceFiles/gui/flatbutton.h
+++ b/Telegram/SourceFiles/gui/flatbutton.h
@@ -103,7 +103,7 @@ public slots:
 
 	void onStateChange(int oldState, ButtonStateChangeSource source);
 
-private:
+protected:
 
 	QString _text;
 
@@ -115,3 +115,14 @@ private:
 
 	float64 _opacity;
 };
+
+class MaskedButton : public IconedButton {
+	Q_OBJECT
+
+public:
+
+	MaskedButton(QWidget *parent, const style::iconedButton &st, const QString &text = QString());
+
+	void paintEvent(QPaintEvent *e);
+
+};
diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp
index fc8fbe404..8ce0b26eb 100644
--- a/Telegram/SourceFiles/gui/text.cpp
+++ b/Telegram/SourceFiles/gui/text.cpp
@@ -404,7 +404,7 @@ public:
 		} else {
 			QUrl url(original), good(url.isValid() ? url.toEncoded() : "");
 			QString readable = good.isValid() ? good.toDisplayString() : original;
-			result = _t->_font->m.elidedText(readable, Qt::ElideRight, LinkCropLimit);
+			result = _t->_font->m.elidedText(readable, Qt::ElideRight, st::linkCropLimit);
 			fullDisplayed = (result == readable) ? 1 : 0;
 		}
 	}
diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp
index 3f70556da..3705456f1 100644
--- a/Telegram/SourceFiles/history.cpp
+++ b/Telegram/SourceFiles/history.cpp
@@ -324,7 +324,11 @@ void UserData::setPhoto(const MTPUserProfilePhoto &p) {
 	} break;
 	default: {
 		photoId = 0;
-		photo = userDefPhoto(colorIndex);
+		if (id == ServiceUserId) {
+			photo = ImagePtr(QPixmap::fromImage(App::wnd()->iconLarge().scaledToWidth(160, Qt::SmoothTransformation)), "PNG");
+		} else {
+			photo = userDefPhoto(colorIndex);
+		}
 	} break;
 	}
 	emit App::main()->peerPhotoChanged(this);
@@ -365,7 +369,7 @@ void UserData::setName(const QString &first, const QString &last, const QString
 			firstName = first;
 			lastName = last;
 		}
-		updateName(firstName + ' ' + lastName, phoneName, usern);
+		updateName(lastName.isEmpty() ? firstName : (firstName + ' ' + lastName), phoneName, usern);
 	}
 	if (updUsername) {
 		if (App::main()) {
@@ -633,7 +637,7 @@ void DocumentOpenLink::onClick(Qt::MouseButton button) const {
 				if (reader.supportsAnimation() && reader.imageCount() > 1 && App::hoveredLinkItem()) {
 					startGif(App::hoveredLinkItem(), already);
 				} else {
-					App::wnd()->showDocument(data, QPixmap::fromImage(reader.read()), App::hoveredLinkItem());
+					App::wnd()->showDocument(data, QPixmap::fromImage(App::readImage(already)), App::hoveredLinkItem());
 				}
 			} else {
 				psOpenFile(already);
@@ -1068,6 +1072,37 @@ void Histories::clear() {
 	Parent::clear();
 }
 
+void Histories::regTyping(History *history, UserData *user) {
+	uint64 ms = getms(true);
+	history->typing[user] = ms + 6000;
+
+	TypingHistories::const_iterator i = typing.find(history);
+	if (i == typing.cend()) {
+		typing.insert(history, ms);
+		history->typingFrame = 0;
+	}
+
+	history->updateTyping(ms, history->typingFrame, true);
+	anim::start(this);
+}
+
+bool Histories::animStep(float64) {
+	uint64 ms = getms(true);
+	for (TypingHistories::iterator i = typing.begin(), e = typing.end(); i != e;) {
+		uint32 typingFrame = (ms - i.value()) / 150;
+		if (i.key()->updateTyping(ms, typingFrame)) {
+			App::main()->dlgUpdated(i.key());
+			App::main()->topBar()->update();
+		}
+		if (i.key()->typing.isEmpty()) {
+			i = typing.erase(i);
+		} else {
+			++i;
+		}
+	}
+	return !typing.isEmpty();
+}
+
 Histories::Parent::iterator Histories::erase(Histories::Parent::iterator i) {
 	delete i.value();
 	return Parent::erase(i);
@@ -4157,7 +4192,7 @@ HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, const
 	fwdNameUpdated();
 }
 
-HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, MsgId id, HistoryMessage *msg) : HistoryMessage(history, block, id, true, true, ::date(unixtime()), MTP::authedId(), msg->HistoryMessage::selectedText(FullItemSel), msg->getMedia())
+HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, MsgId id, HistoryMessage *msg) : HistoryMessage(history, block, id, (history->peer->input.type() != mtpc_inputPeerSelf), (history->peer->input.type() != mtpc_inputPeerSelf), ::date(unixtime()), MTP::authedId(), msg->HistoryMessage::selectedText(FullItemSel), msg->getMedia())
 , fwdDate(dynamic_cast<HistoryForwarded*>(msg) ? dynamic_cast<HistoryForwarded*>(msg)->dateForwarded() : msg->date)
 , fwdFrom(dynamic_cast<HistoryForwarded*>(msg) ? dynamic_cast<HistoryForwarded*>(msg)->fromForwarded() : msg->from())
 , fwdFromName(4096)
diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h
index 736f3dbbb..08f2c9216 100644
--- a/Telegram/SourceFiles/history.h
+++ b/Telegram/SourceFiles/history.h
@@ -480,12 +480,15 @@ public:
 MsgId clientMsgId();
 
 struct History;
-struct Histories : public QHash<PeerId, History*> {
+struct Histories : public QHash<PeerId, History*>, public Animated {
 	typedef QHash<PeerId, History*> Parent;
 
 	Histories() : unreadFull(0), unreadMuted(0) {
 	}
 
+	void regTyping(History *history, UserData *user);
+	bool animStep(float64 ms);
+
 	void clear();
 	Parent::iterator erase(Parent::iterator i);
 	~Histories() {
@@ -494,7 +497,7 @@ struct Histories : public QHash<PeerId, History*> {
 		unreadFull = unreadMuted = 0;
 	}
 
-	HistoryItem *addToBack(const MTPmessage &msg, int msgState = 1); // 1 - new message, 0 - not new message, -1 - searched message
+	HistoryItem *addToBack(const MTPmessage &msg, int msgState = 1); // 2 - new read message, 1 - new unread message, 0 - not new message, -1 - searched message
 //	HistoryItem *addToBack(const MTPgeoChatMessage &msg, bool newMsg = true);
 
 	typedef QMap<History*, uint64> TypingHistories; // when typing in this history started
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index f5c15e184..98600bb27 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -665,12 +665,14 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
 			_menu->addAction(lang(lng_context_clear_selection), historyWidget, SLOT(onClearSelected()));
 		} else if (App::hoveredLinkItem()) {
 			if (isUponSelected != -2) {
-				if (dynamic_cast<HistoryMessage*>(App::hoveredLinkItem())) {
+				if (dynamic_cast<HistoryMessage*>(App::hoveredLinkItem()) && App::hoveredLinkItem()->id > 0) {
 					_menu->addAction(lang(lng_context_forward_msg), historyWidget, SLOT(forwardMessage()))->setEnabled(true);
 				}
 				_menu->addAction(lang(lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true);
 			}
-			_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
+			if (App::hoveredLinkItem()->id > 0) {
+				_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
+			}
 			App::contextItem(App::hoveredLinkItem());
 		}
 	} else { // maybe cursor on some text history item?
@@ -711,7 +713,7 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
 			_menu->addAction(lang(lng_context_forward_selected), historyWidget, SLOT(onForwardSelected()));
 			_menu->addAction(lang(lng_context_delete_selected), historyWidget, SLOT(onDeleteSelected()));
 			_menu->addAction(lang(lng_context_clear_selection), historyWidget, SLOT(onClearSelected()));
-		} else if (item) {
+		} else if (item && ((isUponSelected != -2 && (canForward || canDelete)) || item->id > 0)) {
 			if (!_menu) _menu = new ContextMenu(this);
 			if (isUponSelected != -2) {
 				if (canForward) {
@@ -722,9 +724,11 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
 					_menu->addAction(lang((msg && msg->uploading()) ? lng_context_cancel_upload : lng_context_delete_msg), historyWidget, SLOT(deleteMessage()))->setEnabled(true);
 				}
 			}
-			_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
+			if (item->id > 0) {
+				_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
+			}
 		} else {
-			if (App::mousedItem() && App::mousedItem()->itemType() == HistoryItem::MsgType) {
+			if (App::mousedItem() && App::mousedItem()->itemType() == HistoryItem::MsgType && App::mousedItem()->id > 0) {
 				if (!_menu) _menu = new ContextMenu(this);
 				_menu->addAction(lang(lng_context_select_msg), historyWidget, SLOT(selectMessage()))->setEnabled(true);
 				item = App::mousedItem();
@@ -1425,10 +1429,14 @@ void HistoryHider::mousePressEvent(QMouseEvent *e) {
 void HistoryHider::startHide() {
 	if (hiding) return;
 	hiding = true;
-	if (offered) cacheForAnim = myGrab(this, box);
-	if (_forwardRequest) MTP::cancel(_forwardRequest);
-	aOpacity.start(0);
-	anim::start(this);
+	if (cWideMode()) {
+		if (offered) cacheForAnim = myGrab(this, box);
+		if (_forwardRequest) MTP::cancel(_forwardRequest);
+		aOpacity.start(0);
+		anim::start(this);
+	} else {
+		QTimer::singleShot(0, this, SLOT(deleteLater()));
+	}
 }
 
 void HistoryHider::forward() {
@@ -1473,6 +1481,13 @@ void HistoryHider::resizeEvent(QResizeEvent *e) {
 }
 
 void HistoryHider::offerPeer(PeerId peer) {
+	if (!peer) {
+		offered = 0;
+		toText.setText(st::boxFont, QString());
+		toTextWidth = 0;
+		resizeEvent(0);
+		return;
+	}
 	offered = App::peer(peer);
 	QString phrase;
 	if (_sharedContact) {
@@ -1502,6 +1517,10 @@ void HistoryHider::offerPeer(PeerId peer) {
 	setFocus();
 }
 
+QString HistoryHider::offeredText() const {
+	return toText.original();
+}
+
 bool HistoryHider::wasOffered() const {
 	return !!offered;
 }
@@ -1679,12 +1698,10 @@ void HistoryWidget::typingDone(const MTPBool &result, mtpRequestId req) {
 void HistoryWidget::activate() {
 	if (App::main()->selectingPeer()) {
 		if (hiderOffered) {
-//			hiderOffered = false;
 			App::main()->focusPeerSelect();
 			return;
 		} else {
 			App::main()->dialogsActivate();
-//			App::main()->hidePeerSelect();
 		}
 	}
 	if (_list) {
@@ -1750,6 +1767,7 @@ void HistoryWidget::showPeer(const PeerId &peer, MsgId msgId, bool force, bool l
 			checkUnreadLoaded();
 
 			clearLoadingAround();
+			emit peerShown(histPeer);
 			return activate();
 		}
 		updateTyping(false);
@@ -1899,7 +1917,7 @@ void HistoryWidget::checkUnreadLoaded(bool checkOnlyShow) {
 }
 
 void HistoryWidget::updateControlsVisibility() {
-	if (!hist) {
+	if (!hist || animating()) {
 		_scroll.hide();
 		_send.hide();
 		_toHistoryEnd.hide();
@@ -2225,6 +2243,8 @@ void HistoryWidget::loadMessagesAround() {
 }
 
 void HistoryWidget::onListScroll() {
+	if (_scroll.isHidden()) return;
+
 	App::checkImageCacheSize();
 
 	if (histPreloading || !hist || ((_list->isHidden() || _scroll.isHidden() || !App::wnd()->windowHandle()->isVisible()) && hist->readyForWork())) {
@@ -2320,7 +2340,7 @@ mtpRequestId HistoryWidget::onForward(const PeerId &peer, SelectedItemSet toForw
 
 			MTPstring msgText(MTP_string(msg->selectedText(FullItemSel)));
 
-			int32 flags = 0x01 | 0x02; // unread, out
+			int32 flags = (histPeer->input.type() == mtpc_inputPeerSelf) ? 0 : (0x01 | 0x02); // unread, out
 			hist->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(histPeer->id), MTP_int(unixtime()), msgText, MTP_messageMediaEmpty()));
 			hist->sendRequestId = MTP::send(MTPmessages_SendMessage(histPeer->input, msgText, MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
 		}
@@ -2367,10 +2387,11 @@ void HistoryWidget::shareContact(const PeerId &peer, const QString &phone, const
 
 	h->loadAround(0);
 
-	int32 flags = 0x01 | 0x02; // unread, out
+	PeerData *p = App::peer(peer);
+	int32 flags = (p->input.type() == mtpc_inputPeerSelf) ? 0 : (0x01 | 0x02); // unread, out
 	h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(peer), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname), MTP_int(userId))));
 	
-	h->sendRequestId = MTP::send(MTPmessages_SendMedia(App::peer(peer)->input, MTP_inputMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
+	h->sendRequestId = MTP::send(MTPmessages_SendMedia(p->input, MTP_inputMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
 
 	App::historyRegRandom(randomId, newId);
 	if (hist && histPeer && peer == histPeer->id) {
@@ -2434,6 +2455,7 @@ bool HistoryWidget::animStep(float64 ms) {
 	float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0;
 	bool res = true;
 	if (dt2 >= 1) {
+		anim::stop(this);
 		res = false;
 		a_bgCoord.finish();
 		a_bgAlpha.finish();
@@ -2441,6 +2463,7 @@ bool HistoryWidget::animStep(float64 ms) {
 		a_alpha.finish();
 		_bgAnimCache = _animCache = _animTopBarCache = _bgAnimTopBarCache = QPixmap();
 		App::main()->topBar()->stopAnim();
+		App::main()->topBar()->enableShadow();
 		updateControlsVisibility();
 		if (hist && hist->readyForWork()) {
 			_scroll.show();
@@ -2716,6 +2739,13 @@ void HistoryWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth)
 	}
 }
 
+void HistoryWidget::topBarShadowParams(int32 &x, float64 &o) {
+	if (animating() && a_coord.current() >= 0) {
+		x = a_coord.current();
+		o = a_alpha.current();
+	}
+}
+
 void HistoryWidget::topBarClick() {
 	if (hist) App::main()->showPeerProfile(histPeer);
 }
@@ -2896,11 +2926,11 @@ void HistoryWidget::confirmSendImage(const ReadyLocalMedia &img) {
 	History *h = App::history(img.peer);
 	if (img.type == ToPreparePhoto) {
 		h->loadAround(0);
-		int32 flags = 0x01 | 0x02; // unread, out
+		int32 flags = (h->peer->input.type() == mtpc_inputPeerSelf) ? 0 : (0x01 | 0x02); // unread, out
 		h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(img.photo)));
 	} else if (img.type == ToPrepareDocument) {
 		h->loadAround(0);
-		int32 flags = 0x01 | 0x02; // unread, out
+		int32 flags = (h->peer->input.type() == mtpc_inputPeerSelf) ? 0 : (0x01 | 0x02); // unread, out
 		h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(img.peer), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(img.document)));
 	}
 
@@ -3227,7 +3257,7 @@ void HistoryWidget::setFieldText(const QString &text) {
 }
 
 void HistoryWidget::onCancel() {
-	showPeer(0);
+	if (App::main()) App::main()->showPeer(0);
 	emit cancelled();
 }
 
diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h
index 9a80f5abf..1e836c6d1 100644
--- a/Telegram/SourceFiles/historywidget.h
+++ b/Telegram/SourceFiles/historywidget.h
@@ -204,6 +204,7 @@ public:
 	void resizeEvent(QResizeEvent *e);
 
 	void offerPeer(PeerId peer);
+	QString offeredText() const;
 
 	bool wasOffered() const;
 
@@ -270,6 +271,7 @@ public:
 	void updateTopBarSelection();
 
 	void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
+	void topBarShadowParams(int32 &x, float64 &o);
 	void topBarClick();
 
 	void loadMessages();
diff --git a/Telegram/SourceFiles/intro/intro.cpp b/Telegram/SourceFiles/intro/intro.cpp
index 59a975588..a83b6f784 100644
--- a/Telegram/SourceFiles/intro/intro.cpp
+++ b/Telegram/SourceFiles/intro/intro.cpp
@@ -333,6 +333,10 @@ void IntroWidget::keyPressEvent(QKeyEvent *e) {
 	}
 }
 
+void IntroWidget::updateWideMode() {
+
+}
+
 void IntroWidget::rpcInvalidate() {
 	if (phone) phone->rpcInvalidate();
 	if (code) code->rpcInvalidate();
diff --git a/Telegram/SourceFiles/intro/intro.h b/Telegram/SourceFiles/intro/intro.h
index 437908ff3..8096b0f60 100644
--- a/Telegram/SourceFiles/intro/intro.h
+++ b/Telegram/SourceFiles/intro/intro.h
@@ -40,6 +40,8 @@ public:
 	void mousePressEvent(QMouseEvent *e);
 	void keyPressEvent(QKeyEvent *e);
 
+	void updateWideMode();
+
 	void animShow(const QPixmap &bgAnimCache, bool back = false);
 	bool animStep(float64 ms);
 
diff --git a/Telegram/SourceFiles/intro/introcode.cpp b/Telegram/SourceFiles/intro/introcode.cpp
index da821788a..f338dbf53 100644
--- a/Telegram/SourceFiles/intro/introcode.cpp
+++ b/Telegram/SourceFiles/intro/introcode.cpp
@@ -106,7 +106,7 @@ void IntroCode::paintEvent(QPaintEvent *e) {
 		p.setOpacity(errorAlpha.current());
 		p.setFont(st::introErrFont->f);
 		p.setPen(st::introErrColor->p);
-		p.drawText(textRect.left(), next.y() + next.height() + st::introErrTop + st::introErrFont->ascent, error);
+		p.drawText(QRect(textRect.left(), next.y() + next.height() + st::introErrTop, st::introTextSize.width(), st::introErrHeight), error, style::al_center);
 	}
 }
 
diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp
index c57f074df..8c44b2d87 100644
--- a/Telegram/SourceFiles/layerwidget.cpp
+++ b/Telegram/SourceFiles/layerwidget.cpp
@@ -33,10 +33,17 @@ BackgroundWidget::BackgroundWidget(QWidget *parent, LayeredWidget *w) : QWidget(
 	show();
 	connect(w, SIGNAL(closed()), this, SLOT(onInnerClose()));
 	connect(w, SIGNAL(resized()), this, SLOT(update()));
+	connect(w, SIGNAL(destroyed(QObject*)), this, SLOT(boxDestroyed(QObject*)));
 	w->setFocus();
 }
 
+void BackgroundWidget::showFast() {
+	animStep(st::layerSlideDuration + 1);
+	update();
+}
+
 void BackgroundWidget::paintEvent(QPaintEvent *e) {
+	if (!w) return;
 	bool trivial = (rect() == e->rect());
 
 	QPainter p(this);
@@ -91,6 +98,10 @@ void BackgroundWidget::resizeEvent(QResizeEvent *e) {
 	w->parentResized();
 }
 
+void BackgroundWidget::updateWideMode() {
+
+}
+
 void BackgroundWidget::replaceInner(LayeredWidget *n) {
 	if (_hidden) _hidden->deleteLater();
 	_hidden = w;
@@ -99,6 +110,7 @@ void BackgroundWidget::replaceInner(LayeredWidget *n) {
 	w->setParent(this);
 	connect(w, SIGNAL(closed()), this, SLOT(onInnerClose()));
 	connect(w, SIGNAL(resized()), this, SLOT(update()));
+	connect(w, SIGNAL(destroyed(QObject*)), this, SLOT(boxDestroyed(QObject*)));
 	w->show();
 	resizeEvent(0);
 	w->animStep(1);
@@ -112,8 +124,9 @@ bool BackgroundWidget::animStep(float64 ms) {
 	if (dt >= 1) {
 		aBackground.finish();
 		if (hiding)	{
-			QTimer::singleShot(0, App::wnd(), SLOT(layerHidden()));
+			App::wnd()->layerFinishedHide(this);
 		}
+		anim::stop(this);
 		res = false;
 	} else {
 		aBackground.update(dt, aBackgroundFunc);
@@ -122,6 +135,15 @@ bool BackgroundWidget::animStep(float64 ms) {
 	return res;
 }
 
+void BackgroundWidget::boxDestroyed(QObject *obj) {
+	if (obj == w) {
+		if (App::wnd()) App::wnd()->layerFinishedHide(this);
+		w = 0;
+	} else if (_hidden == obj) {
+		_hidden = 0;
+	}
+}
+
 BackgroundWidget::~BackgroundWidget() {
 	if (App::wnd()) App::wnd()->noBox(this);
 	w->deleteLater();
diff --git a/Telegram/SourceFiles/layerwidget.h b/Telegram/SourceFiles/layerwidget.h
index 3e06c5426..a35f387d9 100644
--- a/Telegram/SourceFiles/layerwidget.h
+++ b/Telegram/SourceFiles/layerwidget.h
@@ -54,11 +54,15 @@ public:
 
 	BackgroundWidget(QWidget *parent, LayeredWidget *w);
 
+	void showFast();
+
 	void paintEvent(QPaintEvent *e);
 	void keyPressEvent(QKeyEvent *e);
 	void mousePressEvent(QMouseEvent *e);
 	void resizeEvent(QResizeEvent *e);
 
+	void updateWideMode();
+
 	void replaceInner(LayeredWidget *n);
 
 	bool animStep(float64 ms);
@@ -69,6 +73,7 @@ public slots:
 
 	void onClose();
 	bool onInnerClose();
+	void boxDestroyed(QObject *obj);
 
 private:
 
diff --git a/Telegram/SourceFiles/localimageloader.cpp b/Telegram/SourceFiles/localimageloader.cpp
index e49e993f5..d34425db0 100644
--- a/Telegram/SourceFiles/localimageloader.cpp
+++ b/Telegram/SourceFiles/localimageloader.cpp
@@ -149,13 +149,13 @@ void LocalImageLoaderPrivate::prepareImages() {
 			photoThumbs.insert('m', medium);
 			photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0)));
 
-			QPixmap full = (w > 800 || h > 800) ? QPixmap::fromImage(img.scaled(800, 800, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(img);
-			photoThumbs.insert('x', full);
-			photoSizes.push_back(MTP_photoSize(MTP_string("x"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0)));
+			QPixmap full = (w > 1280 || h > 1280) ? QPixmap::fromImage(img.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(img);
+			photoThumbs.insert('y', full);
+			photoSizes.push_back(MTP_photoSize(MTP_string("y"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0)));
 
 			{
 				QBuffer jpegBuffer(&jpeg);
-				full.save(&jpegBuffer, "JPG", 87);
+				full.save(&jpegBuffer, "JPG", 77);
 			}
 			if (!filesize) filesize = jpeg.size();
 		
diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp
index d36c2156d..d09070c9e 100644
--- a/Telegram/SourceFiles/localstorage.cpp
+++ b/Telegram/SourceFiles/localstorage.cpp
@@ -1045,6 +1045,24 @@ namespace Local {
 		if (!data->tasks.isEmpty() && (data->tasks.at(0) == ClearManagerAll)) return true;
 		if (task == ClearManagerAll) {
 			data->tasks.clear();
+			if (!_storageMap.isEmpty()) {
+				_storageMap.clear();
+				_storageFilesSize = 0;
+				_mapChanged = true;
+			}
+			if (!_draftsMap.isEmpty()) {
+				_draftsMap.clear();
+				_mapChanged = true;
+			}
+			if (!_draftsPositionsMap.isEmpty()) {
+				_draftsPositionsMap.clear();
+				_mapChanged = true;
+			}
+			if (_locationsKey) {
+				_locationsKey = 0;
+				_mapChanged = true;
+			}
+			_writeMap();
 		} else {
 			if (task & ClearManagerImages) {
 				if (data->images.isEmpty()) {
@@ -1058,10 +1076,12 @@ namespace Local {
 						data->images.insert(k, i.value());
 					}
 				}
-				_storageMap.clear();
-				_storageFilesSize = 0;
-				_mapChanged = true;
-				_writeMap();
+				if (!_storageMap.isEmpty()) {
+					_storageMap.clear();
+					_storageFilesSize = 0;
+					_mapChanged = true;
+					_writeMap();
+				}
 			}
 			for (int32 i = 0, l = data->tasks.size(); i < l; ++i) {
 				if (data->tasks.at(i) == task) return true;
diff --git a/Telegram/SourceFiles/main.cpp b/Telegram/SourceFiles/main.cpp
index 7fe9471ff..186d5ee69 100644
--- a/Telegram/SourceFiles/main.cpp
+++ b/Telegram/SourceFiles/main.cpp
@@ -19,6 +19,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
 #include "application.h"
 #include "pspecific.h"
 
+const char *FeaturesNotify = "\
+Telegram Desktop was updated to version 0.6.18\n\
+\n\
+ \xe2\x80\x94 Single-column layout support added for small chat window.\n\
+ \xe2\x80\x94 Photos are sent up to 1280x1280 size.\n\
+ \xe2\x80\x94 New version notifications added.\n\
+\n\
+Full versions log is available here:\n\
+https://desktop.telegram.org/#changelog";
+
 int main(int argc, char *argv[]) {
 #ifdef _NEED_WIN_GENERATE_DUMP
 	_oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter);
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 35c1cb807..aa5edf9f3 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -143,6 +143,7 @@ void TopBarWidget::enableShadow(bool enable) {
 
 void TopBarWidget::paintEvent(QPaintEvent *e) {
 	QPainter p(this);
+
 	if (e->rect().top() < st::topBarHeight) { // optimize shadow-only drawing
 		p.fillRect(QRect(0, 0, width(), st::topBarHeight), st::topBarBG->b);
 		if (_clearSelection.isHidden()) {
@@ -156,7 +157,16 @@ void TopBarWidget::paintEvent(QPaintEvent *e) {
 		}
 	}
 	if (_drawShadow) {
-		p.fillRect(st::titleShadow, st::topBarHeight, width() - st::titleShadow, st::titleShadow, st::titleShadowColor->b);
+		int32 shadowCoord = 0;
+		float64 shadowOpacity = 1.;
+		main()->topBarShadowParams(shadowCoord, shadowOpacity);
+
+		p.setOpacity(shadowOpacity);
+		if (cWideMode()) {
+			p.fillRect(shadowCoord + st::titleShadow, st::topBarHeight, width() - st::titleShadow, st::titleShadow, st::titleShadowColor->b);
+		} else {
+			p.fillRect(shadowCoord, st::topBarHeight, width(), st::titleShadow, st::titleShadowColor->b);
+		}
 	}
 }
 
@@ -271,8 +281,8 @@ MainWidget *TopBarWidget::main() {
 	return static_cast<MainWidget*>(parentWidget());
 }
 
-MainWidget::MainWidget(Window *window) : QWidget(window), failedObjId(0), _dialogsWidth(st::dlgMinWidth),
-dialogs(this), history(this), profile(0), overview(0), _topBar(this), hider(0), _mediaType(this), _mediaTypeMask(0),
+MainWidget::MainWidget(Window *window) : QWidget(window), _started(0), failedObjId(0), _dialogsWidth(st::dlgMinWidth),
+dialogs(this), history(this), profile(0), overview(0), _topBar(this), _forwardConfirm(0), hider(0), _mediaType(this), _mediaTypeMask(0),
 updPts(0), updDate(0), updQts(-1), updSeq(0), updInited(false), onlineRequest(0), _failDifferenceTimeout(1), _lastUpdateTime(0) {
 	setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
 
@@ -296,7 +306,12 @@ updPts(0), updDate(0), updQts(-1), updSeq(0), updInited(false), onlineRequest(0)
 	}
 
 	dialogs.show();
-	history.show();
+	if (cWideMode()) {
+		history.show();
+	} else {
+		history.hide();
+	}
+	App::wnd()->getTitle()->updateBackButton();
 	_topBar.hide();
 
 	_topBar.raise();
@@ -338,14 +353,70 @@ void MainWidget::onSendPaths(const PeerId &peer) {
 void MainWidget::noHider(HistoryHider *destroyed) {
 	if (hider == destroyed) {
 		hider = 0;
+		if (cWideMode()) {
+			if (_forwardConfirm) {
+				_forwardConfirm->deleteLater();
+				_forwardConfirm = 0;
+			}
+		} else {
+			if (_forwardConfirm) {
+				_forwardConfirm->startHide();
+				_forwardConfirm = 0;
+			}
+			onPeerShown(history.peer());
+			if (profile || overview || (history.peer() && history.peer()->id)) {
+				dialogs.enableShadow(false);
+				QPixmap animCache = myGrab(this, QRect(0, st::topBarHeight, _dialogsWidth, height() - st::topBarHeight)),
+					animTopBarCache = myGrab(this, QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight));
+				dialogs.enableShadow();
+				_topBar.enableShadow();
+				dialogs.hide();
+				if (overview) {
+					overview->show();
+					overview->animShow(animCache, animTopBarCache);
+				} else if (profile) {
+					profile->show();
+					profile->animShow(animCache, animTopBarCache);
+				} else {
+					history.show();
+					history.animShow(animCache, animTopBarCache);
+				}
+			}
+			App::wnd()->getTitle()->updateBackButton();
+		}
 	}
 }
 
-void MainWidget::forwardLayer(bool forwardSelected) {
-	hider = new HistoryHider(this, forwardSelected);
-	hider->show();
-	resizeEvent(0);
-	dialogs.activate();
+void MainWidget::hiderLayer(HistoryHider *h) {
+	hider = h;
+	if (cWideMode()) {
+		hider->show();
+		resizeEvent(0);
+		dialogs.activate();
+	} else {
+		hider->hide();
+		dialogs.enableShadow(false);
+		QPixmap animCache = myGrab(this, QRect(0, 0, _dialogsWidth, height()));
+		dialogs.enableShadow();
+		_topBar.enableShadow();
+
+		onPeerShown(0);
+		if (overview) {
+			overview->hide();
+		} else if (profile) {
+			profile->hide();
+		} else {
+			history.hide();
+		}
+		dialogs.show();
+		resizeEvent(0);
+		dialogs.animShow(animCache);
+		App::wnd()->getTitle()->updateBackButton();
+	}
+}
+
+void MainWidget::forwardLayer(int32 forwardSelected) {
+	hiderLayer((forwardSelected < 0) ? (new HistoryHider(this)) : (new HistoryHider(this, forwardSelected > 0)));
 }
 
 void MainWidget::deleteLayer(int32 selectedCount) {
@@ -360,10 +431,7 @@ void MainWidget::deleteLayer(int32 selectedCount) {
 }
 
 void MainWidget::shareContactLayer(UserData *contact) {
-	hider = new HistoryHider(this, contact);
-	hider->show();
-	resizeEvent(0);
-	dialogs.activate();
+	hiderLayer(new HistoryHider(this, contact));
 }
 
 bool MainWidget::selectingPeer() {
@@ -372,10 +440,23 @@ bool MainWidget::selectingPeer() {
 
 void MainWidget::offerPeer(PeerId peer) {
 	hider->offerPeer(peer);
+	if (!cWideMode()) {
+		_forwardConfirm = new ConfirmBox(hider->offeredText(), lang(lng_forward));
+		connect(_forwardConfirm, SIGNAL(confirmed()), hider, SLOT(forward()));
+		connect(_forwardConfirm, SIGNAL(cancelled()), this, SLOT(onForwardCancel()));
+		connect(_forwardConfirm, SIGNAL(destroyed(QObject*)), this, SLOT(onForwardCancel(QObject*)));
+		App::wnd()->showLayer(_forwardConfirm);
+	}
 }
 
-void MainWidget::hidePeerSelect() {
-	hider->startHide();
+void MainWidget::onForwardCancel(QObject *obj) {
+	if (!obj || obj == _forwardConfirm) {
+		if (_forwardConfirm) {
+			_forwardConfirm->startHide();
+			_forwardConfirm = 0;
+		}
+		if (hider) hider->offerPeer(0);
+	}
 }
 
 void MainWidget::focusPeerSelect() {
@@ -551,7 +632,7 @@ void MainWidget::sendPreparedText(History *hist, const QString &text) {
 		App::historyRegRandom(randomId, newId);
 
 		MTPstring msgText(MTP_string(sendingText));
-		int32 flags = 0x01 | 0x02; // unread, out
+		int32 flags = (hist->peer->input.type() == mtpc_inputPeerSelf) ? 0 : (0x01 | 0x02); // unread, out
 		hist->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(hist->peer->id), MTP_int(unixtime()), msgText, MTP_messageMediaEmpty()));
 		hist->sendRequestId = MTP::send(MTPmessages_SendMessage(hist->peer->input, msgText, MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
 	}
@@ -962,7 +1043,7 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
 						if (reader.supportsAnimation() && reader.imageCount() > 1 && item) {
 							startGif(item, already);
 						} else {
-							App::wnd()->showDocument(document, QPixmap::fromImage(reader.read()), item);
+							App::wnd()->showDocument(document, QPixmap::fromImage(App::readImage(already)), item);
 						}
 					} else {
 						psOpenFile(already);
@@ -1023,11 +1104,44 @@ void MainWidget::cancelSendImage() {
 void MainWidget::dialogsCancelled() {
 	if (hider) {
 		hider->startHide();
+		noHider(hider);
+		history.activate();
 	} else {
 		history.activate();
 	}
 }
 
+void MainWidget::serviceNotification(const QString &msg, const MTPMessageMedia &media, bool unread) {
+	int32 flags = unread ? 0x01 : 0; // unread
+	HistoryItem *item = App::histories().addToBack(MTP_message(MTP_int(flags), MTP_int(clientMsgId()), MTP_int(ServiceUserId), MTP_peerUser(MTP_int(MTP::authedId())), MTP_int(unixtime()), MTP_string(msg), media), unread ? 1 : 2);
+	if (item) {
+		history.peerMessagesUpdated(item->history()->peer->id);
+	}
+}
+
+void MainWidget::serviceHistoryDone(const MTPmessages_Messages &msgs) {
+	switch (msgs.type()) {
+	case mtpc_messages_messages:
+		App::feedUsers(msgs.c_messages_messages().vusers);
+		App::feedChats(msgs.c_messages_messages().vchats);
+		App::feedMsgs(msgs.c_messages_messages().vmessages);
+		break;
+
+	case mtpc_messages_messagesSlice:
+		App::feedUsers(msgs.c_messages_messagesSlice().vusers);
+		App::feedChats(msgs.c_messages_messagesSlice().vchats);
+		App::feedMsgs(msgs.c_messages_messagesSlice().vmessages);
+		break;
+	}
+
+	App::wnd()->showDelayedServiceMsgs();
+}
+
+bool MainWidget::serviceHistoryFail(const RPCError &error) {
+	App::wnd()->showDelayedServiceMsgs();
+	return false;
+}
+
 void MainWidget::setInnerFocus() {
 	if (hider || !history.peer()) {
 		if (hider && hider->wasOffered()) {
@@ -1052,7 +1166,9 @@ void MainWidget::createDialogAtTop(History *history, int32 unreadCount) {
 
 void MainWidget::showPeer(quint64 peerId, qint32 msgId, bool back, bool force) {
 	if (!back && _stack.size() == 1 && _stack[0]->type() == HistoryStackItem && _stack[0]->peer->id == peerId) {
-		back = true;
+		if (cWideMode() || !selectingPeer()) {
+			back = true;
+		}
 	}
 	App::wnd()->hideLayer();
 	QPixmap animCache, animTopBarCache;
@@ -1061,15 +1177,23 @@ void MainWidget::showPeer(quint64 peerId, qint32 msgId, bool back, bool force) {
 		hider = 0;
 	}
 	if (force || !selectingPeer()) {
-		if (history.isHidden() && (profile || overview)) {
+		if ((history.isHidden() && (profile || overview)) || !cWideMode()) {
 			dialogs.enableShadow(false);
 			if (peerId) {
 				_topBar.enableShadow(false);
-				animCache = myGrab(this, history.geometry());
-			} else {
+				if (cWideMode()) {
+					animCache = myGrab(this, QRect(_dialogsWidth, st::topBarHeight, width() - _dialogsWidth, height() - st::topBarHeight));
+				} else {
+					animCache = myGrab(this, QRect(0, st::topBarHeight, _dialogsWidth, height() - st::topBarHeight));
+				}
+			} else if (cWideMode()) {
 				animCache = myGrab(this, QRect(_dialogsWidth, 0, width() - _dialogsWidth, height()));
+			} else {
+				animCache = myGrab(this, QRect(0, 0, _dialogsWidth, height()));
+			}
+			if (peerId || cWideMode()) {
+				animTopBarCache = myGrab(this, QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight));
 			}
-			animTopBarCache = myGrab(this, QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight));
 			dialogs.enableShadow();
 			_topBar.enableShadow();
 			history.show();
@@ -1077,6 +1201,7 @@ void MainWidget::showPeer(quint64 peerId, qint32 msgId, bool back, bool force) {
 	}
 	history.showPeer(peerId, msgId, force);
 	if (force || !selectingPeer()) {
+		bool noPeer = (!history.peer() || !history.peer()->id), onlyDialogs = noPeer && !cWideMode();
 		if (profile || overview) {
 			if (profile) {
 				profile->hide();
@@ -1092,17 +1217,31 @@ void MainWidget::showPeer(quint64 peerId, qint32 msgId, bool back, bool force) {
 				overview = 0;
 			}
 			_stack.clear();
-			if (!history.peer() || !history.peer()->id) {
+		}
+		if (onlyDialogs) {
+			_topBar.hide();
+			history.hide();
+			dialogs.show();
+			if (!animCache.isNull()) {
+				dialogs.animShow(animCache);
+			}
+		} else {
+			if (noPeer) {
 				_topBar.hide();
 				resizeEvent(0);
 			}
+			if (!cWideMode()) dialogs.hide();
+			history.show();
 			if (!animCache.isNull()) {
 				history.animShow(animCache, animTopBarCache, back);
 			}
 		}
 	}
-	dialogs.scrollToPeer(peerId, msgId);
-	dialogs.update();
+	if (!dialogs.isHidden()) {
+		dialogs.scrollToPeer(peerId, msgId);
+		dialogs.update();
+	}
+	App::wnd()->getTitle()->updateBackButton();
 }
 
 void MainWidget::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) {
@@ -1198,6 +1337,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
 	dialogs.raise();
 	_mediaType.raise();
 	if (hider) hider->raise();
+	App::wnd()->getTitle()->updateBackButton();
 }
 
 void MainWidget::showPeerProfile(PeerData *peer, bool back, int32 lastScrollTop, bool allMediaShown) {
@@ -1241,6 +1381,7 @@ void MainWidget::showPeerProfile(PeerData *peer, bool back, int32 lastScrollTop,
 	dialogs.raise();
 	_mediaType.raise();
 	if (hider) hider->raise();
+	App::wnd()->getTitle()->updateBackButton();
 }
 
 void MainWidget::showBackFromStack() {
@@ -1535,35 +1676,94 @@ void MainWidget::hideAll() {
 }
 
 void MainWidget::showAll() {
-	dialogs.show();
-	if (overview) {
-		overview->show();
-	} else if(profile) {
-		profile->show();
+	if (cWideMode()) {
+		if (hider) {
+			hider->show();
+			if (_forwardConfirm) {
+				App::wnd()->hideLayer(true);
+				_forwardConfirm = 0;
+			}
+		}
+		dialogs.show();
+		if (overview) {
+			overview->show();
+		} else if (profile) {
+			profile->show();
+		} else {
+			history.show();
+		}
+		if (profile || overview || history.peer()) {
+			_topBar.show();
+		}
 	} else {
-		history.show();
-	}
-	if (profile || overview || history.peer()) {
-		_topBar.show();
+		if (hider) {
+			hider->hide();
+			if (!_forwardConfirm && hider->wasOffered()) {
+				_forwardConfirm = new ConfirmBox(hider->offeredText(), lang(lng_forward));
+				connect(_forwardConfirm, SIGNAL(confirmed()), hider, SLOT(forward()));
+				connect(_forwardConfirm, SIGNAL(cancelled()), this, SLOT(onForwardCancel()));
+				App::wnd()->showLayer(_forwardConfirm, true);
+			}
+		}
+		if (selectingPeer()) {
+			dialogs.show();
+			history.hide();
+			if (overview) overview->hide();
+			if (profile) profile->hide();
+			_topBar.hide();
+		} else if (overview) {
+			overview->show();
+		} else if (profile) {
+			profile->show();
+		} else if (history.peer()) {
+			history.show();
+		} else {
+			dialogs.show();
+			history.hide();
+		}
+		if (!selectingPeer() && (profile || overview || history.peer())) {
+			_topBar.show();
+			dialogs.hide();
+		}
 	}
 	App::wnd()->checkHistoryActivation();
 }
 
 void MainWidget::resizeEvent(QResizeEvent *e) {
-	_dialogsWidth = snap<int>((width()  * 5) / 14, st::dlgMinWidth, st::dlgMaxWidth);
 	int32 tbh = _topBar.isHidden() ? 0 : st::topBarHeight;
-	dialogs.setGeometry(0, 0, _dialogsWidth + st::dlgShadow, height());
-	_topBar.setGeometry(_dialogsWidth, 0, width() - _dialogsWidth, st::topBarHeight + st::titleShadow);
+	if (cWideMode()) {
+		_dialogsWidth = snap<int>((width() * 5) / 14, st::dlgMinWidth, st::dlgMaxWidth);
+		dialogs.setGeometry(0, 0, _dialogsWidth + st::dlgShadow, height());
+		_topBar.setGeometry(_dialogsWidth, 0, width() - _dialogsWidth, st::topBarHeight + st::titleShadow);
+		history.setGeometry(_dialogsWidth, tbh, width() - _dialogsWidth, height() - tbh);
+		if (hider) hider->setGeometry(QRect(_dialogsWidth, 0, width() - _dialogsWidth, height()));
+	} else {
+		_dialogsWidth = width();
+		dialogs.setGeometry(0, 0, _dialogsWidth + st::dlgShadow, height());
+		_topBar.setGeometry(0, 0, _dialogsWidth, st::topBarHeight + st::titleShadow);
+		history.setGeometry(0, tbh, _dialogsWidth, height() - tbh);
+		if (hider) hider->setGeometry(QRect(0, 0, _dialogsWidth, height()));
+	}
 	_mediaType.move(width() - _mediaType.width(), st::topBarHeight);
-	history.setGeometry(_dialogsWidth, tbh, width() - _dialogsWidth, height() - tbh);
 	if (profile) profile->setGeometry(history.geometry());
 	if (overview) overview->setGeometry(history.geometry());
-	if (hider) hider->setGeometry(QRect(_dialogsWidth, 0, width() - _dialogsWidth, height()));
 }
 
 void MainWidget::keyPressEvent(QKeyEvent *e) {
 }
 
+void MainWidget::updateWideMode() {
+	showAll();
+}
+
+bool MainWidget::needBackButton() {
+	return overview || profile || (history.peer() && history.peer()->id);
+}
+
+void MainWidget::onTitleBack() {
+	showPeer(0, 0, false, true);
+}
+
 void MainWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) {
 	if (profile) {
 		profile->paintTopBar(p, over, decreaseWidth);
@@ -1574,6 +1774,12 @@ void MainWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) {
 	}
 }
 
+void MainWidget::topBarShadowParams(int32 &x, float64 &o) {
+	if (!profile && !overview && dialogs.isHidden()) {
+		history.topBarShadowParams(x, o);
+	}
+}
+
 void MainWidget::onPhotosSelect() {
 	if (overview) overview->switchType(OverviewPhotos);
 	_mediaType.hideStart();
@@ -1609,7 +1815,7 @@ void MainWidget::onTopBarClick() {
 }
 
 void MainWidget::onPeerShown(PeerData *peer) {
-	if (profile || overview || (peer && peer->id)) {
+	if ((cWideMode() || !selectingPeer()) && (profile || overview || (peer && peer->id))) {
 		_topBar.show();
 	} else {
 		_topBar.hide();
@@ -1840,6 +2046,12 @@ void MainWidget::start(const MTPUser &user) {
 		openLocalUrl(cStartUrl());
 		cSetStartUrl(QString());
 	}
+	_started = true;
+	App::wnd()->sendServiceHistoryRequest();
+}
+
+bool MainWidget::started() {
+	return _started;
 }
 
 void MainWidget::openLocalUrl(const QString &url) {
@@ -1992,10 +2204,7 @@ void MainWidget::activate() {
 			}
         } else if (App::wnd() && !App::wnd()->layerShown()) {
 			if (!cSendPaths().isEmpty()) {
-				hider = new HistoryHider(this);
-				hider->show();
-				resizeEvent(0);
-				dialogs.activate();
+				forwardLayer(-1);
 			} else if (history.peer()) {
 				history.activate();
 			} else {
@@ -2250,7 +2459,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 		UserData *user = App::userLoaded(d.vuser_id.v);
 		if (history && user) {
 			if (d.vaction.type() == mtpc_sendMessageTypingAction) {
-				dialogs.regTyping(history, user);
+				App::histories().regTyping(history, user);
 			} else if (d.vaction.type() == mtpc_sendMessageCancelAction) {
 				history->unregTyping(user);
 			}
@@ -2262,7 +2471,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 		History *history = App::historyLoaded(App::peerFromChat(d.vchat_id));
 		UserData *user = (d.vuser_id.v == MTP::authedId()) ? 0 : App::userLoaded(d.vuser_id.v);
 		if (history && user) {
-			dialogs.regTyping(history, user);
+			App::histories().regTyping(history, user);
 		}
 	} break;
 
@@ -2412,12 +2621,24 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 
 	case mtpc_updateNewAuthorization: {
 		const MTPDupdateNewAuthorization &d(update.c_updateNewAuthorization());
+		QDateTime datetime = date(d.vdate);
+		
+		QString text = lang(lng_new_authorization).replace(qsl("{name}"), App::self()->firstName);
+		text = text.replace(qsl("{day}"), langDayOfWeekFull(datetime.date()));
+		text = text.replace(qsl("{date}"), langDayOfMonth(datetime.date()));
+		text = text.replace(qsl("{time}"), datetime.time().toString(qsl("hh:mm")));
+		text = text.replace(qsl("{device}"), qs(d.vdevice));
+		text = text.replace(qsl("{location}"), qs(d.vlocation));
+		App::wnd()->serviceNotification(text);
 	} break;
 
 	case mtpc_updateServiceNotification: {
 		const MTPDupdateServiceNotification &d(update.c_updateServiceNotification());
 		if (d.vpopup.v) {
 			App::wnd()->showLayer(new ConfirmBox(qs(d.vmessage), true));
+			App::wnd()->serviceNotification(qs(d.vmessage), false, d.vmedia);
+		} else {
+			App::wnd()->serviceNotification(qs(d.vmessage), true, d.vmedia);
 		}
 	} break;
 
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index 94a24891d..772fed892 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -28,6 +28,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
 class Window;
 struct DialogRow;
 class MainWidget;
+class ConfirmBox;
 
 class TopBarWidget : public QWidget, public Animated {
 	Q_OBJECT
@@ -167,7 +168,12 @@ public:
 	void resizeEvent(QResizeEvent *e);
 	void keyPressEvent(QKeyEvent *e);
 
+	void updateWideMode();
+	bool needBackButton();
+	void onTitleBack();
+
 	void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
+	void topBarShadowParams(int32 &x, float64 &o);
 	TopBarWidget *topBar();
 
 	void animShow(const QPixmap &bgAnimCache, bool back = false);
@@ -177,6 +183,7 @@ public:
 	void openLocalUrl(const QString &str);
 	void openUserByName(const QString &name);
 	void startFull(const MTPVector<MTPUser> &users);
+	bool started();
 	void applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *history = 0);
 	void gotNotifySetting(MTPInputNotifyPeer peer, const MTPPeerNotifySettings &settings);
 	bool failNotifySetting(MTPInputNotifyPeer peer);
@@ -229,16 +236,16 @@ public:
 
 	int32 dlgsWidth() const;
 
-	void forwardLayer(bool forwardSelected = false);
+	void forwardLayer(int32 forwardSelected = 0); // -1 - send paths
 	void deleteLayer(int32 selectedCount = -1); // -1 - context item, else selected, -2 - cancel upload
 	void shareContactLayer(UserData *contact);
+	void hiderLayer(HistoryHider *h);
 	void noHider(HistoryHider *destroyed);
 	mtpRequestId onForward(const PeerId &peer, bool forwardSelected);
 	void onShareContact(const PeerId &peer, UserData *contact);
 	void onSendPaths(const PeerId &peer);
 	bool selectingPeer();
 	void offerPeer(PeerId peer);
-	void hidePeerSelect();
 	void focusPeerSelect();
 	void dialogsActivate();
 
@@ -290,6 +297,10 @@ public:
 	void showAddContact();
 	void showNewGroup();
 
+	void serviceNotification(const QString &msg, const MTPMessageMedia &media, bool unread);
+	void serviceHistoryDone(const MTPmessages_Messages &msgs);
+	bool serviceHistoryFail(const RPCError &error);
+
 	~MainWidget();
 
 signals:
@@ -337,11 +348,15 @@ public slots:
 	void onDocumentsSelect();
 	void onAudiosSelect();
 
+	void onForwardCancel(QObject *obj = 0);
+
 private:
 
     void partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result);
 	void photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req);
 
+	bool _started;
+
 	uint64 failedObjId;
 	QString failedFileName;
 	void loadFailed(mtpFileLoader *loader, bool started, const char *retrySlot);
@@ -375,12 +390,12 @@ private:
 
 	int32 _dialogsWidth;
 
-	MTPDuserSelf self;	
 	DialogsWidget dialogs;
 	HistoryWidget history;
 	ProfileWidget *profile;
 	OverviewWidget *overview;
 	TopBarWidget _topBar;
+	ConfirmBox *_forwardConfirm; // for narrow mode
 	HistoryHider *hider;
 	StackItems _stack;
 	QPixmap profileAnimCache;
diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp
index e5aa2c7a0..c6e4451d3 100644
--- a/Telegram/SourceFiles/pspecific_wnd.cpp
+++ b/Telegram/SourceFiles/pspecific_wnd.cpp
@@ -1047,8 +1047,8 @@ void PsMainWindow::psInitSize() {
 
 	TWindowPos pos(cWindowPos());
 	if (cDebug()) { // temp while design
-		pos.w = 879;
-		pos.h = 689;
+		pos.w = 800;
+		pos.h = 600;
 	}
 	QRect avail(QDesktopWidget().availableGeometry());
 	bool maximized = false;
diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp
index 9bbde503a..ea5b0dec1 100644
--- a/Telegram/SourceFiles/settings.cpp
+++ b/Telegram/SourceFiles/settings.cpp
@@ -99,6 +99,8 @@ QUrl gUpdateURL = QUrl(qsl("http://tdesktop.com/linux/tupdates/current"));
 
 bool gContactsReceived = false;
 
+bool gWideMode = true;
+
 void settingsParseArgs(int argc, char *argv[]) {
 	if (cPlatform() == dbipMac) {
 		gCustomNotifies = false;
diff --git a/Telegram/SourceFiles/settings.h b/Telegram/SourceFiles/settings.h
index 17f1343f5..90700a7da 100644
--- a/Telegram/SourceFiles/settings.h
+++ b/Telegram/SourceFiles/settings.h
@@ -161,4 +161,6 @@ DeclareReadSetting(QUrl, UpdateURL);
 
 DeclareSetting(bool, ContactsReceived);
 
+DeclareSetting(bool, WideMode);
+
 void settingsParseArgs(int argc, char *argv[]);
diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp
index 19d07fa0c..0da412e7e 100644
--- a/Telegram/SourceFiles/settingswidget.cpp
+++ b/Telegram/SourceFiles/settingswidget.cpp
@@ -1343,7 +1343,11 @@ void SettingsWidget::showAll() {
 	_scroll.show();
 	_inner.show();
 	_inner.showAll();
-	_close.show();
+	if (cWideMode()) {
+		_close.show();
+	} else {
+		_close.hide();
+	}
 }
 
 void SettingsWidget::hideAll() {
@@ -1364,6 +1368,14 @@ void SettingsWidget::dragEnterEvent(QDragEnterEvent *e) {
 void SettingsWidget::dropEvent(QDropEvent *e) {
 }
 
+void SettingsWidget::updateWideMode() {
+	if (cWideMode()) {
+		_close.show();
+	} else {
+		_close.hide();
+	}
+}
+
 void SettingsWidget::updateOnlineDisplay() {
 	_inner.updateOnlineDisplay();
 }
diff --git a/Telegram/SourceFiles/settingswidget.h b/Telegram/SourceFiles/settingswidget.h
index 8f73fa096..bd5d5a3ee 100644
--- a/Telegram/SourceFiles/settingswidget.h
+++ b/Telegram/SourceFiles/settingswidget.h
@@ -245,6 +245,8 @@ public:
 	void dragEnterEvent(QDragEnterEvent *e);
 	void dropEvent(QDropEvent *e);
 
+	void updateWideMode();
+
 	void animShow(const QPixmap &bgAnimCache, bool back = false);
 	bool animStep(float64 ms);
 
diff --git a/Telegram/SourceFiles/title.cpp b/Telegram/SourceFiles/title.cpp
index c7dab9e05..0570f255a 100644
--- a/Telegram/SourceFiles/title.cpp
+++ b/Telegram/SourceFiles/title.cpp
@@ -32,7 +32,7 @@ TitleHider::TitleHider(QWidget *parent) : QWidget(parent), _level(0) {
 void TitleHider::paintEvent(QPaintEvent *e) {
 	QPainter p(this);
 	p.setOpacity(_level * st::layerAlpha);
-	p.fillRect(App::main()->dlgsWidth() - 1, 0, width() - App::main()->dlgsWidth(), height(), st::layerBG->b);
+	p.fillRect(App::main()->dlgsWidth() - st::dlgShadow, 0, width() + st::dlgShadow - App::main()->dlgsWidth(), height(), st::layerBG->b);
 }
 
 void TitleHider::mousePressEvent(QMouseEvent *e) {
@@ -51,6 +51,8 @@ TitleWidget::TitleWidget(Window *window)
 	, wnd(window)
     , hideLevel(0)
     , hider(0)
+	, _back(this, st::titleBackButton)
+	, _cancel(this, lang(lng_cancel), st::titleTextButton)
 	, _settings(this, lang(lng_menu_settings), st::titleTextButton)
 	, _contacts(this, lang(lng_menu_contacts), st::titleTextButton)
 	, _about(this, lang(lng_menu_about), st::titleTextButton)
@@ -61,7 +63,6 @@ TitleWidget::TitleWidget(Window *window)
 	, _close(this, window)
     , lastMaximized(!(window->windowState() & Qt::WindowMaximized))
 {
-
 	setGeometry(0, 0, wnd->width(), st::titleHeight);
 	_update.hide();
 	if (App::app()->updatingState() == Application::UpdatingReady) {
@@ -69,6 +70,8 @@ TitleWidget::TitleWidget(Window *window)
 	}
 	stateChanged();
 
+	connect(&_back, SIGNAL(clicked()), window, SLOT(onTitleBack()));
+	connect(&_cancel, SIGNAL(clicked()), this, SIGNAL(hiderClicked()));
 	connect(&_settings, SIGNAL(clicked()), window, SLOT(showSettings()));
 	connect(&_contacts, SIGNAL(clicked()), this, SLOT(onContacts()));
 	connect(&_about, SIGNAL(clicked()), this, SLOT(onAbout()));
@@ -87,6 +90,11 @@ void TitleWidget::paintEvent(QPaintEvent *e) {
 	QPainter p(this);
 
 	p.fillRect(QRect(0, 0, width(), st::titleHeight), st::titleBG->b);
+	if (!_cancel.isHidden()) {
+		p.setPen(st::titleTextButton.color->p);
+		p.setFont(st::titleTextButton.font->f);
+		p.drawText(st::titleMenuOffset - st::titleTextButton.width / 2, st::titleTextButton.textTop + st::titleTextButton.font->ascent, lang(lng_forward_choose));
+	}
 	p.drawPixmap(st::titleIconPos, App::sprite(), st::titleIconRect);
 }
 
@@ -105,7 +113,11 @@ void TitleWidget::setHideLevel(float64 level) {
 				hider = new TitleHider(this);
 				hider->move(0, 0);
 				hider->resize(size());
-				hider->show();
+				if (cWideMode()) {
+					hider->show();
+				} else {
+					hider->hide();
+				}
 			}
 			hider->setLevel(hideLevel);
 		} else {
@@ -140,6 +152,7 @@ void TitleWidget::resizeEvent(QResizeEvent *e) {
 		_update.move(p);
 		p.setX(p.x() + _update.width());
 	}
+	_cancel.move(p.x() - _cancel.width(), 0);
 
     if (cPlatform() == dbipWindows) {
         p.setX(p.x() - _close.width());
@@ -153,18 +166,67 @@ void TitleWidget::resizeEvent(QResizeEvent *e) {
     }
     
 	_settings.move(st::titleMenuOffset, 0);
-	if (MTP::authedId()) {
+	_back.move(st::titleMenuOffset, 0);
+	if (MTP::authedId() && _back.isHidden() && _cancel.isHidden()) {
 		_contacts.show();
 		_contacts.move(_settings.x() + _settings.width(), 0);
 		_about.move(_contacts.x() + _contacts.width(), 0);
 	} else {
 		_contacts.hide();
-		_about.move(_settings.x() + _settings.width(), 0);
+		if (!MTP::authedId()) _about.move(_settings.x() + _settings.width(), 0);
 	}
 
 	if (hider) hider->resize(size());
 }
 
+void TitleWidget::updateBackButton(int authedChanged) {
+	if (!cWideMode() && App::main() && App::main()->selectingPeer()) {
+		_cancel.show();
+		if (!_back.isHidden()) _back.hide();
+		_settings.hide();
+		_contacts.hide();
+		_about.hide();
+	} else {
+		_cancel.hide();
+		bool authed = authedChanged ? (authedChanged > 0) : (MTP::authedId() > 0);
+		if (authedChanged) {
+			_back.setText(lang((authedChanged > 0) ? lng_menu_conversations : lng_menu_start_messaging));
+		}
+		if (cWideMode()) {
+			if (!_back.isHidden()) _back.hide();
+			_settings.show();
+			if (authed) _contacts.show();
+			_about.show();
+		} else {
+			bool need = App::wnd()->needBackButton();
+			if (need && _back.isHidden()) {
+				_back.show();
+				_settings.hide();
+				_contacts.hide();
+				_about.hide();
+			} else if (!need && !_back.isHidden()) {
+				_back.hide();
+				_settings.show();
+				if (authed) _contacts.show();
+				_about.show();
+			}
+		}
+	}
+	showUpdateBtn();
+	update();
+}
+
+void TitleWidget::updateWideMode() {
+	updateBackButton();
+	if (hider) {
+		if (cWideMode()) {
+			hider->show();
+		} else {
+			hider->hide();
+		}
+	}
+}
+
 void TitleWidget::mousePressEvent(QMouseEvent *e) {
 	if (wnd->psHandleTitle()) return;
 	if (e->buttons() & Qt::LeftButton) {
@@ -189,6 +251,15 @@ void TitleWidget::stateChanged(Qt::WindowState state) {
 }
 
 void TitleWidget::showUpdateBtn() {
+	if (!cWideMode() && App::main() && App::main()->selectingPeer()) {
+		_cancel.show();
+		_update.hide();
+		_minimize.hide();
+		_restore.hide();
+		_maximize.hide();
+		_close.hide();
+		return;
+	}
 	bool updateReady = App::app()->updatingState() == Application::UpdatingReady;
 	if (updateReady || cEvalScale(cConfigScale()) != cEvalScale(cRealScale())) {
 		_update.setText(lang(updateReady ? lng_menu_update : lng_menu_restart));
@@ -234,7 +305,7 @@ HitTestType TitleWidget::hitTest(const QPoint &p) {
 	if (App::wnd() && App::wnd()->layerShown()) return HitTestNone;
 
 	int x(p.x()), y(p.y()), w(width()), h(height() - st::titleShadow);
-	if (hider && x >= App::main()->dlgsWidth()) return HitTestNone;
+	if (cWideMode() && hider && x >= App::main()->dlgsWidth()) return HitTestNone;
 
 	if (x >= st::titleIconPos.x() && y >= st::titleIconPos.y() && x < st::titleIconPos.x() + st::titleIconRect.pxWidth() && y < st::titleIconPos.y() + st::titleIconRect.pxHeight()) {
 		return HitTestIcon;
@@ -248,9 +319,11 @@ HitTestType TitleWidget::hitTest(const QPoint &p) {
 		return HitTestSysButton;
 	} else if (x >= 0 && x < w && y >= 0 && y < h) {
 		if (false
-			|| _settings.geometry().contains(x, y)
+			|| (!_back.isHidden() && _back.geometry().contains(x, y))
+			|| (!_cancel.isHidden() && _cancel.geometry().contains(x, y))
+			|| (!_settings.isHidden() && _settings.geometry().contains(x, y))
 			|| (!_contacts.isHidden() && _contacts.geometry().contains(x, y))
-			|| _about.geometry().contains(x, y)
+			|| (!_about.isHidden() && _about.geometry().contains(x, y))
 		) {
 			return HitTestClient;
 		}
diff --git a/Telegram/SourceFiles/title.h b/Telegram/SourceFiles/title.h
index 4e4bc9cb0..d9fde83d4 100644
--- a/Telegram/SourceFiles/title.h
+++ b/Telegram/SourceFiles/title.h
@@ -45,6 +45,9 @@ public:
 	void paintEvent(QPaintEvent *e);
 	void resizeEvent(QResizeEvent *e);
 
+	void updateBackButton(int authedChanged = 0);
+	void updateWideMode();
+
 	void mousePressEvent(QMouseEvent *e);
 	void mouseDoubleClickEvent(QMouseEvent *e);
 
@@ -80,7 +83,8 @@ private:
 
 	float64 _lastUpdateMs;
 
-	FlatButton _settings, _contacts, _about;
+	MaskedButton _back;
+	FlatButton _cancel, _settings, _contacts, _about;
 
 	UpdateBtn _update;
 	MinimizeBtn _minimize;
diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp
index 66d3cc4ac..5524a7b48 100644
--- a/Telegram/SourceFiles/window.cpp
+++ b/Telegram/SourceFiles/window.cpp
@@ -331,7 +331,7 @@ NotifyWindow::~NotifyWindow() {
 
 Window::Window(QWidget *parent) : PsMainWindow(parent),
 intro(0), main(0), settings(0), layerBG(0), _topWidget(0),
-_connecting(0), _clearManager(0), dragging(false), _inactivePress(false), _mediaView(0) {
+_connecting(0), _clearManager(0), dragging(false), _inactivePress(false), _mediaView(0), _serviceHistoryRequest(0) {
 
 	icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation);
 	icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation);
@@ -438,6 +438,7 @@ void Window::clearWidgets() {
 
 void Window::setupIntro(bool anim) {
 	cSetContactsReceived(false);
+	title->updateBackButton(false);
 	if (intro && (intro->animating() || intro->isVisible()) && !main) return;
 
 	QPixmap bg = myGrab(this, QRect(0, st::titleHeight, width(), height() - st::titleHeight));
@@ -452,13 +453,49 @@ void Window::setupIntro(bool anim) {
 	fixOrder();
 
 	updateTitleStatus();
+
+	_delayedServiceMsgs.clear();
+	if (_serviceHistoryRequest) {
+		MTP::cancel(_serviceHistoryRequest);
+		_serviceHistoryRequest = 0;
+	}
 }
 
 void Window::getNotifySetting(const MTPInputNotifyPeer &peer, uint32 msWait) {
 	MTP::send(MTPaccount_GetNotifySettings(peer), main->rpcDone(&MainWidget::gotNotifySetting, peer), main->rpcFail(&MainWidget::failNotifySetting, peer), 0, msWait);
 }
 
+void Window::serviceNotification(const QString &msg, bool unread, const MTPMessageMedia &media, bool force) {
+	History *h = (main && App::userLoaded(ServiceUserId)) ? App::history(ServiceUserId) : 0;
+	if (!h || (!force && h->isEmpty())) {
+		_delayedServiceMsgs.push_back(DelayedServiceMsg(qMakePair(msg, media), unread));
+		return sendServiceHistoryRequest();
+	}
+
+	main->serviceNotification(msg, media, unread);
+}
+
+void Window::showDelayedServiceMsgs() {
+	QVector<DelayedServiceMsg> toAdd = _delayedServiceMsgs;
+	_delayedServiceMsgs.clear();
+	for (QVector<DelayedServiceMsg>::const_iterator i = toAdd.cbegin(), e = toAdd.cend(); i != e; ++i) {
+		serviceNotification(i->first.first, i->second, i->first.second, true);
+	}
+}
+
+void Window::sendServiceHistoryRequest() {
+	if (!main || !main->started() || _delayedServiceMsgs.isEmpty() || _serviceHistoryRequest) return;
+
+	UserData *user = App::userLoaded(ServiceUserId);
+	if (!user) {
+		user = App::feedUsers(MTP_vector<MTPUser>(1, MTP_userRequest(MTP_int(ServiceUserId), MTP_string("Telegram"), MTP_string(""), MTP_string(""), MTP_long(-1), MTP_string("42777"), MTP_userProfilePhotoEmpty(), MTP_userStatusRecently())));
+	}
+	_serviceHistoryRequest = MTP::send(MTPmessages_GetHistory(user->input, MTP_int(0), MTP_int(0), MTP_int(1)), main->rpcDone(&MainWidget::serviceHistoryDone), main->rpcFail(&MainWidget::serviceHistoryFail));
+}
+
 void Window::setupMain(bool anim) {
+	title->updateBackButton(true);
+
 	QPixmap bg = myGrab(this, QRect(0, st::titleHeight, width(), height() - st::titleHeight));
 	clearWidgets();
 	main = new MainWidget(this);
@@ -477,6 +514,15 @@ void Window::setupMain(bool anim) {
 	_mediaView = new MediaView();
 }
 
+void Window::onTitleBack() {
+	if (main) {
+		main->onTitleBack();
+	}
+	if (settings) {
+		hideSettings();
+	}
+}
+
 void Window::showSettings() {
 	if (isHidden()) showFromTray();
 
@@ -495,6 +541,7 @@ void Window::showSettings() {
 	}
 	settings = new SettingsWidget(this);
 	settings->animShow(bg);
+	title->updateBackButton();
 
 	fixOrder();
 }
@@ -527,6 +574,7 @@ void Window::hideSettings(bool fast) {
 			main->animShow(bg, true);
 		}
 	}
+	title->updateBackButton();
 
 	fixOrder();
 }
@@ -594,9 +642,12 @@ void Window::showDocument(DocumentData *doc, QPixmap pix, HistoryItem *item) {
 	_mediaView->setFocus();
 }
 
-void Window::showLayer(LayeredWidget *w) {
+void Window::showLayer(LayeredWidget *w, bool fast) {
 	layerHidden();
 	layerBG = new BackgroundWidget(this, w);
+	if (fast) {
+		layerBG->showFast();
+	}
 }
 
 void Window::showConnecting(const QString &text, const QString &reconnect) {
@@ -631,9 +682,13 @@ void Window::replaceLayer(LayeredWidget *w) {
 	}
 }
 
-void Window::hideLayer() {
+void Window::hideLayer(bool fast) {
 	if (layerBG) {
 		layerBG->onClose();
+		if (fast) {
+			layerBG->hide();
+			layerBG = 0;
+		}
 	}
 	if (_mediaView && !_mediaView->isHidden()) {
 		_mediaView->hide();
@@ -663,7 +718,10 @@ void Window::checkHistoryActivation(int state) {
 }
 
 void Window::layerHidden() {
-	if (layerBG) layerBG->deleteLater();
+	if (layerBG) {
+		layerBG->hide();
+		layerBG->deleteLater();
+	}
 	layerBG = 0;
 	if (_mediaView && !_mediaView->isHidden()) _mediaView->hide();
 	if (main) main->setInnerFocus();
@@ -903,6 +961,12 @@ void Window::noBox(BackgroundWidget *was) {
 	}
 }
 
+void Window::layerFinishedHide(BackgroundWidget *was) {
+	if (was == layerBG) {
+		QTimer::singleShot(0, this, SLOT(layerHidden()));
+	}
+}
+
 void Window::fixOrder() {
 	title->raise();
 	if (layerBG) layerBG->raise();
@@ -957,12 +1021,29 @@ TitleWidget *Window::getTitle() {
 }
 
 void Window::resizeEvent(QResizeEvent *e) {
+	bool wideMode = (width() >= st::wideModeWidth);
+	if (wideMode != cWideMode()) {
+		cSetWideMode(wideMode);
+		updateWideMode();
+	}
 	title->setGeometry(QRect(0, 0, width(), st::titleHeight + st::titleShadow));
 	if (layerBG) layerBG->resize(width(), height());
 	if (_connecting) _connecting->setGeometry(0, height() - _connecting->height(), _connecting->width(), _connecting->height());
 	emit resized(QSize(width(), height() - st::titleHeight));
 }
 
+void Window::updateWideMode() {
+	title->updateWideMode();
+	if (main) main->updateWideMode();
+	if (settings) settings->updateWideMode();
+	if (intro) intro->updateWideMode();
+	if (layerBG) layerBG->updateWideMode();
+}
+
+bool Window::needBackButton() {
+	return settings || (main && main->needBackButton());
+}
+
 Window::TempDirState Window::tempDirState() {
 	if (_clearManager && _clearManager->hasTask(Local::ClearManagerDownloads)) {
 		return TempDirRemoving;
diff --git a/Telegram/SourceFiles/window.h b/Telegram/SourceFiles/window.h
index 5331dcd21..45781f33f 100644
--- a/Telegram/SourceFiles/window.h
+++ b/Telegram/SourceFiles/window.h
@@ -140,11 +140,16 @@ public:
 	void paintEvent(QPaintEvent *e);
 
 	void resizeEvent(QResizeEvent *e);
+	void updateWideMode();
+	bool needBackButton();
 
 	void setupIntro(bool anim);
 	void setupMain(bool anim);
 	void startMain(const MTPUser &user);
 	void getNotifySetting(const MTPInputNotifyPeer &peer, uint32 msWait = 0);
+	void serviceNotification(const QString &msg, bool unread = true, const MTPMessageMedia &media = MTP_messageMediaEmpty(), bool force = false);
+	void sendServiceHistoryRequest();
+	void showDelayedServiceMsgs();
 
 	void mtpStateChanged(int32 dc, int32 state);
 
@@ -169,9 +174,9 @@ public:
 	void showPhoto(PhotoData *photo, HistoryItem *item);
 	void showPhoto(PhotoData *photo, PeerData *item);
 	void showDocument(DocumentData *doc, QPixmap pix, HistoryItem *item);
-	void showLayer(LayeredWidget *w);
+	void showLayer(LayeredWidget *w, bool fast = false);
 	void replaceLayer(LayeredWidget *w);
-	void hideLayer();
+	void hideLayer(bool fast = false);
 	bool hideInnerLayer();
 
 	bool layerShown();
@@ -184,6 +189,7 @@ public:
 	void noSettings(SettingsWidget *was);
 	void noMain(MainWidget *was);
 	void noBox(BackgroundWidget *was);
+	void layerFinishedHide(BackgroundWidget *was);
 
 	void topWidget(QWidget *w);
 	void noTopWidget(QWidget *w);
@@ -224,6 +230,8 @@ public slots:
 	
 	void checkHistoryActivation(int state = -1);
     
+	void onTitleBack();
+
 	void showSettings();
 	void layerHidden();
 	void updateTitleStatus();
@@ -265,6 +273,10 @@ private:
 
 	QWidget *centralwidget;
 
+	typedef QPair<QPair<QString, MTPMessageMedia>, bool> DelayedServiceMsg;
+	QVector<DelayedServiceMsg> _delayedServiceMsgs;
+	mtpRequestId _serviceHistoryRequest;
+
 	TitleWidget *title;
 	IntroWidget *intro;
 	MainWidget *main;
diff --git a/Telegram/Telegram.plist b/Telegram/Telegram.plist
index 5fdec5450..4b2119d65 100644
--- a/Telegram/Telegram.plist
+++ b/Telegram/Telegram.plist
@@ -11,7 +11,7 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>0.6.17</string>
+	<string>0.6.18</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleURLTypes</key>
diff --git a/Telegram/Telegram.rc b/Telegram/Telegram.rc
index 08e08a47a..e0c0581a5 100644
Binary files a/Telegram/Telegram.rc and b/Telegram/Telegram.rc differ
diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj
index aef9eae91..579b5d5b0 100644
--- a/Telegram/Telegram.xcodeproj/project.pbxproj
+++ b/Telegram/Telegram.xcodeproj/project.pbxproj
@@ -1577,7 +1577,7 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 0.6.17;
+				CURRENT_PROJECT_VERSION = 0.6.18;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
 				GCC_OPTIMIZATION_LEVEL = 0;
@@ -1595,7 +1595,7 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				COPY_PHASE_STRIP = YES;
-				CURRENT_PROJECT_VERSION = 0.6.17;
+				CURRENT_PROJECT_VERSION = 0.6.18;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
 				GCC_OPTIMIZATION_LEVEL = fast;
 				GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@@ -1621,10 +1621,10 @@
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				CODE_SIGN_IDENTITY = "";
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 0.6.17;
+				CURRENT_PROJECT_VERSION = 0.6.18;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DYLIB_COMPATIBILITY_VERSION = 0.6;
-				DYLIB_CURRENT_VERSION = 0.6.17;
+				DYLIB_CURRENT_VERSION = 0.6.18;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@@ -1764,10 +1764,10 @@
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				CODE_SIGN_IDENTITY = "";
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 0.6.17;
+				CURRENT_PROJECT_VERSION = 0.6.18;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DYLIB_COMPATIBILITY_VERSION = 0.6;
-				DYLIB_CURRENT_VERSION = 0.6.17;
+				DYLIB_CURRENT_VERSION = 0.6.18;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				FRAMEWORK_SEARCH_PATHS = "";
 				GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
diff --git a/Telegram/Version.sh b/Telegram/Version.sh
index a410a845f..a373be447 100755
--- a/Telegram/Version.sh
+++ b/Telegram/Version.sh
@@ -1,2 +1,2 @@
-echo 6017 0.6.17
+echo 6018 0.6.18