- AlbumsFragment: added loading image to image worker which is shown
when the albums cover is loading or absent
- AlbumsFragment.AlbumsAdapter: moved some logic to the parent
AlbumsEndlessAdapter class. And now AlbumsAdapter extends it
- AlbumsFragment.AlbumsAdapter: fixed setting of empty cover to the view
via image worker to avoid async task may change it in the future issue
- MainActivity: added REQUEST_ALBUMS request code constant
- Preferences: added variation of getApi method with no args
- SelectAlbumsActivity: added
- SyncUploadFragment: now it implements OnClickListener
- SyncUploadFragment: added new fields albumsText and albumsWrapper
- SyncUploadFragment: now it overrides onSaveInstanceState to store
albums information
- SyncUploadFragment: now init method is called in onViewCreated
- SyncUploadFragment, UploadActivity.UploadUiFragment: added albumsText
initialization to the init method. Clicking on albumsText opens
SelectAlbumsActivity
- SyncUploadFragment: added onActivityResult implementation which
handles result received from SelectAlbumsActivity
- SyncUploadFragment.UploadInitTask,
UploadActivity.UploadUiFragment.getUploadMetaData: added setting of
albums data to the upload meta data
- UploadActivity: added REQUEST_ALBUMS constant
- UploadActivity.UploadUiFragment: added SELECTED_ALBUMS constant
- UploadActivity.UploadUiFragment: added albumsText field
- UploadActivity.UploadUiFragment: added saving of selected albums
information to the onSaveInstanceState method
- UploadActivity.UploadUiFragment: added handling of REQUEST_ALBUMS
request code to the onActivityResult method
- UploadActivity.UploadUiFragment: added handling of R.id.edit_albums
clicks to the onClick method
- ImageWorker.BitmapWorkerTask: added support of null data parameter to
the doInBackground method
- Album: now it implements Parcelable
- AlbumUtils: added
- Tagutils: getTagsString method functionality moved to
UploadMetaDataUtils.getCommaSeparatedString method
- TroveboxApi: added albums metadata support to the uploadPhoto method
- UploadMetaData: added mAlbums field
- UploadMetaDataUtils: added
- UploadsProviderAccessor: added JSON_ALBUMS constant
- UploadsProviderAccessor: added albums upload metadata support to the
addPendingUpload and extractPhotoUpload methods
- AlbumsEndlessAdapter: added
- MultiSelectAlbumsAdapter: added
- StringMapParcelableWrapper: added
- res/layout/activity_select_albums.xml: added
- res/layout/activity_upload.xml: added edit_albums EditText
- res/layout/fragment_sync_upload_settings.xml: added edit_albums
EditText
- res/layout_list_item_album_checkbox.xml: added
- res/values/strings.xml, res/values-ru/strings.xml: added
title_activity_select_albums and upload_albums constants
- AndroidManifest.xml: added SelectAlbumsActivity section
- TroveboxApiTest: added albums testing to the testPhotoUpload

#385
- ApiBase: NetworkConnectionTimeout_ms constant is now public
- ApiBase: added few variations of execute method with connectionTimeout
param
- TroveboxApi: changed execute method variation to the one with the
custom timeout in the uploadPhoto method. The used timeout is 2 minutes

non-issue
- GuiUtils: added post method
- res/drawable/bg.xml: changed background o the new design color
This commit is contained in:
Eugene Popovich 2013-04-16 14:33:27 +03:00
parent 6eaa95a027
commit 77a9060523
30 changed files with 1022 additions and 115 deletions

View file

@ -5,7 +5,6 @@
android:versionCode="6"
android:versionName="1.5" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="17" />
@ -112,6 +111,12 @@
android:label="@string/title_activity_select_tags"
android:theme="@style/Theme.Trovebox.DialogActivity.Light" >
</activity>
<activity
android:name=".SelectAlbumsActivity"
android:configChanges="orientation"
android:label="@string/title_activity_select_albums"
android:theme="@style/Theme.Trovebox.DialogActivity.Light" >
</activity>
<activity
android:name="com.aviary.android.feather.FeatherActivity"
android:configChanges="orientation|keyboardHidden"

View file

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<issue id="MissingTranslation" severity="warning" />
</lint>

View file

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/bg_pattern"
android:tileMode="repeat" />
<color xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#faf3ef" />

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="1" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" >
<ListView
android:id="@+id/list_select_albums"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="multipleChoice" >
</ListView>
<ProgressBar
android:id="@+id/loading"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:visibility="gone" />
</RelativeLayout>
<Button
android:id="@+id/finishBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/upload_select_tags_finish" />
</LinearLayout>

View file

@ -62,6 +62,16 @@
android:hint="@string/upload_title_hint"
android:inputType="textCapWords" />
<EditText
android:id="@+id/edit_albums"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:focusable="false"
android:focusableInTouchMode="false"
android:hint="@string/upload_albums"
android:inputType="none" />
<EditText
android:id="@+id/edit_tags"
android:layout_width="match_parent"

View file

@ -31,6 +31,16 @@
android:inputType="textCapWords" >
</EditText>
<EditText
android:id="@+id/edit_albums"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:focusable="false"
android:focusableInTouchMode="false"
android:hint="@string/upload_albums"
android:inputType="none" />
<EditText
android:id="@+id/edit_tags"
android:layout_width="match_parent"

View file

@ -9,8 +9,7 @@
android:paddingRight="@dimen/site_padding"
android:paddingTop="@dimen/site_padding_half" >
<ImageView
android:id="@+id/cover"
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dip"
@ -19,9 +18,15 @@
android:paddingBottom="2dp"
android:paddingLeft="1dp"
android:paddingRight="2dp"
android:paddingTop="1dp"
android:scaleType="centerCrop"
android:src="@drawable/icon" />
android:paddingTop="1dp" >
<ImageView
android:id="@+id/cover"
android:layout_width="@dimen/album_item_size"
android:layout_height="@dimen/album_item_size"
android:scaleType="centerCrop"
android:src="@drawable/empty_photo" />
</RelativeLayout>
<TextView
android:id="@+id/text_name"

