From 10aa210e04bed4a8ab399a28c1aba1ffe7616edf Mon Sep 17 00:00:00 2001
From: Vadim Savchuk <vsavchuk@productengine.com>
Date: Wed, 28 Oct 2009 23:59:51 +0200
Subject: [PATCH] Partial implementation of normal priority task EXT-1096
 (Implement recent time in recent people list). - Implemented display of last
 interaction time (e.g. 5m, 3d, 10w). - Removed dead code for displaying
 avatar away/busy status. TODO: i18n, visual fixes.

--HG--
branch : product-engine
---
 indra/newview/llavatarlist.cpp                | 76 ++++++++++++++++++-
 indra/newview/llavatarlist.h                  |  8 +-
 indra/newview/llavatarlistitem.cpp            | 50 +++++-------
 indra/newview/llavatarlistitem.h              |  6 +-
 indra/newview/llchiclet.cpp                   |  2 +-
 .../default/xui/en/panel_avatar_list_item.xml | 11 +--
 .../skins/default/xui/en/panel_people.xml     |  1 +
 7 files changed, 114 insertions(+), 40 deletions(-)

diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index e93d0dfa50d..05a1f75e01c 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -37,11 +37,15 @@
 // newview
 #include "llcallingcard.h" // for LLAvatarTracker
 #include "llcachename.h"
+#include "llrecentpeople.h"
 #include "llvoiceclient.h"
 #include "llviewercontrol.h"	// for gSavedSettings
 
 static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list");
 
+// Last interaction time update period.
+static const F32 LIT_UPDATE_PERIOD = 5;
+
 // Maximum number of avatars that can be added to a list in one pass.
 // Used to limit time spent for avatar list update per frame.
 static const unsigned ADD_LIMIT = 50;
@@ -74,19 +78,35 @@ static const LLFlatListView::ItemReverseComparator REVERSE_NAME_COMPARATOR(NAME_
 
 LLAvatarList::Params::Params()
 : ignore_online_status("ignore_online_status", false)
+, show_last_interaction_time("show_last_interaction_time", false)
 {
 }
 
 LLAvatarList::LLAvatarList(const Params& p)
 :	LLFlatListView(p)
 , mIgnoreOnlineStatus(p.ignore_online_status)
+, mShowLastInteractionTime(p.show_last_interaction_time)
 , mContextMenu(NULL)
 , mDirty(true) // to force initial update
+, mLITUpdateTimer(NULL)
 {
 	setCommitOnSelectionChange(true);
 
 	// Set default sort order.
 	setComparator(&NAME_COMPARATOR);
+
+	if (mShowLastInteractionTime)
+	{
+		mLITUpdateTimer = new LLTimer();
+		mLITUpdateTimer->setTimerExpirySec(0); // zero to force initial update
+		mLITUpdateTimer->start();
+	}
+}
+
+LLAvatarList::~LLAvatarList()
+{
+	delete mLITUpdateTimer;
+	mShowIcons = gSavedSettings.getBOOL(mIconParamName);
 }
 
 void LLAvatarList::setShowIcons(std::string param_name)
@@ -105,6 +125,12 @@ void LLAvatarList::draw()
 
 	if (mDirty)
 		refresh();
+
+	if (mShowLastInteractionTime && mLITUpdateTimer->hasExpired())
+	{
+		updateLastInteractionTimes();
+		mLITUpdateTimer->setTimerExpirySec(LIT_UPDATE_PERIOD); // restart the timer
+	}
 }
 
 void LLAvatarList::setNameFilter(const std::string& filter)
