diff options
-rwxr-xr-x | indra/newview/CMakeLists.txt | 2 | ||||
-rwxr-xr-x | indra/newview/llfloatersnapshot.cpp | 8 | ||||
-rw-r--r-- | indra/newview/llfloatertwitter.cpp | 669 | ||||
-rw-r--r-- | indra/newview/llfloatertwitter.h | 122 | ||||
-rw-r--r-- | indra/newview/llsnapshotlivepreview.cpp | 3 | ||||
-rw-r--r-- | indra/newview/lltwitterconnect.cpp | 3 | ||||
-rwxr-xr-x | indra/newview/llviewerfloaterreg.cpp | 2 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_twitter.xml | 89 | ||||
-rwxr-xr-x | indra/newview/skins/default/xui/en/menu_viewer.xml | 11 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/panel_twitter_account.xml | 75 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/panel_twitter_photo.xml | 152 | ||||
-rwxr-xr-x | indra/newview/skins/default/xui/en/strings.xml | 8 |
12 files changed, 1137 insertions, 7 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 226c739e48..746991a6f0 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -288,6 +288,7 @@ set(viewer_SOURCE_FILES llfloatertos.cpp llfloatertoybox.cpp llfloatertranslationsettings.cpp + llfloatertwitter.cpp llfloateruipreview.cpp llfloaterurlentry.cpp llfloatervoiceeffect.cpp @@ -879,6 +880,7 @@ set(viewer_HEADER_FILES llfloatertos.h llfloatertoybox.h llfloatertranslationsettings.h + llfloatertwitter.h llfloateruipreview.h llfloaterurlentry.h llfloatervoiceeffect.h diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index fa92ed094b..4701e128d3 100755 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -33,6 +33,7 @@ #include "llfloaterreg.h" #include "llfloatersocial.h" #include "llfloaterflickr.h" +#include "llfloatertwitter.h" #include "llcheckboxctrl.h" #include "llcombobox.h" #include "llpostcard.h" @@ -1265,10 +1266,11 @@ S32 LLFloaterSnapshot::notify(const LLSD& info) void LLFloaterSnapshot::update() { LLFloaterSnapshot* inst = LLFloaterReg::findTypedInstance<LLFloaterSnapshot>("snapshot"); - LLFloaterSocial* floater_social = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social"); - LLFloaterFlickr* floater_flickr = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr"); + LLFloaterSocial* floater_social = LLFloaterReg::findTypedInstance<LLFloaterSocial>("social"); + LLFloaterFlickr* floater_flickr = LLFloaterReg::findTypedInstance<LLFloaterFlickr>("flickr"); + LLFloaterTwitter* floater_twitter = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter"); - if (!inst && !floater_social && !floater_flickr) + if (!inst && !floater_social && !floater_flickr && !floater_twitter) return; BOOL changed = FALSE; diff --git a/indra/newview/llfloatertwitter.cpp b/indra/newview/llfloatertwitter.cpp new file mode 100644 index 0000000000..b45cf32945 --- /dev/null +++ b/indra/newview/llfloatertwitter.cpp @@ -0,0 +1,669 @@ +/** +* @file llfloatertwitter.cpp +* @brief Implementation of llfloatertwitter +* @author cho@lindenlab.com +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llfloatertwitter.h" + +#include "llagent.h" +#include "llagentui.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "lltwitterconnect.h" +#include "llfloaterreg.h" +#include "lliconctrl.h" +#include "llresmgr.h" // LLLocale +#include "llsdserialize.h" +#include "llloadingindicator.h" +#include "llplugincookiestore.h" +#include "llslurl.h" +#include "lltrans.h" +#include "llsnapshotlivepreview.h" +#include "llviewerregion.h" +#include "llviewercontrol.h" +#include "llviewermedia.h" + +static LLRegisterPanelClassWrapper<LLTwitterPhotoPanel> t_panel_photo("lltwitterphotopanel"); +static LLRegisterPanelClassWrapper<LLTwitterAccountPanel> t_panel_account("lltwitteraccountpanel"); + +const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte +const std::string DEFAULT_PHOTO_QUERY_PARAMETERS = "?sourceid=slshare_photo&utm_source=twitter&utm_medium=photo&utm_campaign=slshare"; + +/////////////////////////// +//LLTwitterPhotoPanel/////// +/////////////////////////// + +LLTwitterPhotoPanel::LLTwitterPhotoPanel() : +mSnapshotPanel(NULL), +mResolutionComboBox(NULL), +mRefreshBtn(NULL), +mWorkingLabel(NULL), +mThumbnailPlaceholder(NULL), +mCaptionTextBox(NULL), +mLocationCheckbox(NULL), +mPostButton(NULL) +{ + mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", boost::bind(&LLTwitterPhotoPanel::onSend, this)); + mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", boost::bind(&LLTwitterPhotoPanel::onClickNewSnapshot, this)); +} + +LLTwitterPhotoPanel::~LLTwitterPhotoPanel() +{ + if(mPreviewHandle.get()) + { + mPreviewHandle.get()->die(); + } +} + +BOOL LLTwitterPhotoPanel::postBuild() +{ + setVisibleCallback(boost::bind(&LLTwitterPhotoPanel::onVisibilityChange, this, _2)); + + mSnapshotPanel = getChild<LLUICtrl>("snapshot_panel"); + mResolutionComboBox = getChild<LLUICtrl>("resolution_combobox"); + mResolutionComboBox->setCommitCallback(boost::bind(&LLTwitterPhotoPanel::updateResolution, this, TRUE)); + mRefreshBtn = getChild<LLUICtrl>("new_snapshot_btn"); + mWorkingLabel = getChild<LLUICtrl>("working_lbl"); + mThumbnailPlaceholder = getChild<LLUICtrl>("thumbnail_placeholder"); + mCaptionTextBox = getChild<LLUICtrl>("photo_caption"); + mLocationCheckbox = getChild<LLUICtrl>("add_location_cb"); + mPostButton = getChild<LLUICtrl>("post_photo_btn"); + mCancelButton = getChild<LLUICtrl>("cancel_photo_btn"); + + return LLPanel::postBuild(); +} + +void LLTwitterPhotoPanel::draw() +{ + LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get()); + + // Enable interaction only if no transaction with the service is on-going (prevent duplicated posts) + bool no_ongoing_connection = !(LLTwitterConnect::instance().isTransactionOngoing()); + mCancelButton->setEnabled(no_ongoing_connection); + mCaptionTextBox->setEnabled(no_ongoing_connection); + mResolutionComboBox->setEnabled(no_ongoing_connection); + mRefreshBtn->setEnabled(no_ongoing_connection); + mLocationCheckbox->setEnabled(no_ongoing_connection); + + // Display the preview if one is available + if (previewp && previewp->getThumbnailImage()) + { + const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect(); + const S32 thumbnail_w = previewp->getThumbnailWidth(); + const S32 thumbnail_h = previewp->getThumbnailHeight(); + + // calc preview offset within the preview rect + const S32 local_offset_x = (thumbnail_rect.getWidth() - thumbnail_w) / 2 ; + const S32 local_offset_y = (thumbnail_rect.getHeight() - thumbnail_h) / 2 ; + + // calc preview offset within the floater rect + // Hack : To get the full offset, we need to take into account each and every offset of each widgets up to the floater. + // This is almost as arbitrary as using a fixed offset so that's what we do here for the sake of simplicity. + // *TODO : Get the offset looking through the hierarchy of widgets, should be done in postBuild() so to avoid traversing the hierarchy each time. + S32 offset_x = thumbnail_rect.mLeft + local_offset_x - 1; + S32 offset_y = thumbnail_rect.mBottom + local_offset_y - 39; + + mSnapshotPanel->localPointToOtherView(offset_x, offset_y, &offset_x, &offset_y, getParentByType<LLFloater>()); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + // Apply floater transparency to the texture unless the floater is focused. + F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); + LLColor4 color = LLColor4::white; + gl_draw_scaled_image(offset_x, offset_y, + thumbnail_w, thumbnail_h, + previewp->getThumbnailImage(), color % alpha); + + previewp->drawPreviewRect(offset_x, offset_y) ; + } + + // Update the visibility of the working (computing preview) label + mWorkingLabel->setVisible(!(previewp && previewp->getSnapshotUpToDate())); + + // Enable Post if we have a preview to send and no on going connection being processed + mPostButton->setEnabled(no_ongoing_connection && (previewp && previewp->getSnapshotUpToDate())); + + // Draw the rest of the panel on top of it + LLPanel::draw(); +} + +LLSnapshotLivePreview* LLTwitterPhotoPanel::getPreviewView() +{ + LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get(); + return previewp; +} + +void LLTwitterPhotoPanel::onVisibilityChange(const LLSD& new_visibility) +{ + bool visible = new_visibility.asBoolean(); + if (visible) + { + if (mPreviewHandle.get()) + { + LLSnapshotLivePreview* preview = getPreviewView(); + if(preview) + { + lldebugs << "opened, updating snapshot" << llendl; + preview->updateSnapshot(TRUE); + } + } + else + { + LLRect full_screen_rect = getRootView()->getRect(); + LLSnapshotLivePreview::Params p; + p.rect(full_screen_rect); + LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p); + mPreviewHandle = previewp->getHandle(); + + previewp->setSnapshotType(previewp->SNAPSHOT_WEB); + previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG); + //previewp->setSnapshotQuality(98); + previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect()); + + updateControls(); + } + } +} + +void LLTwitterPhotoPanel::onClickNewSnapshot() +{ + LLSnapshotLivePreview* previewp = getPreviewView(); + if (previewp) + { + //setStatus(Impl::STATUS_READY); + lldebugs << "updating snapshot" << llendl; + previewp->updateSnapshot(TRUE); + } +} + +void LLTwitterPhotoPanel::onSend() +{ + LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterPhotoPanel"); // just in case it is already listening + LLEventPumps::instance().obtain("TwitterConnectState").listen("LLTwitterPhotoPanel", boost::bind(&LLTwitterPhotoPanel::onTwitterConnectStateChange, this, _1)); + + // Connect to Twitter if necessary and then post + if (LLTwitterConnect::instance().isConnected()) + { + sendPhoto(); + } + else + { + LLTwitterConnect::instance().checkConnectionToTwitter(true); + } +} + +bool LLTwitterPhotoPanel::onTwitterConnectStateChange(const LLSD& data) +{ + switch (data.get("enum").asInteger()) + { + case LLTwitterConnect::TWITTER_CONNECTED: + sendPhoto(); + break; + + case LLTwitterConnect::TWITTER_POSTED: + LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterPhotoPanel"); + clearAndClose(); + break; + } + + return false; +} + +void LLTwitterPhotoPanel::sendPhoto() +{ + // Get the caption + std::string caption = mCaptionTextBox->getValue().asString(); + + // Add the location if required + bool add_location = mLocationCheckbox->getValue().asBoolean(); + if (add_location) + { + // Get the SLURL for the location + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + std::string slurl_string = slurl.getSLURLString(); + + // Add query parameters so Google Analytics can track incoming clicks! + slurl_string += DEFAULT_PHOTO_QUERY_PARAMETERS; + + // Add it to the caption (pretty crude, but we don't have a better option with photos) + if (caption.empty()) + caption = slurl_string; + else + caption = caption + " " + slurl_string; + } + + // Get the image + LLSnapshotLivePreview* previewp = getPreviewView(); + + // Post to Twitter + LLTwitterConnect::instance().uploadPhoto(previewp->getFormattedImage(), caption); + + updateControls(); +} + +void LLTwitterPhotoPanel::clearAndClose() +{ + mCaptionTextBox->setValue(""); + + LLFloater* floater = getParentByType<LLFloater>(); + if (floater) + { + floater->closeFloater(); + } +} + +void LLTwitterPhotoPanel::updateControls() +{ + LLSnapshotLivePreview* previewp = getPreviewView(); + BOOL got_bytes = previewp && previewp->getDataSize() > 0; + BOOL got_snap = previewp && previewp->getSnapshotUpToDate(); + LLSnapshotLivePreview::ESnapshotType shot_type = (previewp ? previewp->getSnapshotType() : LLSnapshotLivePreview::SNAPSHOT_POSTCARD); + + // *TODO: Separate maximum size for Web images from postcards + lldebugs << "Is snapshot up-to-date? " << got_snap << llendl; + + LLLocale locale(LLLocale::USER_LOCALE); + std::string bytes_string; + if (got_snap) + { + LLResMgr::getInstance()->getIntegerString(bytes_string, (previewp->getDataSize()) >> 10 ); + } + + //getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : getString("unknown")); <---uses localized string + getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : "unknown"); + getChild<LLUICtrl>("file_size_label")->setColor( + shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD + && got_bytes + && previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLUIColor(LLColor4::red) : LLUIColorTable::instance().getColor( "LabelTextColor" )); + + updateResolution(FALSE); +} + +void LLTwitterPhotoPanel::updateResolution(BOOL do_update) +{ + LLComboBox* combobox = static_cast<LLComboBox *>(mResolutionComboBox); + + std::string sdstring = combobox->getSelectedValue(); + LLSD sdres; + std::stringstream sstream(sdstring); + LLSDSerialize::fromNotation(sdres, sstream, sdstring.size()); + + S32 width = sdres[0]; + S32 height = sdres[1]; + + LLSnapshotLivePreview * previewp = static_cast<LLSnapshotLivePreview *>(mPreviewHandle.get()); + if (previewp && combobox->getCurrentIndex() >= 0) + { + S32 original_width = 0 , original_height = 0 ; + previewp->getSize(original_width, original_height) ; + + if (width == 0 || height == 0) + { + // take resolution from current window size + lldebugs << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" << gViewerWindow->getWindowHeightRaw() << llendl; + previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); + } + else + { + // use the resolution from the selected pre-canned drop-down choice + lldebugs << "Setting preview res selected from combo: " << width << "x" << height << llendl; + previewp->setSize(width, height); + } + + checkAspectRatio(width); + + previewp->getSize(width, height); + + if(original_width != width || original_height != height) + { + previewp->setSize(width, height); + + // hide old preview as the aspect ratio could be wrong + lldebugs << "updating thumbnail" << llendl; + + previewp->updateSnapshot(FALSE, TRUE); + if(do_update) + { + lldebugs << "Will update controls" << llendl; + updateControls(); + LLTwitterPhotoPanel::onClickNewSnapshot(); + } + } + + } +} + +void LLTwitterPhotoPanel::checkAspectRatio(S32 index) +{ + LLSnapshotLivePreview *previewp = getPreviewView() ; + + BOOL keep_aspect = FALSE; + + if (0 == index) // current window size + { + keep_aspect = TRUE; + } + else // predefined resolution + { + keep_aspect = FALSE; + } + + if (previewp) + { + previewp->mKeepAspectRatio = keep_aspect; + } +} + +LLUICtrl* LLTwitterPhotoPanel::getRefreshBtn() +{ + return mRefreshBtn; +} + +/////////////////////////// +//LLTwitterAccountPanel////// +/////////////////////////// + +LLTwitterAccountPanel::LLTwitterAccountPanel() : +mAccountCaptionLabel(NULL), +mAccountNameLabel(NULL), +mPanelButtons(NULL), +mConnectButton(NULL), +mDisconnectButton(NULL) +{ + mCommitCallbackRegistrar.add("SocialSharing.Connect", boost::bind(&LLTwitterAccountPanel::onConnect, this)); + mCommitCallbackRegistrar.add("SocialSharing.Disconnect", boost::bind(&LLTwitterAccountPanel::onDisconnect, this)); + + setVisibleCallback(boost::bind(&LLTwitterAccountPanel::onVisibilityChange, this, _2)); +} + +BOOL LLTwitterAccountPanel::postBuild() +{ + mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label"); + mAccountNameLabel = getChild<LLTextBox>("account_name_label"); + mPanelButtons = getChild<LLUICtrl>("panel_buttons"); + mConnectButton = getChild<LLUICtrl>("connect_btn"); + mDisconnectButton = getChild<LLUICtrl>("disconnect_btn"); + + return LLPanel::postBuild(); +} + +void LLTwitterAccountPanel::draw() +{ + LLTwitterConnect::EConnectionState connection_state = LLTwitterConnect::instance().getConnectionState(); + + //Disable the 'disconnect' button and the 'use another account' button when disconnecting in progress + bool disconnecting = connection_state == LLTwitterConnect::TWITTER_DISCONNECTING; + mDisconnectButton->setEnabled(!disconnecting); + + //Disable the 'connect' button when a connection is in progress + bool connecting = connection_state == LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS; + mConnectButton->setEnabled(!connecting); + + LLPanel::draw(); +} + +void LLTwitterAccountPanel::onVisibilityChange(const LLSD& new_visibility) +{ + bool visible = new_visibility.asBoolean(); + + if(visible) + { + LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterAccountPanel"); + LLEventPumps::instance().obtain("TwitterConnectState").listen("LLTwitterAccountPanel", boost::bind(&LLTwitterAccountPanel::onTwitterConnectStateChange, this, _1)); + + LLEventPumps::instance().obtain("TwitterConnectInfo").stopListening("LLTwitterAccountPanel"); + LLEventPumps::instance().obtain("TwitterConnectInfo").listen("LLTwitterAccountPanel", boost::bind(&LLTwitterAccountPanel::onTwitterConnectInfoChange, this)); + + //Connected + if(LLTwitterConnect::instance().isConnected()) + { + showConnectedLayout(); + } + //Check if connected (show disconnected layout in meantime) + else + { + showDisconnectedLayout(); + } + if ((LLTwitterConnect::instance().getConnectionState() == LLTwitterConnect::TWITTER_NOT_CONNECTED) || + (LLTwitterConnect::instance().getConnectionState() == LLTwitterConnect::TWITTER_CONNECTION_FAILED)) + { + LLTwitterConnect::instance().checkConnectionToTwitter(); + } + } + else + { + LLEventPumps::instance().obtain("TwitterConnectState").stopListening("LLTwitterAccountPanel"); + LLEventPumps::instance().obtain("TwitterConnectInfo").stopListening("LLTwitterAccountPanel"); + } +} + +bool LLTwitterAccountPanel::onTwitterConnectStateChange(const LLSD& data) +{ + if(LLTwitterConnect::instance().isConnected()) + { + //In process of disconnecting so leave the layout as is + if(data.get("enum").asInteger() != LLTwitterConnect::TWITTER_DISCONNECTING) + { + showConnectedLayout(); + } + } + else + { + showDisconnectedLayout(); + } + + return false; +} + +bool LLTwitterAccountPanel::onTwitterConnectInfoChange() +{ + LLSD info = LLTwitterConnect::instance().getInfo(); + std::string clickable_name; + + //Strings of format [http://www.somewebsite.com Click Me] become clickable text + if(info.has("link") && info.has("name")) + { + clickable_name = "[" + info["link"].asString() + " " + info["name"].asString() + "]"; + } + + mAccountNameLabel->setText(clickable_name); + + return false; +} + +void LLTwitterAccountPanel::showConnectButton() +{ + if(!mConnectButton->getVisible()) + { + mConnectButton->setVisible(TRUE); + mDisconnectButton->setVisible(FALSE); + } +} + +void LLTwitterAccountPanel::hideConnectButton() +{ + if(mConnectButton->getVisible()) + { + mConnectButton->setVisible(FALSE); + mDisconnectButton->setVisible(TRUE); + } +} + +void LLTwitterAccountPanel::showDisconnectedLayout() +{ + mAccountCaptionLabel->setText(getString("twitter_disconnected")); + mAccountNameLabel->setText(std::string("")); + showConnectButton(); +} + +void LLTwitterAccountPanel::showConnectedLayout() +{ + LLTwitterConnect::instance().loadTwitterInfo(); + + mAccountCaptionLabel->setText(getString("twitter_connected")); + hideConnectButton(); +} + +void LLTwitterAccountPanel::onConnect() +{ + LLTwitterConnect::instance().checkConnectionToTwitter(true); + + //Clear only the twitter browser cookies so that the twitter login screen appears + LLViewerMedia::getCookieStore()->removeCookiesByDomain(".twitter.com"); +} + +void LLTwitterAccountPanel::onDisconnect() +{ + LLTwitterConnect::instance().disconnectFromTwitter(); + + LLViewerMedia::getCookieStore()->removeCookiesByDomain(".twitter.com"); +} + +//////////////////////// +//LLFloaterTwitter/////// +//////////////////////// + +LLFloaterTwitter::LLFloaterTwitter(const LLSD& key) : LLFloater(key), + mSocialPhotoPanel(NULL), + mStatusErrorText(NULL), + mStatusLoadingText(NULL), + mStatusLoadingIndicator(NULL) +{ + mCommitCallbackRegistrar.add("SocialSharing.Cancel", boost::bind(&LLFloaterTwitter::onCancel, this)); +} + +void LLFloaterTwitter::onCancel() +{ + closeFloater(); +} + +BOOL LLFloaterTwitter::postBuild() +{ + // Keep tab of the Photo Panel + mSocialPhotoPanel = static_cast<LLTwitterPhotoPanel*>(getChild<LLUICtrl>("panel_twitter_photo")); + // Connection status widgets + mStatusErrorText = getChild<LLTextBox>("connection_error_text"); + mStatusLoadingText = getChild<LLTextBox>("connection_loading_text"); + mStatusLoadingIndicator = getChild<LLUICtrl>("connection_loading_indicator"); + return LLFloater::postBuild(); +} + +// static +void LLFloaterTwitter::preUpdate() +{ + LLFloaterTwitter* instance = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter"); + if (instance) + { + //Will set file size text to 'unknown' + instance->mSocialPhotoPanel->updateControls(); + } +} + +// static +void LLFloaterTwitter::postUpdate() +{ + LLFloaterTwitter* instance = LLFloaterReg::findTypedInstance<LLFloaterTwitter>("twitter"); + if (instance) + { + //Will set the file size text + instance->mSocialPhotoPanel->updateControls(); + + // The refresh button is initially hidden. We show it after the first update, + // i.e. after snapshot is taken + LLUICtrl * refresh_button = instance->mSocialPhotoPanel->getRefreshBtn(); + + if (!refresh_button->getVisible()) + { + refresh_button->setVisible(true); + } + + } +} + +void LLFloaterTwitter::draw() +{ + if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator) + { + mStatusErrorText->setVisible(false); + mStatusLoadingText->setVisible(false); + mStatusLoadingIndicator->setVisible(false); + LLTwitterConnect::EConnectionState connection_state = LLTwitterConnect::instance().getConnectionState(); + std::string status_text; + + switch (connection_state) + { + case LLTwitterConnect::TWITTER_NOT_CONNECTED: + // No status displayed when first opening the panel and no connection done + case LLTwitterConnect::TWITTER_CONNECTED: + // When successfully connected, no message is displayed + case LLTwitterConnect::TWITTER_POSTED: + // No success message to show since we actually close the floater after successful posting completion + break; + case LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS: + // Connection loading indicator + mStatusLoadingText->setVisible(true); + status_text = LLTrans::getString("SocialTwitterConnecting"); + mStatusLoadingText->setValue(status_text); + mStatusLoadingIndicator->setVisible(true); + break; + case LLTwitterConnect::TWITTER_POSTING: + // Posting indicator + mStatusLoadingText->setVisible(true); + status_text = LLTrans::getString("SocialTwitterPosting"); + mStatusLoadingText->setValue(status_text); + mStatusLoadingIndicator->setVisible(true); + break; + case LLTwitterConnect::TWITTER_CONNECTION_FAILED: + // Error connecting to the service + mStatusErrorText->setVisible(true); + status_text = LLTrans::getString("SocialTwitterErrorConnecting"); + mStatusErrorText->setValue(status_text); + break; + case LLTwitterConnect::TWITTER_POST_FAILED: + // Error posting to the service + mStatusErrorText->setVisible(true); + status_text = LLTrans::getString("SocialTwitterErrorPosting"); + mStatusErrorText->setValue(status_text); + break; + case LLTwitterConnect::TWITTER_DISCONNECTING: + // Disconnecting loading indicator + mStatusLoadingText->setVisible(true); + status_text = LLTrans::getString("SocialTwitterDisconnecting"); + mStatusLoadingText->setValue(status_text); + mStatusLoadingIndicator->setVisible(true); + break; + case LLTwitterConnect::TWITTER_DISCONNECT_FAILED: + // Error disconnecting from the service + mStatusErrorText->setVisible(true); + status_text = LLTrans::getString("SocialTwitterErrorDisconnecting"); + mStatusErrorText->setValue(status_text); + break; + } + } + LLFloater::draw(); +} + diff --git a/indra/newview/llfloatertwitter.h b/indra/newview/llfloatertwitter.h new file mode 100644 index 0000000000..d0c7b57eef --- /dev/null +++ b/indra/newview/llfloatertwitter.h @@ -0,0 +1,122 @@ +/** +* @file llfloatertwitter.h +* @brief Header file for llfloatertwitter +* @author cho@lindenlab.com +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LL_LLFLOATERTWITTER_H +#define LL_LLFLOATERTWITTER_H + +#include "llfloater.h" +#include "lltextbox.h" +#include "llviewertexture.h" + +class LLIconCtrl; +class LLCheckBoxCtrl; +class LLSnapshotLivePreview; + +class LLTwitterPhotoPanel : public LLPanel +{ +public: + LLTwitterPhotoPanel(); + ~LLTwitterPhotoPanel(); + + BOOL postBuild(); + void draw(); + + LLSnapshotLivePreview* getPreviewView(); + void onVisibilityChange(const LLSD& new_visibility); + void onClickNewSnapshot(); + void onSend(); + bool onTwitterConnectStateChange(const LLSD& data); + + void sendPhoto(); + void clearAndClose(); + + void updateControls(); + void updateResolution(BOOL do_update); + void checkAspectRatio(S32 index); + LLUICtrl* getRefreshBtn(); + +private: + LLHandle<LLView> mPreviewHandle; + + LLUICtrl * mSnapshotPanel; + LLUICtrl * mResolutionComboBox; + LLUICtrl * mRefreshBtn; + LLUICtrl * mWorkingLabel; + LLUICtrl * mThumbnailPlaceholder; + LLUICtrl * mCaptionTextBox; + LLUICtrl * mLocationCheckbox; + LLUICtrl * mPostButton; + LLUICtrl* mCancelButton; +}; + +class LLTwitterAccountPanel : public LLPanel +{ +public: + LLTwitterAccountPanel(); + BOOL postBuild(); + void draw(); + +private: + void onVisibilityChange(const LLSD& new_visibility); + bool onTwitterConnectStateChange(const LLSD& data); + bool onTwitterConnectInfoChange(); + void onConnect(); + void onUseAnotherAccount(); + void onDisconnect(); + + void showConnectButton(); + void hideConnectButton(); + void showDisconnectedLayout(); + void showConnectedLayout(); + + LLTextBox * mAccountCaptionLabel; + LLTextBox * mAccountNameLabel; + LLUICtrl * mPanelButtons; + LLUICtrl * mConnectButton; + LLUICtrl * mDisconnectButton; +}; + + +class LLFloaterTwitter : public LLFloater +{ +public: + LLFloaterTwitter(const LLSD& key); + BOOL postBuild(); + void draw(); + void onCancel(); + + static void preUpdate(); + static void postUpdate(); + +private: + LLTwitterPhotoPanel* mSocialPhotoPanel; + LLTextBox* mStatusErrorText; + LLTextBox* mStatusLoadingText; + LLUICtrl* mStatusLoadingIndicator; +}; + +#endif // LL_LLFLOATERTWITTER_H + diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index afd9942e77..67952f83c7 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -36,6 +36,7 @@ #include "llfloaterreg.h" #include "llfloatersocial.h" #include "llfloaterflickr.h" +#include "llfloatertwitter.h" #include "llimagebmp.h" #include "llimagej2c.h" #include "llimagejpeg.h" @@ -211,6 +212,7 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail LLFloaterSnapshot::preUpdate(); LLFloaterSocial::preUpdate(); LLFloaterFlickr::preUpdate(); + LLFloaterTwitter::preUpdate(); } // Update thumbnail if requested. @@ -769,6 +771,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) LLFloaterSnapshot::postUpdate(); LLFloaterSocial::postUpdate(); LLFloaterFlickr::postUpdate(); + LLFloaterTwitter::postUpdate(); return TRUE; } diff --git a/indra/newview/lltwitterconnect.cpp b/indra/newview/lltwitterconnect.cpp index 80142e7073..5abd654d0c 100644 --- a/indra/newview/lltwitterconnect.cpp +++ b/indra/newview/lltwitterconnect.cpp @@ -296,7 +296,8 @@ std::string LLTwitterConnect::getTwitterConnectURL(const std::string& route, boo LLViewerRegion *regionp = gAgent.getRegion(); if (regionp) { - url = regionp->getCapability("TwitterConnect"); + url = "http://pdp15.lindenlab.com/twitter/agent/" + gAgentID.asString(); // TEMPORARY FOR TESTING - CHO + //url = regionp->getCapability("TwitterConnect"); url += route; if (include_read_from_master && mReadFromMaster) diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 0541da95fc..e74e6fef3d 100755 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -116,6 +116,7 @@ #include "llfloatertopobjects.h" #include "llfloatertoybox.h" #include "llfloatertranslationsettings.h" +#include "llfloatertwitter.h" #include "llfloateruipreview.h" #include "llfloatervoiceeffect.h" #include "llfloatervoicevolume.h" @@ -307,6 +308,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundDevices>); LLFloaterReg::add("social", "floater_social.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSocial>); LLFloaterReg::add("flickr", "floater_flickr.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFlickr>); + LLFloaterReg::add("twitter", "floater_twitter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTwitter>); LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloater>); LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRunQueue>); LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>); diff --git a/indra/newview/skins/default/xui/en/floater_twitter.xml b/indra/newview/skins/default/xui/en/floater_twitter.xml new file mode 100644 index 0000000000..7007a14cdb --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_twitter.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<floater + positioning="cascading" + can_close="true" + can_resize="false" + help_topic="floater_twitter" + layout="topleft" + name="floater_twitter" + save_rect="true" + single_instance="true" + reuse_instance="true" + title="TWITTER" + height="482" + width="304"> + <panel + height="482" + width="304" + visible="true" + name="background" + follows="all" + top="0" + left="0"> + <tab_container + name="tabs" + tab_group="1" + tab_min_width="70" + tab_height="30" + tab_position="top" + top="7" + height="437" + halign="center"> + <panel + filename="panel_twitter_photo.xml" + class="lltwitterphotopanel" + follows="all" + label="COMPOSE" + name="panel_twitter_photo"/> + <panel + filename="panel_twitter_account.xml" + class="lltwitteraccountpanel" + follows="all" + label="ACCOUNT" + name="panel_twitter_account"/> + </tab_container> + <panel + name="connection_status_panel" + follows="left|bottom|right" + height="24"> + <text + name="connection_error_text" + type="string" + follows="left|bottom|right" + top="5" + left="9" + width="250" + height="20" + wrap="true" + halign="left" + valign="center" + text_color="DrYellow" + font="SansSerif"> + Error + </text> + <loading_indicator + follows="left|bottom|right" + height="24" + width="24" + name="connection_loading_indicator" + top="2" + left="9" + visible="true"/> + <text + name="connection_loading_text" + type="string" + follows="left|bottom|right" + top="5" + left_pad="5" + width="250" + height="20" + wrap="true" + halign="left" + valign="center" + text_color="EmphasisColor" + font="SansSerif"> + Loading... + </text> + </panel> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index bbd6e94579..79adb4e8bb 100755 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -282,14 +282,21 @@ <menu_item_separator/> <menu_item_call label="Facebook..." - name="PostToFacebook"> + name="Facebook"> <menu_item_call.on_click function="Floater.Toggle" parameter="social"/> </menu_item_call> <menu_item_call + label="Twitter..." + name="Twitter"> + <menu_item_call.on_click + function="Floater.Toggle" + parameter="twitter"/> + </menu_item_call> + <menu_item_call label="Flickr..." - name="UploadToFacebook"> + name="Flickr"> <menu_item_call.on_click function="Floater.Toggle" parameter="flickr"/> diff --git a/indra/newview/skins/default/xui/en/panel_twitter_account.xml b/indra/newview/skins/default/xui/en/panel_twitter_account.xml new file mode 100644 index 0000000000..4a413bd711 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_twitter_account.xml @@ -0,0 +1,75 @@ +<panel + height="400" + width="304" + layout="topleft" + name="panel_twitter_account"> + <string + name="twitter_connected" + value="You are connected to Twitter as:" /> + <string + name="twitter_disconnected" + value="Not connected to Twitter" /> + <text + layout="topleft" + length="1" + follows="top|left" + font="SansSerif" + height="16" + left="9" + name="account_caption_label" + top="21" + type="string"> + Not connected to Twitter. + </text> + <text + layout="topleft" + top_pad="2" + length="1" + follows="top|left" + font="SansSerif" + height="16" + left="9" + name="account_name_label" + parse_urls="true" + type="string"/> + <panel + layout="topleft" + name="panel_buttons" + height="345" + left="9"> + <button + layout="topleft" + follows="left|top" + top_pad="9" + visible="true" + height="23" + label="Connect..." + name="connect_btn" + width="210"> + <commit_callback function="SocialSharing.Connect"/> + </button> + + <button + layout="topleft" + follows="left|top" + top_delta="0" + height="23" + label="Disconnect" + name="disconnect_btn" + width="210" + visible="false"> + <commit_callback function="SocialSharing.Disconnect"/> + </button> + <text + layout="topleft" + length="1" + follows="top|left" + height="16" + left="0" + name="account_learn_more_label" + top_pad="20" + type="string"> + [http://community.secondlife.com/t5/English-Knowledge-Base/Second-Life-Share/ta-p/2149711 Learn about posting to Twitter] + </text> + </panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_twitter_photo.xml b/indra/newview/skins/default/xui/en/panel_twitter_photo.xml new file mode 100644 index 0000000000..058c65402a --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_twitter_photo.xml @@ -0,0 +1,152 @@ + <panel + height="400" + width="304" + layout="topleft" + name="panel_twitter_photo"> + <layout_stack + layout="topleft" + border_size="0" + height="392" + follows="all" + orientation="vertical" + name="stack_photo" + top="8"> + <layout_panel + name="snapshot_panel" + height="367"> + <combo_box + control_name="SocialPhotoResolution" + follows="left|top" + top="6" + left="9" + name="resolution_combobox" + tool_tip="Image resolution" + height="21" + width="135"> + <combo_box.item + label="Current Window" + name="CurrentWindow" + value="[i0,i0]" /> + <combo_box.item + label="640x480" + name="640x480" + value="[i640,i480]" /> + <combo_box.item + label="800x600" + name="800x600" + value="[i800,i600]" /> + <combo_box.item + label="1024x768" + name="1024x768" + value="[i1024,i768]" /> + </combo_box> + <text + follows="left|top" + font="SansSerifSmall" + height="14" + left="208" + length="1" + halign="right" + name="file_size_label" + top="9" + type="string" + width="50"> + [SIZE] KB + </text> + <panel + height="150" + width="250" + visible="true" + name="thumbnail_placeholder" + top="33" + follows="left|top" + left="9"> + </panel> + <button + follows="left|top" + height="23" + label="Refresh" + left="9" + top_pad="5" + name="new_snapshot_btn" + tool_tip="Click to refresh" + visible="true" + width="100" > + <button.commit_callback + function="SocialSharing.RefreshPhoto" /> + </button> + <text + follows="left|top" + font="SansSerif" + text_color="EmphasisColor" + height="14" + top_pad="-19" + left_pad="-20" + length="1" + halign="center" + name="working_lbl" + translate="false" + type="string" + visible="true" + width="150"> + Refreshing... + </text> + <text + length="1" + follows="top|left|right" + font="SansSerif" + height="16" + left="9" + name="caption_label" + top_pad="20" + type="string"> + Comment (optional): + </text> + <text_editor + follows="left|top" + height="87" + width="250" + left="9" + length="1" + max_length="700" + name="photo_caption" + type="string" + word_wrap="true"> + </text_editor> + <check_box + follows="left|top" + initial_value="true" + label="Include location in posting" + name="add_location_cb" + left="9" + height="16" + top_pad="8"/> + </layout_panel> + <layout_panel + name="photo_button_panel" + height="25"> + <button + follows="left|top" + top="0" + left="9" + height="23" + label="Post" + name="post_photo_btn" + width="100"> + <button.commit_callback + function="SocialSharing.SendPhoto" /> + </button> + <button + follows="left|top" + height="23" + label="Cancel" + name="cancel_photo_btn" + left_pad="15" + top_delta="0" + width="100"> + <button.commit_callback + function="SocialSharing.Cancel" /> + </button> + </layout_panel> + </layout_stack> + </panel> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index ce09faeac0..2b707ed84b 100755 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -148,7 +148,7 @@ Please try logging in again in a minute.</string> <string name="SentToInvalidRegion">You were sent to an invalid region.</string> <string name="TestingDisconnect">Testing viewer disconnect</string> - <!-- SLShare: Facebook, Flickr, and so on... --> + <!-- SLShare: Facebook, Flickr, and Twitter --> <string name="SocialFacebookConnecting">Connecting to Facebook...</string> <string name="SocialFacebookPosting">Posting...</string> <string name="SocialFacebookDisconnecting">Disconnecting from Facebook...</string> @@ -161,6 +161,12 @@ Please try logging in again in a minute.</string> <string name="SocialFlickrErrorConnecting">Problem connecting to Flickr</string> <string name="SocialFlickrErrorPosting">Problem posting to Flickr</string> <string name="SocialFlickrErrorDisconnecting">Problem disconnecting from Flickr</string> + <string name="SocialTwitterConnecting">Connecting to Twitter...</string> + <string name="SocialTwitterPosting">Posting...</string> + <string name="SocialTwitterDisconnecting">Disconnecting from Twitter...</string> + <string name="SocialTwitterErrorConnecting">Problem connecting to Twitter</string> + <string name="SocialTwitterErrorPosting">Problem posting to Twitter</string> + <string name="SocialTwitterErrorDisconnecting">Problem disconnecting from Twitter</string> <!-- Tooltip --> <string name="TooltipPerson">Person</string><!-- Object under mouse pointer is an avatar --> |