View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="@dimen/site_padding_half"
android:paddingLeft="@dimen/site_padding_half"
android:paddingRight="@dimen/site_padding_half"
android:paddingTop="@dimen/site_padding_half" >
<CheckBox
android:id="@+id/album_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/site_padding_half"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/site_padding_half"
android:adjustViewBounds="true"
android:background="@drawable/shadow_border"
android:paddingBottom="2dp"
android:paddingLeft="1dp"
android:paddingRight="2dp"
android:paddingTop="1dp" >
<ImageView
android:id="@+id/cover"
android:layout_width="@dimen/album_item_size"
android:layout_height="@dimen/album_item_size"
android:scaleType="centerCrop"
android:src="@drawable/empty_photo" />
</RelativeLayout>
<TextView
android:id="@+id/text_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="very very very very very very very very very very very very long name"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

View file

@ -80,6 +80,7 @@
<string name="upload_title">Загрузка</string>
<string name="upload_title_hint">Название</string>
<string name="upload_tags">Теги</string>
<string name="upload_albums">Альбомы</string>
<string name="upload_select_tags">Выберите теги</string>
<string name="upload_select_tags_finish">Завершить</string>
<string name="upload_description">Описание</string>
@ -98,6 +99,9 @@
<!-- SelectTagsActivity -->
<string name="title_activity_select_tags">Выбор тегов</string>
<!-- SelectAlbumsActivity -->
<string name="title_activity_select_albums">Выбор альбомов</string>
<!-- Sync screen -->
<string name="sync_next_button">Следующий шаг</string>
<string name="sync_previous_button">Предыдущий шаг</string>

View file

@ -80,6 +80,7 @@
<string name="upload_title">Upload</string>
<string name="upload_title_hint">Title</string>
<string name="upload_tags">Tags</string>
<string name="upload_albums">Albums</string>
<string name="upload_select_tags">Select Tags</string>
<string name="upload_select_tags_finish">Finish</string>
<string name="upload_description">Description</string>
@ -97,6 +98,9 @@
<!-- SelectTagsActivity -->
<string name="title_activity_select_tags">Select Tags</string>
<!-- SelectAlbumsActivity -->
<string name="title_activity_select_albums">Select Albums</string>
<!-- Sync screen -->
<string name="sync_next_button">Next</string>

View file

@ -1,7 +1,6 @@
package com.trovebox.android.app;
import org.holoeverywhere.LayoutInflater;
import org.holoeverywhere.app.Activity;
@ -19,15 +18,9 @@ import com.trovebox.android.app.bitmapfun.util.ImageCache;
import com.trovebox.android.app.bitmapfun.util.ImageFetcher;
import com.trovebox.android.app.common.CommonRefreshableFragmentWithImageWorker;
import com.trovebox.android.app.model.Album;
import com.trovebox.android.app.net.AlbumsResponse;
import com.trovebox.android.app.net.ITroveboxApi;
import com.trovebox.android.app.net.Paging;
import com.trovebox.android.app.net.ReturnSizes;
import com.trovebox.android.app.net.TroveboxResponseUtils;
import com.trovebox.android.app.ui.adapter.EndlessAdapter;
import com.trovebox.android.app.util.CommonUtils;
import com.trovebox.android.app.ui.adapter.AlbumsEndlessAdapter;
import com.trovebox.android.app.util.GalleryOpenControl;
import com.trovebox.android.app.util.GuiUtils;
import com.trovebox.android.app.util.LoadingControl;
import com.trovebox.android.app.util.TrackerUtils;
@ -65,6 +58,7 @@ public class AlbumsFragment extends CommonRefreshableFragmentWithImageWorker imp
list.setAdapter(mAdapter);
list.setOnItemClickListener(this);
}
@Override
public void onAttach(Activity activity)
{
@ -81,6 +75,7 @@ public class AlbumsFragment extends CommonRefreshableFragmentWithImageWorker imp
thumbSize = new ReturnSizes(mImageThumbSize, mImageThumbSize, true);
mImageWorker = new ImageFetcher(getActivity(), loadingControl, thumbSize.getWidth(),
thumbSize.getHeight());
mImageWorker.setLoadingImage(R.drawable.empty_photo);
mImageWorker.setImageCache(ImageCache.findOrCreateCache(getActivity(),
ImageCache.THUMBS_CACHE_DIR));
}
@ -110,28 +105,11 @@ public class AlbumsFragment extends CommonRefreshableFragmentWithImageWorker imp
protected boolean isRefreshMenuVisible() {
return !loadingControl.isLoading();
}
private class AlbumsAdapter extends EndlessAdapter<Album>
private class AlbumsAdapter extends AlbumsEndlessAdapter
{
public static final int DEFAULT_PAGE_SIZE = 20;
private final ITroveboxApi mTroveboxApi;
public AlbumsAdapter()
{
this(DEFAULT_PAGE_SIZE);
}
public AlbumsAdapter(int pageSize)
{
super(pageSize);
mTroveboxApi = Preferences.getApi(getActivity());
loadFirstPage();
}
@Override
public long getItemId(int position)
{
// return ((Album) getItem(position)).getAlbum().hashCode();
return position;
public AlbumsAdapter() {
super(loadingControl);
}
@Override
@ -157,46 +135,11 @@ public class AlbumsFragment extends CommonRefreshableFragmentWithImageWorker imp
.loadImage(album.getCover().getUrl(thumbSize.toString()), image);
} else
{
image.setImageBitmap(null);
mImageWorker
.loadImage(null, image);
}
return convertView;
}
@Override
public LoadResponse loadItems(int page)
{
if (CommonUtils.checkLoggedInAndOnline())
{
try
{
AlbumsResponse response = mTroveboxApi.getAlbums(new Paging(page,
getPageSize()));
if (TroveboxResponseUtils.checkResponseValid(response))
{
return new LoadResponse(response.getAlbums(), response.hasNextPage());
}
} catch (Exception e)
{
GuiUtils.error(
TAG,
R.string.errorCouldNotLoadNextAlbumsInList,
e);
}
}
return new LoadResponse(null, false);
}
@Override
protected void onStartLoading()
{
loadingControl.startLoading();
}
@Override
protected void onStoppedLoading()
{
loadingControl.stopLoading();
}
}
}

View file