@@ -218,12 +244,12 @@ void LLAvatarList::refresh()
 void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_online, EAddPosition pos)
 {
 	LLAvatarListItem* item = new LLAvatarListItem();
-	item->showStatus(false);
 	item->showInfoBtn(true);
 	item->showSpeakingIndicator(true);
 	item->setName(name);
 	item->setAvatarId(id, mIgnoreOnlineStatus);
 	item->setOnline(mIgnoreOnlineStatus ? true : is_online);
+	item->showLastInteractionTime(mShowLastInteractionTime);
 	item->setContextMenu(mContextMenu);
 
 	item->childSetVisible("info_btn", false);
@@ -279,6 +305,54 @@ void LLAvatarList::computeDifference(
 	vadded.erase(it, vadded.end());
 }
 
+static std::string format_secs(S32 secs)
+{
+	// *TODO: reinventing the wheel?
+	// *TODO: i18n
+	static const int LL_AL_MIN		= 60;
+	static const int LL_AL_HOUR		= LL_AL_MIN * 60;
+	static const int LL_AL_DAY		= LL_AL_HOUR * 24;
+	static const int LL_AL_WEEK		= LL_AL_DAY * 7;
+	static const int LL_AL_MONTH	= LL_AL_DAY * 31;
+	static const int LL_AL_YEAR		= LL_AL_DAY * 365;
+
+    std::string s;
+
+    if (secs >= LL_AL_YEAR)
+        s = llformat("%dy", secs / LL_AL_YEAR);
+    else if (secs >= LL_AL_MONTH)
+        s = llformat("%dmon", secs / LL_AL_MONTH);
+    else if (secs >= LL_AL_WEEK)
+        s = llformat("%dw", secs / LL_AL_WEEK);
+    else if (secs >= LL_AL_DAY)
+        s = llformat("%dd", secs / LL_AL_DAY);
+    else if (secs >= LL_AL_HOUR)
+        s = llformat("%dh", secs / LL_AL_HOUR);
+    else if (secs >= LL_AL_MIN)
+        s = llformat("%dm", secs / LL_AL_MIN);
+    else
+        s = llformat("%ds", secs);
+
+    return s;
+}
+
+// Refresh shown time of our last interaction with all listed avatars.
+void LLAvatarList::updateLastInteractionTimes()
+{
+	S32 now = (S32) LLDate::now().secondsSinceEpoch();
+	std::vector<LLPanel*> items;
+	getItems(items);
+
+	for( std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++)
+	{
+		// *TODO: error handling
+		LLAvatarListItem* item = static_cast<LLAvatarListItem*>(*it);
+		S32 secs_since = now - (S32) LLRecentPeople::instance().getDate(item->getAvatarId()).secondsSinceEpoch();
+		if (secs_since >= 0)
+			item->setLastInteractionTime(format_secs(secs_since));
+	}
+}
+
 bool LLAvatarItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const
 {
 	const LLAvatarListItem* avatar_item1 = dynamic_cast<const LLAvatarListItem*>(item1);
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index f60f1f00f33..8f2f0249a61 100644
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -37,6 +37,8 @@
 
 #include "llavatarlistitem.h"
 
+class LLTimer;
+
 /**
  * Generic list of avatars.
  * 
@@ -56,11 +58,12 @@ class LLAvatarList : public LLFlatListView
 	struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> 
 	{
 		Optional<bool> ignore_online_status; // show all items as online
+		Optional<bool> show_last_interaction_time; // show most recent interaction time. *HACK: move this to a derived class
 		Params();
 	};
 
 	LLAvatarList(const Params&);
-	virtual	~LLAvatarList() {}
+	virtual	~LLAvatarList();
 
 	virtual void draw(); // from LLView
 
@@ -85,13 +88,16 @@ class LLAvatarList : public LLFlatListView
 		const std::vector<LLUUID>& vnew,
 		std::vector<LLUUID>& vadded,
 		std::vector<LLUUID>& vremoved);
+	void updateLastInteractionTimes();
 
 private:
 
 	bool mIgnoreOnlineStatus;
+	bool mShowLastInteractionTime;
 	bool mDirty;
 	bool mShowIcons;
 
+	LLTimer*				mLITUpdateTimer; // last interaction time update timer
 	std::string				mIconParamName;
 	std::string				mNameFilter;
 	uuid_vector_t			mIDs;
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index 4ecb9537ba8..84644305017 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -48,7 +48,7 @@ LLAvatarListItem::LLAvatarListItem()
 :	LLPanel(),
 	mAvatarIcon(NULL),
 	mAvatarName(NULL),
-	mStatus(NULL),
+	mLastInteractionTime(NULL),
 	mSpeakingIndicator(NULL),
 	mInfoBtn(NULL),
 	mProfileBtn(NULL),
@@ -74,8 +74,8 @@ BOOL  LLAvatarListItem::postBuild()
 {
 	mAvatarIcon = getChild<LLAvatarIconCtrl>("avatar_icon");
 	mAvatarName = getChild<LLTextBox>("avatar_name");
-	mStatus = getChild<LLTextBox>("avatar_status");
-
+	mLastInteractionTime = getChild<LLTextBox>("last_interaction");
+	
 	mSpeakingIndicator = getChild<LLOutputMonitorCtrl>("speaking_indicator");
 	mInfoBtn = getChild<LLButton>("info_btn");
 	mProfileBtn = getChild<LLButton>("profile_btn");
@@ -97,12 +97,6 @@ BOOL  LLAvatarListItem::postBuild()
 		rect.setLeftTopAndSize(mName->getRect().mLeft, mName->getRect().mTop, mName->getRect().getWidth() + 30, mName->getRect().getHeight());
 		mName->setRect(rect);
 
-		if(mStatus)
-		{
-			rect.setLeftTopAndSize(mStatus->getRect().mLeft + 30, mStatus->getRect().mTop, mStatus->getRect().getWidth(), mStatus->getRect().getHeight());
-			mStatus->setRect(rect);
-		}
-
 		if(mLocator)
 		{
 			rect.setLeftTopAndSize(mLocator->getRect().mLeft + 30, mLocator->getRect().mTop, mLocator->getRect().getWidth(), mLocator->getRect().getHeight());
@@ -137,11 +131,6 @@ void LLAvatarListItem::onMouseLeave(S32 x, S32 y, MASK mask)
 	LLPanel::onMouseLeave(x, y, mask);
 }
 
-void LLAvatarListItem::setStatus(const std::string& status)
-{
-	mStatus->setValue(status);
-}
-
 // virtual, called by LLAvatarTracker
 void LLAvatarListItem::changed(U32 mask)
 {
@@ -195,6 +184,24 @@ void LLAvatarListItem::setAvatarId(const LLUUID& id, bool ignore_status_changes)
 	gCacheName->get(id, FALSE, boost::bind(&LLAvatarListItem::onNameCache, this, _2, _3));
 }
 
+void LLAvatarListItem::showLastInteractionTime(bool show)
+{
+	if (show)
+		return;
+
+	LLRect	name_rect	= mAvatarName->getRect();
+	LLRect	time_rect	= mLastInteractionTime->getRect();
+
+	mLastInteractionTime->setVisible(false);
+	name_rect.mRight += (time_rect.mRight - name_rect.mRight);
+	mAvatarName->setRect(name_rect);
+}
+
+void LLAvatarListItem::setLastInteractionTime(const std::string& val)
+{
+	mLastInteractionTime->setValue(val);
+}
+
 void LLAvatarListItem::setAvatarIconVisible(bool visible)
 {
 	// Already done? Then do nothing.
@@ -240,21 +247,6 @@ void LLAvatarListItem::onProfileBtnClick()
 	LLAvatarActions::showProfile(mAvatarId);
 }
 
-void LLAvatarListItem::showStatus(bool show_status)
-{
-	// *HACK: dirty hack until we can determine correct avatar status (EXT-1076).
-
-	if (show_status)
-		return;
-
-	LLRect	name_rect	= mAvatarName->getRect();
-	LLRect	status_rect	= mStatus->getRect();
-
-	mStatus->setVisible(show_status);
-	name_rect.mRight += (status_rect.mRight - name_rect.mRight);
-	mAvatarName->setRect(name_rect);
-}
-
 void LLAvatarListItem::setValue( const LLSD& value )
 {
 	if (!value.isMap()) return;;
diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h
index a8d39192176..10c0b17005f 100644
--- a/indra/newview/llavatarlistitem.h
+++ b/indra/newview/llavatarlistitem.h
@@ -60,10 +60,10 @@ class LLAvatarListItem : public LLPanel, public LLFriendObserver
 	virtual void setValue(const LLSD& value);
 	virtual void changed(U32 mask); // from LLFriendObserver
 
-	void setStatus(const std::string& status);
 	void setOnline(bool online);
 	void setName(const std::string& name);
 	void setAvatarId(const LLUUID& id, bool ignore_status_changes = false);
+	void setLastInteractionTime(const std::string& val);
 	void setAvatarIconVisible(bool visible);
 	
 	const LLUUID& getAvatarId() const;
@@ -74,7 +74,7 @@ class LLAvatarListItem : public LLPanel, public LLFriendObserver
 
 	void showSpeakingIndicator(bool show) { mSpeakingIndicator->setVisible(show); }
 	void showInfoBtn(bool show_info_btn) {mInfoBtn->setVisible(show_info_btn); }
-	void showStatus(bool show_status);
+	void showLastInteractionTime(bool show);
 
 	void setContextMenu(ContextMenu* menu) { mContextMenu = menu; }
 
@@ -90,7 +90,7 @@ class LLAvatarListItem : public LLPanel, public LLFriendObserver
 
 	LLAvatarIconCtrl* mAvatarIcon;
 	LLTextBox* mAvatarName;
-	LLTextBox* mStatus;
+	LLTextBox* mLastInteractionTime;
 	
 	LLOutputMonitorCtrl* mSpeakingIndicator;
 	LLButton* mInfoBtn;
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 61a60a24be6..4ff360cd74d 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -1398,7 +1398,7 @@ void LLTalkButton::onClick_ShowBtn()
 
 
 	LLAvatarListItem* item = new LLAvatarListItem();
-	item->showStatus(true);
+	item->showLastInteractionTime(false);
 	item->showInfoBtn(true);
 	item->showSpeakingIndicator(true);
 	item->reshape(mPrivateCallPanel->getRect().getWidth(), item->getRect().getHeight(), FALSE);
diff --git a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
index f747c557e22..8aaa462aaf0 100644
--- a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
@@ -47,17 +47,17 @@
      top="6"
      use_ellipses="true"
      value="Unknown"
-     width="166" />
+     width="196" />
     <text
-     follows="left"
+     follows="right"
      font="SansSerifSmall"
      height="15"
      layout="topleft"
      left_pad="10"
-     name="avatar_status"
+     name="last_interaction"
      text_color="LtGray_50"
-     value="Away"
-     width="50" />
+     value="0s"
+     width="24" />
     <output_monitor
      auto_update="true"
      follows="right"
@@ -75,6 +75,7 @@
      image_pressed="Info_Press"
      image_hover="Info_Over"
      image_unselected="Info_Off"
+     layout="topleft"
      left_pad="3"
      right="-25"
      name="info_btn"
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 7b19ab1a1cb..ec6377c7237 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -301,6 +301,7 @@ background_visible="true"
              left="0"
              multi_select="true"
              name="avatar_list"
+             show_last_interaction_time="true"
              top="2"
              width="313" />
             <panel
-- 
GitLab