@ -68,6 +68,7 @@ public class MainActivity extends CommonActivity
public final static int AUTHORIZE_ACTIVITY_REQUEST_CODE = 0;
public final static int PURCHASE_FLOW_REQUEST_CODE = 1;
public static final int REQUEST_ALBUMS = 2;
private ActionBar mActionBar;
private AtomicInteger loaders = new AtomicInteger(0);

View file

@ -237,12 +237,14 @@ public class Preferences {
/**
* Check whether currently used server is self-hosted
*
* @return true if server is self-hosted, otherwise return false
*/
public static boolean isSelfHosted()
{
return !isHosted();
}
/**
* Check whether currently used server is hosted or self-hosted
*
@ -271,6 +273,7 @@ public class Preferences {
/**
* Check whether the purchase was already verified by the application
*
* @param purchase purchase to verify
* @return true if purchase was successfully verified
*/
@ -282,6 +285,7 @@ public class Preferences {
/**
* Set purchase verified state to the cache
*
* @param purchase related purchase
* @param verified whether the verification was successful
*/
@ -290,6 +294,7 @@ public class Preferences {
getVerifiedPaymentsPreferences().edit().putBoolean(
purchase.getDeveloperPayload() + ":" + purchase.getToken(), verified);
}
/**
* Check whether necessary system version information already retrieved and
* stored in the cache
@ -304,8 +309,8 @@ public class Preferences {
}
/**
* Set whether necessary system version information retrieved
* and cached properly
* Set whether necessary system version information retrieved and cached
* properly
*
* @param value true if information retrieved and saved, false othwerwise
*/
@ -318,6 +323,7 @@ public class Preferences {
value)
.commit();
}
public static void logout(Context context) {
getDefaultSharedPreferences(context)
.edit()
@ -394,6 +400,14 @@ public class Preferences {
return consumer;
}
/**
* Get the ITroveboxApi implementation
* @return
*/
public static ITroveboxApi getApi() {
return getApi(TroveboxApplication.getContext());
}
public static ITroveboxApi getApi(Context context) {
return TroveboxApi.createInstance(context);
}

View file

@ -0,0 +1,233 @@
package com.trovebox.android.app;
import java.util.Map;
import org.holoeverywhere.LayoutInflater;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.trovebox.android.app.bitmapfun.util.ImageCache;
import com.trovebox.android.app.bitmapfun.util.ImageFetcher;
import com.trovebox.android.app.common.CommonActivity;
import com.trovebox.android.app.common.CommonFragmentWithImageWorker;
import com.trovebox.android.app.model.Album;
import com.trovebox.android.app.net.ReturnSizes;
import com.trovebox.android.app.ui.adapter.MultiSelectAlbumsAdapter;
import com.trovebox.android.app.util.LoadingControl;
import com.trovebox.android.app.util.TrackerUtils;
import com.trovebox.android.app.util.data.StringMapParcelableWrapper;
/**
* The activity which allows to select albums
*
* @author Eugene Popovich
*/
public class SelectAlbumsActivity
extends CommonActivity {
public static final String TAG =
SelectAlbumsActivity.class.getSimpleName();
public static final String SELECTED_ALBUMS = "SELECTED_ALBUMS";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null)
{
getSupportFragmentManager().beginTransaction()
.replace(android.R.id.content, new SelectAlbumsUiFragment())
.commit();
}
}
public static class SelectAlbumsUiFragment extends CommonFragmentWithImageWorker
implements LoadingControl, OnItemClickListener
{
private int mLoaders = 0;
private AlbumsAdapter mAdapter;
private ListView list;
private ReturnSizes thumbSize;
@Override
protected void initImageWorker() {
int mImageThumbSize = getResources().getDimensionPixelSize(
R.dimen.album_item_size);
thumbSize = new ReturnSizes(mImageThumbSize, mImageThumbSize, true);
mImageWorker = new ImageFetcher(getActivity(), this, thumbSize.getWidth(),
thumbSize.getHeight());
mImageWorker.setLoadingImage(R.drawable.empty_photo);
mImageWorker.setImageCache(ImageCache.findOrCreateCache(getActivity(),
ImageCache.THUMBS_CACHE_DIR, false));
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState)
{
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.activity_select_albums, container,
false);
return v;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
init(view);
}
void init(View v)
{
StringMapParcelableWrapper albumsWrapper = getActivity().getIntent()
.getParcelableExtra(SELECTED_ALBUMS);
mAdapter = new AlbumsAdapter(albumsWrapper == null ? null : albumsWrapper.getMap());
list = (ListView) v.findViewById(R.id.list_select_albums);
list.setAdapter(mAdapter);
list.setOnItemClickListener(this);
Button finishBtn = (Button) v.findViewById(R.id.finishBtn);
finishBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
TrackerUtils.trackButtonClickEvent("finishBtn",
SelectAlbumsUiFragment.this);
finishedClicked(v);
}
});
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view,
int position, long id)
{
TrackerUtils.trackButtonClickEvent("album_item", SelectAlbumsUiFragment.this);
ViewHolder vh = mAdapter.getViewHolder(view);
mAdapter.onAlbumViewClicked(vh.checkBox, !vh.checkBox.isChecked());
}
/**
* Return selected Albums to the upload activity
*
* @param v
*/
public void finishedClicked(View v) {
Intent data = new Intent();
data.putExtra(SELECTED_ALBUMS, mAdapter.getSelectedAlbumsParceble());
getActivity().setResult(RESULT_OK, data);
getActivity().finish();
}
private class AlbumsAdapter extends MultiSelectAlbumsAdapter {
public AlbumsAdapter(Map<String, String> alreadySelectedAlbums) {
super(SelectAlbumsUiFragment.this);
if (alreadySelectedAlbums != null)
{
checkedAlbums.putAll(alreadySelectedAlbums);
}
}
@Override
public View getView(Album album, View convertView, ViewGroup parent) {
if (convertView == null) {
final LayoutInflater layoutInflater = (LayoutInflater) getActivity()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(
R.layout.list_item_album_checkbox, null);
}
ViewHolder vh = getViewHolder(convertView);
initAlbumCheckbox(album, vh.checkBox);
vh.name.setText(album.getName());
if (album.getCover() != null)
{
mImageWorker
.loadImage(album.getCover().getUrl(thumbSize.toString()), vh.cover);
} else
{
mImageWorker
.loadImage(null, vh.cover);
}
return convertView;
}
ViewHolder getViewHolder(View view)
{
ViewHolder viewHolder = (ViewHolder) view.getTag();
if (viewHolder == null)
{
viewHolder = new ViewHolder();
viewHolder.checkBox = (CheckBox) view
.findViewById(R.id.album_checkbox);
viewHolder.cover = (ImageView) view.findViewById(R.id.cover);
viewHolder.name = (TextView) view.findViewById(R.id.text_name);
}
return viewHolder;
}
public StringMapParcelableWrapper getSelectedAlbumsParceble() {
return new StringMapParcelableWrapper(checkedAlbums);
}
}
public static class ViewHolder
{
CheckBox checkBox;
ImageView cover;
TextView name;
}
@Override
public void startLoading()
{
if (mLoaders++ == 0)
{
showLoading(true);
}
}
@Override
public void stopLoading()
{
if (--mLoaders == 0)
{
showLoading(false);
}
}
@Override
public boolean isLoading() {
return mLoaders > 0;
}
private void showLoading(boolean show)
{
if (getView() != null)
{
getView().findViewById(R.id.loading).setVisibility(show ? View.VISIBLE :
View.GONE);
}
}
}
}

View file

@ -3,6 +3,7 @@ package com.trovebox.android.app;
import java.io.File;
import java.util.ArrayList;
import java.util.Map;
import org.holoeverywhere.LayoutInflater;
import org.holoeverywhere.app.Activity;
@ -11,6 +12,7 @@ import org.holoeverywhere.widget.Switch;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@ -24,6 +26,7 @@ import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.trovebox.android.app.common.CommonFragment;
import com.trovebox.android.app.facebook.FacebookUtils;
import com.trovebox.android.app.model.utils.AlbumUtils;
import com.trovebox.android.app.net.UploadMetaData;
import com.trovebox.android.app.net.account.AccountLimitUtils;
import com.trovebox.android.app.provider.UploadsProviderAccessor;
@ -36,17 +39,22 @@ import com.trovebox.android.app.util.ProgressDialogLoadingControl;
import com.trovebox.android.app.util.SyncUtils;
import com.trovebox.android.app.util.TrackerUtils;
import com.trovebox.android.app.util.concurrent.AsyncTaskEx;
import com.trovebox.android.app.util.data.StringMapParcelableWrapper;
public class SyncUploadFragment extends CommonFragment
public class SyncUploadFragment extends CommonFragment implements OnClickListener
{
static final String TAG = SyncUploadFragment.class.getSimpleName();
static final String SELECTED_ALBUMS = "SELECTED_ALBUMS";
public static final int REQUEST_ALBUMS = MainActivity.REQUEST_ALBUMS;
PreviousStepFlow previousStepFlow;
private LoadingControl loadingControl;
EditText editTitle;
EditText editTags;
EditText albumsText;
Switch privateSwitch;
Switch twitterSwitch;
Switch facebookSwitch;
StringMapParcelableWrapper albumsWrapper;
static SyncUploadFragment instance;
@ -56,6 +64,7 @@ public class SyncUploadFragment extends CommonFragment
setHasOptionsMenu(true);
instance = this;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
@ -80,6 +89,12 @@ public class SyncUploadFragment extends CommonFragment
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(SELECTED_ALBUMS, (Parcelable) albumsText.getTag());
}
@Override
public void onDestroy() {
super.onDestroy();
@ -101,11 +116,16 @@ public class SyncUploadFragment extends CommonFragment
super.onCreateView(inflater, container, savedInstanceState);
View v = inflater.inflate(R.layout.fragment_sync_upload_settings,
container, false);
init(v);
return v;
}
public void init(View v)
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
init(view, savedInstanceState);
}
public void init(View v, Bundle savedInstanceState)
{
final Button uploadBtn = (Button) v.findViewById(R.id.uploadBtn);
uploadBtn.setOnClickListener(new OnClickListener()
@ -123,10 +143,20 @@ public class SyncUploadFragment extends CommonFragment
R.id.edit_title);
editTags = (EditText) v.findViewById(
R.id.edit_tags);
albumsText = ((EditText) v.findViewById(R.id.edit_albums));
if (savedInstanceState != null)
{
albumsWrapper = savedInstanceState.getParcelable(SELECTED_ALBUMS);
}
if (albumsWrapper != null)
{
albumsText.setTag(albumsWrapper);
}
privateSwitch = (Switch) v.findViewById(R.id.private_switch);
twitterSwitch = (Switch) v.findViewById(R.id.twitter_switch);
facebookSwitch = (Switch) v.findViewById(R.id.facebook_switch);
albumsText.setOnClickListener(this);
privateSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
@ -168,6 +198,39 @@ public class SyncUploadFragment extends CommonFragment
facebookSwitch.setEnabled(enabled);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.edit_albums: {
TrackerUtils.trackButtonClickEvent("select_albums", SyncUploadFragment.this);
Intent i = new Intent(getActivity(), SelectAlbumsActivity.class);
i.putExtra(SelectAlbumsActivity.SELECTED_ALBUMS,
(Parcelable) albumsText.getTag());
startActivityForResult(i, REQUEST_ALBUMS);
}
break;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_ALBUMS:
if (resultCode == Activity.RESULT_OK && data.getExtras() != null) {
StringMapParcelableWrapper albumsWrapper = data.getExtras().getParcelable(
SelectAlbumsActivity.SELECTED_ALBUMS);
Map<String, String> albums = albumsWrapper.getMap();
albumsText.setText(AlbumUtils.getAlbumsString(albums));
albumsText.setTag(albumsWrapper);
this.albumsWrapper = albumsWrapper;
}
break;
default:
break;
}
}
void uploadSelectedFiles(
final boolean checkTwitter,
final boolean checkFacebook)
@ -259,6 +322,13 @@ public class SyncUploadFragment extends CommonFragment
.getText().toString());
metaData.setTags(editTags
.getText().toString());
StringMapParcelableWrapper albumsWrapper = (StringMapParcelableWrapper) albumsText
.getTag();
if (albumsWrapper != null)
{
metaData.setAlbums(albumsWrapper.getMap());
}
metaData.setPrivate(privateSwitch.isChecked());
boolean shareOnFacebook = facebookSwitch.isChecked();
boolean shareOnTwitter = twitterSwitch.isChecked();

View file

@ -5,6 +5,7 @@ import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.holoeverywhere.LayoutInflater;
@ -20,6 +21,7 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
@ -38,6 +40,7 @@ import com.trovebox.android.app.common.CommonFragment;
import com.trovebox.android.app.facebook.FacebookProvider;
import com.trovebox.android.app.facebook.FacebookUtils;
import com.trovebox.android.app.feather.FeatherFragment;
import com.trovebox.android.app.model.utils.AlbumUtils;
import com.trovebox.android.app.model.utils.TagUtils;
import com.trovebox.android.app.net.UploadMetaData;
import com.trovebox.android.app.net.account.AccountLimitUtils;
@ -51,6 +54,7 @@ import com.trovebox.android.app.util.GuiUtils;
import com.trovebox.android.app.util.ImageUtils;
import com.trovebox.android.app.util.ProgressDialogLoadingControl;
import com.trovebox.android.app.util.TrackerUtils;
import com.trovebox.android.app.util.data.StringMapParcelableWrapper;
/**
* This activity handles uploading pictures to Trovebox.
@ -65,6 +69,7 @@ public class UploadActivity extends CommonActivity {
private static final int REQUEST_GALLERY = 0;
private static final int REQUEST_CAMERA = 1;
private static final int REQUEST_TAGS = 2;
private static final int REQUEST_ALBUMS = 3;
private static final int ACTION_REQUEST_FEATHER = 100;
public final static int AUTHORIZE_ACTIVITY_REQUEST_CODE = 10;
@ -125,6 +130,7 @@ public class UploadActivity extends CommonActivity {
static final String UPLOAD_IMAGE_FILE = "UploadActivityFile";
static final String UPLOAD_IMAGE_FILE_ORIGINAL = "UploadActivityFileOriginal";
static final String UPLOAD_IMAGE_FILE_URI = "UploadActivityFileUri";
static final String SELECTED_ALBUMS = "SELECTED_ALBUMS";
private File mUploadImageFile;
private File mUploadImageFileOriginal;
@ -137,6 +143,7 @@ public class UploadActivity extends CommonActivity {
FeatherFragment featherFragment;
EditText tagsText;
EditText albumsText;
private SelectImageDialogFragment imageSelectionFragment;
/**
* This variable controls whether the dialog should be shown in the
@ -203,7 +210,7 @@ public class UploadActivity extends CommonActivity {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
init(view);
init(view, savedInstanceState);
}
@Override
@ -211,13 +218,14 @@ public class UploadActivity extends CommonActivity {
super.onSaveInstanceState(outState);
outState.putSerializable(UPLOAD_IMAGE_FILE, mUploadImageFile);
outState.putSerializable(UPLOAD_IMAGE_FILE_ORIGINAL, mUploadImageFileOriginal);
outState.putParcelable(SELECTED_ALBUMS, (Parcelable) albumsText.getTag());
if (fileUri != null)
{
outState.putString(UPLOAD_IMAGE_FILE_URI, fileUri.toString());
}
}
void init(View v)
void init(View v, Bundle savedInstanceState)
{
final Button buttonUpload = (Button) v.findViewById(R.id.button_upload);
buttonUpload.setOnClickListener(this);
@ -226,6 +234,11 @@ public class UploadActivity extends CommonActivity {
v.findViewById(R.id.image_upload).setOnClickListener(this);
v.findViewById(R.id.button_edit).setOnClickListener(this);
tagsText = ((EditText) v.findViewById(R.id.edit_tags));
albumsText = ((EditText) v.findViewById(R.id.edit_albums));
if (savedInstanceState != null)
{
albumsText.setTag(savedInstanceState.getParcelable(SELECTED_ALBUMS));
}
uploadOriginalSwitch = (Switch) v.findViewById(R.id.upload_original_switch);
privateSwitch = (Switch) v.findViewById(R.id.private_switch);
@ -241,6 +254,8 @@ public class UploadActivity extends CommonActivity {
});
reinitShareSwitches();
albumsText.setOnClickListener(this);
Intent intent = getActivity().getIntent();
boolean showOptions = true;
if (intent != null)
@ -271,6 +286,10 @@ public class UploadActivity extends CommonActivity {
.getDescription());
((EditText) v.findViewById(R.id.edit_tags))
.setText(pendingUpload.getMetaData().getTags());
Map<String, String> albums = pendingUpload.getMetaData().getAlbums();
albumsText.setText(AlbumUtils.getAlbumsString(albums));
albumsText.setTag(albums == null ? null
: new StringMapParcelableWrapper(albums));
privateSwitch.setChecked(pendingUpload.getMetaData().isPrivate());
twitterSwitch.setChecked(pendingUpload.isShareOnTwitter());
facebookSwitch.setChecked(pendingUpload.isShareOnFacebook());
@ -320,6 +339,7 @@ public class UploadActivity extends CommonActivity {
twitterSwitch.setEnabled(enabled);
facebookSwitch.setEnabled(enabled);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@ -341,6 +361,15 @@ public class UploadActivity extends CommonActivity {
tagsText.setText(selectedTags);
}
break;
case REQUEST_ALBUMS:
if (resultCode == RESULT_OK && data.getExtras() != null) {
StringMapParcelableWrapper albumsWrapper = data.getExtras().getParcelable(
SelectAlbumsActivity.SELECTED_ALBUMS);
Map<String, String> albums = albumsWrapper.getMap();
albumsText.setText(AlbumUtils.getAlbumsString(albums));
albumsText.setTag(albumsWrapper);
}
break;
case REQUEST_GALLERY:
if (resultCode == RESULT_OK && data.getData() != null) {
setSelectedImageUri(data.getData());
@ -519,11 +548,20 @@ public class UploadActivity extends CommonActivity {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.select_tags:
case R.id.select_tags: {
TrackerUtils.trackButtonClickEvent("select_tags", getActivity());
Intent i = new Intent(getActivity(), SelectTagsActivity.class);
i.putExtra(SelectTagsActivity.SELECTED_TAGS, tagsText.getText().toString());
startActivityForResult(i, REQUEST_TAGS);
}
break;
case R.id.edit_albums: {
TrackerUtils.trackButtonClickEvent("select_albums", getActivity());
Intent i = new Intent(getActivity(), SelectAlbumsActivity.class);
i.putExtra(SelectAlbumsActivity.SELECTED_ALBUMS,
(Parcelable) albumsText.getTag());
startActivityForResult(i, REQUEST_ALBUMS);
}
break;
case R.id.button_upload:
TrackerUtils.trackButtonClickEvent("button_upload", getActivity());
@ -682,6 +720,12 @@ public class UploadActivity extends CommonActivity {
tags = TagUtils.getTagsString(tagsSet);
}
metaData.setTags(tags);
StringMapParcelableWrapper albumsWrapper = (StringMapParcelableWrapper) albumsText
.getTag();
if (albumsWrapper != null)
{
metaData.setAlbums(albumsWrapper.getMap());
}
metaData.setPrivate(isPrivate);
return metaData;
}

View file

@ -327,6 +327,10 @@ public abstract class ImageWorker {
try
{
data = params[0];
if (data == null)
{
return null;
}
final String dataString = String.valueOf(data);
Bitmap bitmap = null;

View file

@ -4,12 +4,15 @@ package com.trovebox.android.app.model;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Class representing a Album on Trovebox.
*
* @author Eugene Popovich
*/
public class Album
public class Album implements Parcelable
{
public static final int VISIBILITY_VISIBLE = 1;
public static final int VISIBILITY_INVISIBLE = 0;
@ -20,6 +23,11 @@ public class Album
protected int mCount;
protected Photo mCover;
private Album()
{
}
/**
* Creates a Album object from json.
*
@ -71,4 +79,44 @@ public class Album
{
return mCover;
}
/*****************************
* PARCELABLE IMPLEMENTATION *
*****************************/
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(mId);
out.writeString(mOwner);
out.writeString(mName);
out.writeInt(mVisible);
out.writeInt(mCount);
out.writeParcelable(mCover, flags);
}
public static final Parcelable.Creator<Album> CREATOR = new Parcelable.Creator<Album>() {
@Override
public Album createFromParcel(Parcel in) {
return new Album(in);
}
@Override
public Album[] newArray(int size) {
return new Album[size];
}
};
private Album(Parcel in) {
this();
mId = in.readString();
mOwner = in.readString();
mName = in.readString();
mVisible = in.readInt();
mCount = in.readInt();
mCover = in.readParcelable(Album.class.getClassLoader());
}
}

View file

@ -0,0 +1,35 @@
package com.trovebox.android.app.model.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.trovebox.android.app.net.UploadMetaDataUtils;
import com.trovebox.android.app.util.compare.ToStringComparator;
/**
* @author Eugene Popovich
*/
public class AlbumUtils {
/**
* Get the album names string from the albums map
*
* @param albums
* @return
*/
public static String getAlbumsString(Map<String, String> albums)
{
Collection<String> values = albums == null ? null : albums.values();
if (values != null)
{
values = new ArrayList<String>(values);
Collections.sort((List<String>) values, new ToStringComparator());
}
return UploadMetaDataUtils.getCommaSeparatedString(values);
}
}

View file

@ -4,11 +4,12 @@ package com.trovebox.android.app.model.utils;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import android.text.TextUtils;
import com.trovebox.android.app.net.UploadMetaDataUtils;
/**
* @author Eugene Popovich
*/
@ -39,19 +40,7 @@ public class TagUtils {
*/
public static String getTagsString(Collection<String> tags)
{
if (tags != null && !tags.isEmpty())
{
Iterator<String> it = tags.iterator();
StringBuilder sb = new StringBuilder(it.next());
while (it.hasNext())
{
sb.append("," + it.next());
}
return sb.toString();
} else
{
return null;
}
return UploadMetaDataUtils.getCommaSeparatedString(tags);
}
}

View file

@ -46,7 +46,7 @@ public class ApiBase {
public final static String TAG = ApiBase.class.getSimpleName();
private Context context;
static int NetworkConnectionTimeout_ms = 10000;
public static int NetworkConnectionTimeout_ms = 10000;
public ApiBase(Context context) {
this.context = context;
@ -85,6 +85,24 @@ public class ApiBase {
*
* @param request request to perform
* @param listener Progress Listener with callback on progress
* @param connectionTimeout the connection and socket timeout
* @return the response from the API
* @throws ClientProtocolException
* @throws IOException
*/
public ApiResponse execute(ApiRequest request, ProgressListener listener, int connectionTimeout)
throws ClientProtocolException, IOException {
return execute(request, Preferences.getServer(this.context),
Preferences.getOAuthConsumer(context), listener, connectionTimeout);
}
/**
* Execute a request to the API.
*
* @param request request to perform
* @param baseUrl the base server url
* @param consumer the oauth consumer key to sign request
* @param listener Progress Listener with callback on progress
* @return the response from the API
* @throws ClientProtocolException
* @throws IOException
@ -92,6 +110,24 @@ public class ApiBase {
public ApiResponse execute(ApiRequest request, String baseUrl, OAuthConsumer consumer,
ProgressListener listener)
throws ClientProtocolException, IOException {
return execute(request, baseUrl, consumer, listener, NetworkConnectionTimeout_ms);
}
/**
* Execute a request to the API.
*
* @param request request to perform
* @param baseUrl the base server url
* @param consumer the oauth consumer key to sign request
* @param listener Progress Listener with callback on progress
* @param connectionTimeout the connection and socket timeout
* @return the response from the API
* @throws ClientProtocolException
* @throws IOException
*/
public ApiResponse execute(ApiRequest request, String baseUrl, OAuthConsumer consumer,
ProgressListener listener, int connectionTimeout)
throws ClientProtocolException, IOException {
// PoolingClientConnectionManager();
HttpParams params = new BasicHttpParams();
@ -99,9 +135,9 @@ public class ApiBase {
HttpConnectionParams.setStaleCheckingEnabled(
params, false);
HttpConnectionParams.setConnectionTimeout(params,
NetworkConnectionTimeout_ms);
connectionTimeout);
HttpConnectionParams.setSoTimeout(params,
NetworkConnectionTimeout_ms);
connectionTimeout);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
DefaultHttpClient httpClient = new DefaultHttpClient(params);

View file

@ -212,6 +212,10 @@ public class TroveboxApi extends ApiBase implements ITroveboxApi {
if (metaData.getTags() != null) {
request.addParameter("tags", metaData.getTags());
}
if (metaData.getAlbums() != null)
{
request.addParameter("albums", UploadMetaDataUtils.getAlbumIds(metaData));
}
if (metaData.getTitle() != null) {
request.addParameter("title", metaData.getTitle());
}
@ -222,7 +226,7 @@ public class TroveboxApi extends ApiBase implements ITroveboxApi {
Integer.toString(metaData.getPermission()));
request.addFileParameter("photo", imageFile);
ApiResponse response = execute(request, progressListener);
ApiResponse response = execute(request, progressListener, NetworkConnectionTimeout_ms * 12);
return new UploadResponse(response.getJSONObject());
}

View file

@ -1,6 +1,8 @@
package com.trovebox.android.app.net;
import java.util.Map;
import com.trovebox.android.app.model.Photo;
public class UploadMetaData {
@ -8,6 +10,7 @@ public class UploadMetaData {
private String mDescription;
private String mTags;
private int mPermission;
private Map<String, String> mAlbums;
public void setTitle(String title) {
mTitle = title;
@ -48,4 +51,12 @@ public class UploadMetaData {
public boolean isPrivate() {
return getPermission() == Photo.PERMISSION_PRIVATE;
}
public Map<String, String> getAlbums() {
return mAlbums;
}
public void setAlbums(Map<String, String> albums) {
this.mAlbums = albums;
}
}

View file

@ -0,0 +1,67 @@
package com.trovebox.android.app.net;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
/**
* @author Eugene Popovich
*/
public class UploadMetaDataUtils {
/**
* Get the album ids comma separated string from the upload meta data
*
* @param uploadMetaData
* @return
*/
public static String getAlbumIds(UploadMetaData uploadMetaData)
{
Map<String, String> albums = uploadMetaData.getAlbums();
String result = null;
if(albums != null)
{
result = getCommaSeparatedString(albums.keySet());
}
return result;
}
/**
* Get the album names comma separated string from the upload meta data
*
* @param uploadMetaData
* @return
*/
public static String getAlbumNames(UploadMetaData uploadMetaData)
{
Map<String, String> albums = uploadMetaData.getAlbums();
String result = null;
if (albums != null)
{
result = getCommaSeparatedString(albums.values());
}
return result;
}
/**
* Get comma separated string from collection
*
* @param strings
* @return
*/
public static String getCommaSeparatedString(Collection<String> strings)
{
if (strings != null && !strings.isEmpty())
{
Iterator<String> it = strings.iterator();
StringBuilder sb = new StringBuilder(it.next());
while (it.hasNext())
{
sb.append("," + it.next());
}
return sb.toString();
} else
{
return null;
}
}
}

View file

@ -3,7 +3,11 @@ package com.trovebox.android.app.provider;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.json.JSONException;
import org.json.JSONObject;
@ -26,6 +30,7 @@ public class UploadsProviderAccessor {
private static final String JSON_TITLE = "title";
private static final String JSON_DESCRIPTION = "description";
private static final String JSON_TAGS = "tags";
private static final String JSON_ALBUMS = "albums";
private static final String JSON_PERMISSION = "permission";
private final Context mContext;
@ -53,6 +58,15 @@ public class UploadsProviderAccessor {
if (metaData.getTags() != null) {
data.put(JSON_TAGS, metaData.getTags());
}
if (metaData.getAlbums() != null)
{
JSONObject albums = new JSONObject();
for (Entry<String, String> album : metaData.getAlbums().entrySet())
{
albums.put(album.getKey(), album.getValue());
}
data.put(JSON_ALBUMS, albums);
}
data.put(JSON_PERMISSION, metaData.getPermission());
values.put(UploadsProvider.KEY_METADATA_JSON, data.toString());
} catch (JSONException e) {
@ -197,6 +211,21 @@ public class UploadsProviderAccessor {
if (jsonMeta.has(JSON_TAGS)) {
metaData.setTags(jsonMeta.optString(JSON_TAGS));
}
if (jsonMeta.has(JSON_ALBUMS))
{
JSONObject jsonAlbums = jsonMeta.optJSONObject(JSON_ALBUMS);
if (jsonAlbums != null)
{
Iterator<?> albumIdsIterator = jsonAlbums.keys();
Map<String, String> albums = new HashMap<String, String>();
while (albumIdsIterator.hasNext())
{
String albumId = (String) albumIdsIterator.next();
albums.put(albumId, jsonAlbums.optString(albumId));
}
metaData.setAlbums(albums);
}
}
if (jsonMeta.has(JSON_TITLE)) {
metaData.setTitle(jsonMeta.optString(JSON_TITLE));
}

View file

@ -0,0 +1,85 @@
package com.trovebox.android.app.ui.adapter;
import com.trovebox.android.app.Preferences;
import com.trovebox.android.app.R;
import com.trovebox.android.app.model.Album;
import com.trovebox.android.app.net.AlbumsResponse;
import com.trovebox.android.app.net.ITroveboxApi;
import com.trovebox.android.app.net.Paging;
import com.trovebox.android.app.net.TroveboxResponseUtils;
import com.trovebox.android.app.util.CommonUtils;
import com.trovebox.android.app.util.GuiUtils;
import com.trovebox.android.app.util.LoadingControl;
/**
* An endless adapter for albums
*
* @author Eugene Popovich
*/
public abstract class AlbumsEndlessAdapter extends EndlessAdapter<Album> {
public static final int DEFAULT_PAGE_SIZE = 20;
private final String TAG = AlbumsEndlessAdapter.class.getSimpleName();
private final ITroveboxApi mTroveboxApi;
private LoadingControl loadingControl;
public AlbumsEndlessAdapter(LoadingControl loadingControl)
{
this(DEFAULT_PAGE_SIZE, loadingControl);
}
public AlbumsEndlessAdapter(int pageSize, LoadingControl loadingControl) {
super(pageSize);
this.loadingControl = loadingControl;
mTroveboxApi = Preferences.getApi();
loadFirstPage();
}
@Override
public long getItemId(int position)
{
return ((Album) getItem(position)).getId().hashCode();
}
@Override
public LoadResponse loadItems(int page)
{
if (CommonUtils.checkLoggedInAndOnline())
{
try
{
AlbumsResponse response = mTroveboxApi.getAlbums(new Paging(page,
getPageSize()));
if (TroveboxResponseUtils.checkResponseValid(response))
{
return new LoadResponse(response.getAlbums(), response.hasNextPage());
}
} catch (Exception e)
{
GuiUtils.error(
TAG,
R.string.errorCouldNotLoadNextAlbumsInList,
e);
}
}
return new LoadResponse(null, false);
}
@Override
protected void onStartLoading()
{
if (loadingControl != null)
{
loadingControl.startLoading();
}
}
@Override
protected void onStoppedLoading()
{
if (loadingControl != null)
{
loadingControl.stopLoading();
}
}
}

View file

@ -0,0 +1,85 @@
package com.trovebox.android.app.ui.adapter;
import java.util.HashMap;
import java.util.Map;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import com.trovebox.android.app.model.Album;
import com.trovebox.android.app.util.LoadingControl;
/**
* @author Eugene Popovich
*/
public abstract class MultiSelectAlbumsAdapter extends AlbumsEndlessAdapter
{
static final String TAG = MultiSelectAlbumsAdapter.class.getSimpleName();
protected Map<String, String> checkedAlbums = new HashMap<String, String>();
public MultiSelectAlbumsAdapter(LoadingControl loadingControl)
{
super(loadingControl);
}
@Override
public long getItemId(int position)
{
return ((Album) getItem(position)).getId().hashCode();
}
/**
* Init the album checkbox
*
* @param album
* @param checkBox
*/
public void initAlbumCheckbox(Album album, CheckBox checkBox) {
checkBox.setChecked(isChecked(album));
checkBox.setTag(album);
}
/**
* Should be called when album view is clicked
*
* @param buttonView
* @param isChecked
*/
public void onAlbumViewClicked(
CompoundButton buttonView,
boolean isChecked) {
Album album = (Album) buttonView.getTag();
if (isChecked)
{
checkedAlbums.put(album.getId(), album.getName());
}
else
{
checkedAlbums.remove(album.getId());
}
buttonView.setChecked(isChecked);
}
protected boolean isChecked(Album album)
{
boolean result = false;
if (album != null)
{
return isChecked(album.getId());
}
return result;
}
protected boolean isChecked(String albumId)
{
boolean result = false;
if (albumId != null)
{
result = checkedAlbums.containsKey(albumId);
}
return result;
}
}

View file

@ -34,6 +34,17 @@ public class GuiUtils
}
/**
* Post action to handler
*
* @param action
*/
public static final void post(Runnable action)
{
CommonUtils.debug(TAG, "post");
mHandler.post(action);
}
/**
* Run action in UI thread
*

View file

@ -0,0 +1,71 @@
package com.trovebox.android.app.util.data;
import java.util.HashMap;
import java.util.Map;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Simple class to wrap string map as a {@link Parcelable} object
*
* @author Eugene Popovich
*/
public class StringMapParcelableWrapper implements Parcelable {
Map<String, String> map;
public StringMapParcelableWrapper() {
map = new HashMap<String, String>();
}
public StringMapParcelableWrapper(Map<String, String> map) {
this.map = map;
}
public Map<String, String> getMap()
{
return map;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int parcelableFlags) {
final int N = map.size();
dest.writeInt(N);
if (N > 0) {
for (Map.Entry<String, String> entry : map.entrySet()) {
dest.writeString(entry.getKey());
String dat = entry.getValue();
dest.writeString(dat);
// etc...
}
}
}
public static final Creator<StringMapParcelableWrapper> CREATOR = new Creator<StringMapParcelableWrapper>() {
@Override
public StringMapParcelableWrapper createFromParcel(Parcel source) {
return new StringMapParcelableWrapper(source);
}
@Override
public StringMapParcelableWrapper[] newArray(int size) {
return new StringMapParcelableWrapper[size];
}
};
private StringMapParcelableWrapper(Parcel source) {
this();
final int N = source.readInt();
for (int i = 0; i < N; i++) {
String key = source.readString();
String dat = source.readString();
// etc...
map.put(key, dat);
}
}
}

View file

@ -6,28 +6,29 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.client.ClientProtocolException;
import org.json.JSONException;
import com.trovebox.android.app.TroveboxApplication;
import com.trovebox.android.app.model.Photo;
import com.trovebox.android.app.net.ITroveboxApi;
import com.trovebox.android.app.net.TroveboxApi;
import com.trovebox.android.app.net.PhotoResponse;
import com.trovebox.android.app.net.PhotosResponse;
import com.trovebox.android.app.net.TagsResponse;
import com.trovebox.android.app.net.UploadMetaData;
import com.trovebox.android.app.net.UploadResponse;
import com.trovebox.android.app.util.TrackerUtils;
import com.trovebox.android.test.util.FileUtils;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Environment;
import android.test.ApplicationTestCase;
import com.trovebox.android.app.TroveboxApplication;
import com.trovebox.android.app.model.Photo;
import com.trovebox.android.app.net.ITroveboxApi;
import com.trovebox.android.app.net.PhotoResponse;
import com.trovebox.android.app.net.PhotosResponse;
import com.trovebox.android.app.net.TagsResponse;
import com.trovebox.android.app.net.TroveboxApi;
import com.trovebox.android.app.net.UploadMetaData;
import com.trovebox.android.app.net.UploadResponse;
import com.trovebox.android.app.util.TrackerUtils;
import com.trovebox.android.test.util.FileUtils;
public class TroveboxApiTest extends ApplicationTestCase<TroveboxApplication>
{
@ -94,6 +95,10 @@ public class TroveboxApiTest extends ApplicationTestCase<TroveboxApplication>
settings.setTitle("Android");
settings.setDescription("Nice picture of an android");
settings.setTags("test");
Map<String, String> albums = new HashMap<String, String>();
albums.put("1", "test");
albums.put("2", "test2");
settings.setAlbums(albums);
settings.setPrivate(false);
try {
UploadResponse resp = mApi.uploadPhoto(file, settings, null);