package com.rafali.flickruploader.ui.activity; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Point; import android.media.MediaScannerConnection; import android.media.MediaScannerConnection.OnScanCompletedListener; import android.net.Uri; import android.os.Bundle; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.google.android.gms.analytics.GoogleAnalytics; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.paypal.android.sdk.payments.PayPalService; import com.rafali.common.STR; import com.rafali.common.ToolString; import com.rafali.flickruploader.FlickrUploader; import com.rafali.flickruploader.api.FlickrApi; import com.rafali.flickruploader.enums.MEDIA_TYPE; import com.rafali.flickruploader.enums.PRIVACY; import com.rafali.flickruploader.enums.VIEW_GROUP_TYPE; import com.rafali.flickruploader.enums.VIEW_SIZE; import com.rafali.flickruploader.model.Folder; import com.rafali.flickruploader.model.Media; import com.rafali.flickruploader.service.UploadService; import com.rafali.flickruploader.service.UploadService.BasicUploadProgressListener; import com.rafali.flickruploader.service.UploadService.UploadProgressListener; import com.rafali.flickruploader.tool.Utils; import com.rafali.flickruploader.tool.Utils.Callback; import com.rafali.flickruploader.ui.DrawerContentView; import com.rafali.flickruploader.ui.DrawerHandleView; import com.rafali.flickruploader.ui.widget.SlidingDrawer; import com.rafali.flickruploader.ui.widget.StickyHeaderListView; import com.rafali.flickruploader.ui.widget.StickyHeaderListView.Header; import com.rafali.flickruploader.ui.widget.StickyHeaderListView.HeaderAdapter; import com.rafali.flickruploader2.R; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.Background; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.UiThread; import org.androidannotations.annotations.ViewById; import org.androidannotations.api.BackgroundExecutor; import org.slf4j.LoggerFactory; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import uk.co.senab.bitmapcache.CacheableBitmapDrawable; import uk.co.senab.bitmapcache.CacheableImageView; @EActivity(R.layout.flickr_uploader_activity) public class FlickrUploaderActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener { static final org.slf4j.Logger LOG = LoggerFactory.getLogger(FlickrUploaderActivity.class); private static FlickrUploaderActivity instance; private FlickrUploaderActivity activity = this; @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); LOG.debug("onCreate " + bundle); load(); UploadService.wake(); if (!FlickrApi.isAuthentified()) { Utils.confirmSignIn(activity); } if (instance != null) instance.finish(); instance = activity; Utils.checkPremium(false, new Utils.Callback<Boolean>() { @Override public void onResult(Boolean result) { checkPremium(); renderMenu(); } }); handleIntent(getIntent()); } @UiThread void checkPremium() { if (!Utils.isPremium() && !Utils.isTrial()) { Utils.showPremiumDialog(activity, new Callback<Boolean>() { @Override public void onResult(Boolean result) { renderMenu(); } }); } } boolean finishOnClose = false; @Background void handleIntent(Intent intent) { if (intent != null) { String action = intent.getAction(); String type = intent.getType(); List<String> paths = null; if (Intent.ACTION_SEND.equals(action) && type != null) { if (type.startsWith("image/") || type.startsWith("video/")) { Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); String path = Utils.getRealPathFromURI(imageUri); if (path != null) { paths = Arrays.asList(path); } } finishOnClose = true; } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { if (type.startsWith("image/") || type.startsWith("video/")) { List<Uri> imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); paths = new ArrayList<String>(); for (Uri imageUri : imageUris) { String path = Utils.getRealPathFromURI(imageUri); if (path != null) { paths.add(path); } } } finishOnClose = true; } if (paths != null && !paths.isEmpty()) { List<Media> medias = Utils.loadMedia(true); Iterator<Media> it = medias.iterator(); while (it.hasNext()) { Media media = it.next(); if (paths.contains(media.getPath())) { selectedMedia.add(media); } } if (selectedMedia.isEmpty()) { Utils.toast("No media found"); } else { confirmUpload(selectedMedia); } } } } SimpleDateFormat format = new SimpleDateFormat("MMMM, yyyy", Locale.US); List<Object> thumbItems; List<Media> medias; void load() { load(false); } @Background(serial = "load") void load(boolean refresh) { runOnUiThread(new Runnable() { @Override public void run() { swipeContainer.setRefreshing(true); } }); medias = Utils.loadMedia(refresh); boolean showPhotos = Utils.getShowPhotos(); boolean showVideos = Utils.getShowVideos(); boolean showUploaded = Utils.getShowUploaded(); boolean showNotUploaded = Utils.getShowNotUploaded(); Iterator<Media> it = medias.iterator(); while (it.hasNext()) { Media media = it.next(); if (!showPhotos && media.isPhoto() || !showVideos && media.isVideo()) { it.remove(); } else if (!showUploaded && media.isUploaded() || !showNotUploaded && !media.isUploaded()) { it.remove(); } } if (Utils.getViewGroupType() == VIEW_GROUP_TYPE.date) { Collections.sort(medias, Utils.MEDIA_COMPARATOR); } else { Comparator<Media> folderComparator = new Comparator<Media>() { @Override public int compare(Media arg0, Media arg1) { int compareTo = arg0.getFolderName().compareTo(arg1.getFolderName()); if (compareTo == 0) { compareTo = arg0.getFolderPath().compareTo(arg1.getFolderPath()); if (compareTo == 0) { return Utils.MEDIA_COMPARATOR.compare(arg0, arg1); } } return compareTo; } }; Collections.sort(medias, folderComparator); } computeHeaders(true); renderListView(); } @UiThread void setLoading(int progress) { if (message != null) { message.setText("Loading… " + progress + "%"); } } @UiThread void computeHeaders(boolean clearHeaders) { headers = new ArrayList<Header>(); if (clearHeaders) { headerMap = new HashMap<Media, Header>(); headerIds = new HashMap<String, Header>(); } thumbItems = new ArrayList<Object>(); computeNbColumn(); Media[] mediaRow = null; int currentIndex = 0; for (Media media : medias) {// FIXME concurrent modification Header header; if (Utils.getViewGroupType() == VIEW_GROUP_TYPE.date) { String id = format.format(new Date(media.getTimestampCreated())); header = headerIds.get(id); if (header == null) { header = new Header(id, id); headerIds.put(id, header); } } else { String id = media.getFolderPath(); header = headerIds.get(id); if (header == null) { header = new Header(id, media.getFolderName()); headerIds.put(id, header); } } if (!headers.contains(header)) { headers.add(header); thumbItems.add(header); mediaRow = null; header.count = 1; } else { header.count++; } if (header.collapsed) { continue; } headerMap.put(media, header); if (mediaRow == null || currentIndex >= mediaRow.length) { mediaRow = new Media[computed_nb_column]; currentIndex = 0; thumbItems.add(mediaRow); } mediaRow[currentIndex] = media; currentIndex++; } if (listView != null) { renderHeader(listView.getFloatingSectionHeader()); photoAdapter.notifyDataSetChanged(); } } Map<Media, Header> headerMap; List<Header> headers; Map<String, Header> headerIds; @Override protected void onStart() { super.onStart(); GoogleAnalytics.getInstance(activity).reportActivityStart(activity); } @Override protected void onStop() { super.onStop(); GoogleAnalytics.getInstance(activity).reportActivityStop(activity); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); renderMenu(); LOG.debug("onNewIntent : " + intent); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); LOG.debug("onConfigurationChanged"); computeHeaders(false); } public static FlickrUploaderActivity getInstance() { return instance; } @Override protected void onDestroy() { LOG.debug("onDestroy"); super.onDestroy(); if (instance == this) instance = null; destroyed = true; UploadService.unregister(drawerHandleView); UploadService.unregister(drawerContentView); UploadService.unregister(uploadProgressListener); stopService(new Intent(this, PayPalService.class)); } public boolean destroyed = false; PhotoAdapter photoAdapter = new PhotoAdapter(); @ViewById(R.id.message) TextView message; @UiThread void renderListView() { if (listView != null) { swipeContainer.setRefreshing(false); if (listView.getAdapter() == null) { listView.setDividerHeight(0); listView.setAdapter(photoAdapter); listView.setFastScrollEnabled(true); } else { photoAdapter.notifyDataSetChanged(); } if (medias != null && medias.isEmpty()) { message.setVisibility(View.VISIBLE); if (Utils.loadMedia(false).isEmpty()) { message.setText("No media found"); } else { message.setText("No media matching your filter"); } } else { message.setVisibility(View.GONE); } } } @ViewById(R.id.drawer_handle) DrawerHandleView drawerHandleView; @ViewById(R.id.drawer_content) DrawerContentView drawerContentView; @ViewById(R.id.slidingDrawer) SlidingDrawer slidingDrawer; @ViewById(R.id.swipe_container) SwipeRefreshLayout swipeContainer; @AfterViews void afterViews() { UploadService.register(drawerHandleView); UploadService.register(drawerContentView); UploadService.register(uploadProgressListener); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setTitle(null); actionBar.setIcon(null); actionBar.setDisplayShowHomeEnabled(false); } slidingDrawer.setOnDrawerOpenListener(new SlidingDrawer.OnDrawerOpenListener() { @Override public void onDrawerOpened() { Utils.setBooleanProperty(STR.show_sliding_demo, false); drawerContentView.updateLists(); } }); swipeContainer.setOnRefreshListener(this); // swipeContainer.setColorScheme(android.R.color.white, android.R.color.white, android.R.color.black, android.R.color.darker_gray); } UploadProgressListener uploadProgressListener = new BasicUploadProgressListener() { @Override public void onProcessed(Media media) { if (!Utils.getShowUploaded() || !Utils.getShowNotUploaded()) { load(); } update(media); } }; void computeNbColumn() { Point size = new Point(); WindowManager wm = (WindowManager) FlickrUploader.getAppContext().getSystemService(Context.WINDOW_SERVICE); wm.getDefaultDisplay().getSize(size); int screenWidthPx = size.x; VIEW_SIZE view_size = Utils.getViewSize(); final int req_width; final int nb_column; if (view_size == VIEW_SIZE.small) { req_width = Utils.getScaledSize(64); nb_column = Math.max(4, screenWidthPx / req_width); } else if (view_size == VIEW_SIZE.large) { req_width = Utils.getScaledSize(192); nb_column = Math.max(2, screenWidthPx / req_width); } else { req_width = Utils.getScaledSize(128); nb_column = Math.max(3, screenWidthPx / req_width); } if (view_size == VIEW_SIZE.small) { computed_req_height = screenWidthPx / nb_column; } else { computed_req_height = screenWidthPx / nb_column * 3 / 4; } computed_req_width = screenWidthPx / nb_column; computed_nb_column = nb_column; // LOG.info(view_size + ", nb_column : " + nb_column + // ", screenWidthPx : " + screenWidthPx); } int computed_req_height = 100; int computed_req_width = 100; int computed_nb_column = 2; @UiThread void confirmUpload(final Collection<Media> mediasToUpload) { if (FlickrApi.isAuthentified()) { new AlertDialog.Builder(activity).setTitle("Upload to").setPositiveButton(null, null).setNegativeButton(null, null).setCancelable(true) .setItems(new String[]{"Default set (" + STR.instantUpload + ")", "One set per folder", "New set…", "Existing set…"}, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: enqueue(Lists.newArrayList(mediasToUpload), STR.instantUpload); clearSelection(); break; case 1: Multimap<String, Media> multimap = HashMultimap.create(); for (Media media : mediasToUpload) { multimap.put(media.getFolderName(), media); } for (String folderName : multimap.keySet()) { enqueue(multimap.get(folderName), folderName); } clearSelection(); break; case 2: showNewSetDialog(null); break; case 3: showExistingSetDialog(); break; default: break; } LOG.debug("which : " + which); } }).show(); } else { Utils.confirmSignIn(activity); } } @UiThread void clearSelection() { selectedMedia.clear(); for (Header header : headers) { header.selected = false; } refresh(); } @UiThread void showExistingSetDialog() { Utils.showExistingSetDialog(activity, new Callback<String>() { @Override public void onResult(String result) { enqueue(Lists.newArrayList(selectedMedia), result); clearSelection(); } }, null); } @UiThread void showNewSetDialog(final Folder folder) { showNewSetDialog(activity, folder == null ? null : folder.getName(), new Callback<String>() { @Override public void onResult(final String value) { if (ToolString.isBlank(value)) { Utils.toast("Title cannot be empty"); showNewSetDialog(folder); } else { BackgroundExecutor.execute(new Runnable() { @Override public void run() { enqueue(Lists.newArrayList(selectedMedia), value); clearSelection(); } }); } } }); } ProgressDialog progressDialog; @UiThread void showLoading(String title, String message) { if (progressDialog == null) { progressDialog = new ProgressDialog(activity); } progressDialog.setTitle(title); progressDialog.setMessage(message); progressDialog.setIndeterminate(true); progressDialog.show(); } @UiThread void hideLoading() { if (progressDialog != null) { progressDialog.dismiss(); } } static void showNewSetDialog(final Activity activity, final String folderTitle, final Callback<String> callback) { AlertDialog.Builder alert = new AlertDialog.Builder(activity); alert.setTitle("Photo Set Title"); // Set an EditText view to get user input final EditText input = new EditText(activity); input.setText(folderTitle); alert.setView(input); alert.setPositiveButton("OK", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String value = input.getText().toString(); LOG.debug("value : " + value); callback.onResult(value); } }); alert.setNegativeButton("Cancel", null); alert.show(); } @Background void enqueue(Collection<Media> images, String photoSetTitle) { int enqueued = UploadService.enqueue(false, images, photoSetTitle); if (slidingDrawer != null && enqueued > 0) { runOnUiThread(new Runnable() { @Override public void run() { if (Utils.getBooleanProperty(STR.show_sliding_demo, true)) { slidingDrawer.demo(); } drawerContentView.setCurrentTab(DrawerContentView.TAB_QUEUED_INDEX); } }); } } void renderHeader(View headerView) { if (headerView != null && headerView.getTag(Header.class.hashCode()) instanceof Header) { Header header = (Header) headerView.getTag(Header.class.hashCode()); // LOG.debug("rendering : " + header + " on " + headerView); TextView count = (TextView) headerView.getTag(R.id.count); count.setCompoundDrawablesWithIntrinsicBounds(0, 0, header.selected ? R.drawable.checkbox_on : R.drawable.checkbox_off, 0); count.setTextColor(getResources().getColor(header.selected ? R.color.litegray : R.color.gray)); count.setText("" + header.count); // checkbox.setText("" + header.selected); TextView title = (TextView) headerView.getTag(R.id.title); title.setCompoundDrawablesWithIntrinsicBounds(header.collapsed ? R.drawable.expand_off : R.drawable.expand_on, 0, 0, 0); title.setText(header.title); } } Set<Media> selectedMedia = new HashSet<Media>(); class PhotoAdapter extends BaseAdapter implements HeaderAdapter { private static final String UPLOAD = "Upload"; private static final String CANCEL_UPLOAD = "Cancel upload"; private static final String OPEN_IN_FLICKR = "Open in Flickr"; public PhotoAdapter() { } @Override public int getCount() { return thumbItems.size(); } @Override public Object getItem(int position) { return thumbItems.get(position); } @Override public long getItemId(int arg0) { return arg0; } static final int VIEW_HEADER = 0; static final int VIEW_THUMB = 1; @Override public int getItemViewType(int position) { if (thumbItems.get(position) instanceof Header) { return VIEW_HEADER; } return VIEW_THUMB; } @Override public int getViewTypeCount() { return 2; } @Override public View getView(int position, View convertView, ViewGroup parent) { Object item = getItem(position); if (item instanceof Header) { return getHeaderView(position, convertView); } else { final Media[] mediaRow = (Media[]) item; LinearLayout linearLayout; if (convertView == null || !(convertView instanceof LinearLayout)) { linearLayout = new LinearLayout(activity); linearLayout.setOrientation(LinearLayout.HORIZONTAL); } else { linearLayout = (LinearLayout) convertView; } if (linearLayout.getChildCount() != mediaRow.length) { linearLayout.removeAllViews(); for (int i = 0; i < mediaRow.length; i++) { View thumbView = getLayoutInflater().inflate(R.layout.grid_thumb, linearLayout, false); thumbView.setTag(R.id.check_image, thumbView.findViewById(R.id.check_image)); thumbView.setTag(R.id.uploading, thumbView.findViewById(R.id.uploading)); thumbView.setTag(R.id.image_view, thumbView.findViewById(R.id.image_view)); thumbView.setTag(R.id.uploaded, thumbView.findViewById(R.id.uploaded)); thumbView.setTag(R.id.type, thumbView.findViewById(R.id.type)); linearLayout.addView(thumbView); thumbView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Media media = (Media) v.getTag(); Header header = headerMap.get(media); if (selectedMedia.contains(media)) { v.findViewById(R.id.check_image).setVisibility(View.GONE); selectedMedia.remove(media); if (header.selected) { header.selected = false; } } else { v.findViewById(R.id.check_image).setVisibility(View.VISIBLE); selectedMedia.add(media); if (!header.selected) { List<Media> headerMedias = new ArrayList<Media>(); Iterator<Entry<Media, Header>> it = headerMap.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Media, Header> entry = it.next(); if (entry.getValue() == header) { headerMedias.add(entry.getKey()); } } if (selectedMedia.containsAll(headerMedias)) { header.selected = true; } } } refresh(); } }); thumbView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewDetachedFromWindow(View v) { thumbViews.values().removeAll(Collections.singleton(v)); } @Override public void onViewAttachedToWindow(View v) { if (v.getTag() instanceof Media) { thumbViews.put((Media) v.getTag(), v); } } }); thumbView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { if (v.getTag() instanceof Media) { final Media media = (Media) v.getTag(); final CharSequence[] items = new CharSequence[1]; if (media.isUploaded()) { items[0] = OPEN_IN_FLICKR; } else if (media.isQueued()) { items[0] = CANCEL_UPLOAD; } else { items[0] = UPLOAD; } AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setItems(items, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { if (OPEN_IN_FLICKR.equals(items[item])) { Utils.setStringProperty(STR.mediaToSync, media.getFlickrId()); Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse("http://www.flickr.com/photos/" + Utils.getStringProperty(STR.userId) + "/" + media.getFlickrId())); startActivity(i); } else if (CANCEL_UPLOAD.equals(items[item])) { UploadService.dequeue(Lists.newArrayList(media)); } else if (UPLOAD.equals(items[item])) { confirmUpload(Lists.newArrayList(media)); } } }); AlertDialog alert = builder.create(); alert.show(); } return true; } }); } } if (linearLayout.getTag() != mediaRow) { linearLayout.setTag(mediaRow); for (int i = 0; i < mediaRow.length; i++) { View thumbView = linearLayout.getChildAt(i); Media media = mediaRow[i]; if (media == null) { thumbViews.remove(thumbView.getTag()); thumbView.setTag(media); renderImageView(thumbView, true); } else if (!media.equals(thumbView.getTag())) { thumbViews.remove(thumbView.getTag()); thumbViews.put(media, thumbView); thumbView.setTag(media); renderImageView(thumbView, true); } } } return linearLayout; } } public View getHeaderView(int position, View convertView) { final TextView title; final TextView count; if (convertView == null) { convertView = View.inflate(activity, R.layout.grid_header, null); convertView.setTag(Header.class); convertView.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, Utils.getScaledSize(48))); convertView.findViewById(R.id.count).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Header header = (Header) v.getTag(); header.selected = !header.selected; Iterator<Entry<Media, Header>> it = headerMap.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Media, Header> entry = it.next(); if (entry.getValue() == header) { if (header.selected) { selectedMedia.add(entry.getKey()); } else { selectedMedia.remove(entry.getKey()); } } } refresh(); } }); title = (TextView) convertView.findViewById(R.id.title); convertView.setTag(R.id.title, title); count = (TextView) convertView.findViewById(R.id.count); convertView.setTag(R.id.count, count); convertView.findViewById(R.id.expand).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final Header header = (Header) title.getTag(); header.collapsed = !header.collapsed; computeHeaders(false); } }); convertView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewDetachedFromWindow(View v) { attachedHeaderViews.remove(v); } @Override public void onViewAttachedToWindow(View v) { attachedHeaderViews.add(v); renderHeader(v); } }); } else { title = (TextView) convertView.getTag(R.id.title); count = (TextView) convertView.getTag(R.id.count); } Header header = (Header) thumbItems.get(position); convertView.setTag(Header.class.hashCode(), header); count.setTag(header); title.setTag(header); renderHeader(convertView); // LOG.debug(header + " : convertView = " + convertView); return convertView; } @Override public int getHeaderPosition(int firstVisibleItem) { if (thumbItems.size() > firstVisibleItem) { Object thumbObject = thumbItems.get(firstVisibleItem); if (thumbObject instanceof Header) { return firstVisibleItem; } else { Media[] mediaRow = (Media[]) thumbObject; return thumbItems.indexOf(headerMap.get(mediaRow[0])); } } return -1; } } public static void onLoadProgress(int progress) { if (instance != null) { instance.setLoading(progress); } } public static void updateStatic(Media media) { if (instance != null) { instance.update(media); } } Map<Media, View> thumbViews = new HashMap<Media, View>(); private void update(Media media) { View thumbView = thumbViews.get(media); if (thumbView != null) { renderImageView(thumbView, false); } if (medias != null && !medias.contains(media)) { load(); } } Set<View> attachedHeaderViews = new HashSet<View>(); ExecutorService executorService = Executors.newSingleThreadExecutor(); @UiThread void renderImageView(final View convertView, boolean reset) { if (convertView.getTag() instanceof Media) { convertView.setVisibility(View.VISIBLE); convertView.setLayoutParams(new LinearLayout.LayoutParams(computed_req_width, computed_req_height)); final Media media = (Media) convertView.getTag(); final CacheableImageView imageView = (CacheableImageView) convertView.getTag(R.id.image_view); imageView.setTag(media); final View check_image = (View) convertView.getTag(R.id.check_image); final ImageView uploadedImageView = (ImageView) convertView.getTag(R.id.uploaded); if (reset) { check_image.setVisibility(View.GONE); uploadedImageView.setVisibility(View.GONE); } View type = (View) convertView.getTag(R.id.type); type.setVisibility(media.getMediaType() == MEDIA_TYPE.VIDEO ? View.VISIBLE : View.GONE); final CacheableBitmapDrawable wrapper = Utils.getCache().getFromMemoryCache(media.getPath() + "_" + Utils.getViewSize()); if (wrapper != null && !wrapper.getBitmap().isRecycled()) { // The cache has it, so just display it imageView.setImageDrawable(wrapper); } else { imageView.setImageDrawable(null); } executorService.submit(new Runnable() { @Override public void run() { try { if (media.equals(imageView.getTag())) { final boolean uploading = media.isQueued(); final boolean uploaded = media.isUploaded(); final int privacyResource; if (uploaded) { privacyResource = getPrivacyResource(media.getPrivacy()); } else { privacyResource = 0; } final CacheableBitmapDrawable bitmapDrawable; if (wrapper != null && !wrapper.getBitmap().isRecycled()) { bitmapDrawable = wrapper; } else { Bitmap bitmap = Utils.getBitmap(media, Utils.getViewSize()); if (bitmap != null) { bitmapDrawable = Utils.getCache().put(media.getPath() + "_" + Utils.getViewSize(), bitmap); } else { bitmapDrawable = null; } } runOnUiThread(new Runnable() { @Override public void run() { if (media.equals(imageView.getTag())) { check_image.setVisibility(selectedMedia.contains(media) ? View.VISIBLE : View.GONE); uploadedImageView.setVisibility(uploaded ? View.VISIBLE : View.GONE); ((View) convertView.getTag(R.id.uploading)).setVisibility(uploading ? View.VISIBLE : View.GONE); if (wrapper != bitmapDrawable) { imageView.setImageDrawable(bitmapDrawable); } if (privacyResource != 0) { uploadedImageView.setImageResource(privacyResource); } } } }); } } catch (Throwable e) { LOG.error("FINAL ERROR\n" + ToolString.stack2string(e)); } } }); } else { convertView.setVisibility(View.GONE); } } private Menu menu; @ViewById(R.id.list_view) StickyHeaderListView listView; private boolean paused = false; @Override public void onBackPressed() { if (slidingDrawer != null && slidingDrawer.isOpened()) { slidingDrawer.animateClose(); } else { if (finishOnClose) { finish(); } else { moveTaskToBack(true); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { this.menu = menu; super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { renderMenu(); return super.onPrepareOptionsMenu(menu); } @UiThread void renderMenu() { if (menu != null && menu.findItem(R.id.trial_info) != null) { menu.findItem(R.id.trial_info).setVisible(!Utils.isPremium()); switch (Utils.getViewSize()) { case small: menu.findItem(R.id.view_size_small).setChecked(true); break; case medium: menu.findItem(R.id.view_size_medium).setChecked(true); break; case large: menu.findItem(R.id.view_size_large).setChecked(true); break; default: break; } menu.findItem(R.id.filter_photos).setChecked(Utils.getShowPhotos()); menu.findItem(R.id.filter_videos).setChecked(Utils.getShowVideos()); menu.findItem(R.id.filter_uploaded).setChecked(Utils.getShowUploaded()); menu.findItem(R.id.filter_not_uploaded).setChecked(Utils.getShowNotUploaded()); switch (Utils.getViewGroupType()) { case date: menu.findItem(R.id.group_by_date).setChecked(true); break; case folder: menu.findItem(R.id.group_by_folder).setChecked(true); break; default: break; } } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.trial_info: Utils.showPremiumDialog(activity, new Utils.Callback<Boolean>() { @Override public void onResult(Boolean result) { } }); break; case R.id.preferences: startActivity(new Intent(activity, PreferencesActivity.class)); break; case R.id.faq: Utils.showHelpDialog(activity); break; case R.id.view_size_small: Utils.setViewSize(VIEW_SIZE.small); computeHeaders(false); item.setChecked(true); break; case R.id.view_size_medium: Utils.setViewSize(VIEW_SIZE.medium); computeHeaders(false); item.setChecked(true); break; case R.id.view_size_large: Utils.setViewSize(VIEW_SIZE.large); computeHeaders(false); item.setChecked(true); break; case R.id.filter_photos: item.setChecked(!item.isChecked()); Utils.setShowPhotos(item.isChecked()); load(); break; case R.id.filter_videos: item.setChecked(!item.isChecked()); Utils.setShowVideos(item.isChecked()); load(); break; case R.id.filter_uploaded: item.setChecked(!item.isChecked()); Utils.setShowUploaded(item.isChecked()); load(); break; case R.id.filter_not_uploaded: item.setChecked(!item.isChecked()); Utils.setShowNotUploaded(item.isChecked()); load(); break; case R.id.select_all: for (Header header : headers) { header.selected = true; } selectedMedia.addAll(medias); refresh(); break; case R.id.select_none: for (Header header : headers) { header.selected = false; } selectedMedia.clear(); refresh(); break; case R.id.group_by_date: item.setChecked(true); Utils.setViewGroupType(VIEW_GROUP_TYPE.date); load(); break; case R.id.group_by_folder: item.setChecked(true); Utils.setViewGroupType(VIEW_GROUP_TYPE.folder); load(); break; case R.id.expand_all: for (Header header : headers) { header.collapsed = false; } computeHeaders(false); break; case R.id.collapse_all: for (Header header : headers) { header.collapsed = true; } computeHeaders(false); break; case R.id.upload_add: if (Utils.isPremium() || Utils.isTrial()) { if (selectedMedia.isEmpty()) { Utils.toast("Select at least one file"); } else { confirmUpload(selectedMedia); } } else { checkPremium(); } break; case R.id.upload_remove: if (selectedMedia.isEmpty()) { Utils.toast("Select at least one file"); } else { UploadService.dequeue(selectedMedia); clearSelection(); } break; } return (super.onOptionsItemSelected(item)); } @Override protected void onResume() { if (paused) { load(); } paused = false; super.onResume(); UploadService.wake(); drawerHandleView.onActivityResume(); renderLoop(); String mediaToSync = Utils.getStringProperty(STR.mediaToSync); if (ToolString.isNotBlank(mediaToSync)) { Utils.clearProperty(STR.mediaToSync); FlickrApi.syncMedia(mediaToSync); } } @UiThread(delay = 1000) void renderLoop() { if (!paused && !destroyed) { if (drawerHandleView != null) { drawerHandleView.render(); if (slidingDrawer.isOpened()) { drawerContentView.renderCurrentView(); } } renderLoop(); } } @UiThread @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (Utils.onActivityResult(requestCode, resultCode, data)) { return; } if (resultCode == FlickrWebAuthActivity.RESULT_CODE_AUTH) { if (FlickrApi.isAuthentified()) { Utils.showAutoUploadDialog(activity); } } else { super.onActivityResult(requestCode, resultCode, data); } } @UiThread(delay = 100) public void refresh() { if (listView != null) { renderMenu(); int childCount = listView.getChildCount(); for (int i = 0; i < childCount; i++) { View convertView = listView.getChildAt(i); if (convertView instanceof LinearLayout && convertView.getTag() instanceof Media[]) { LinearLayout linearLayout = (LinearLayout) convertView; for (int j = 0; j < linearLayout.getChildCount(); j++) { renderImageView(linearLayout.getChildAt(j), false); } } } for (View headerView : attachedHeaderViews) { renderHeader(headerView); } renderHeader(listView.getFloatingSectionHeader()); } if (selectedMedia.isEmpty()) { getSupportActionBar().setTitle(null); } else { getSupportActionBar().setTitle("" + selectedMedia.size()); } } int getPrivacyResource(PRIVACY privacy) { if (privacy != null) { switch (privacy) { case PUBLIC: return R.drawable.uploaded_public; case FAMILY: case FRIENDS: case FRIENDS_FAMILY: return R.drawable.uploaded_friends; default: break; } } return R.drawable.uploaded; } @Override protected void onPause() { paused = true; super.onPause(); } public boolean isPaused() { return paused; } public SlidingDrawer getSlidingDrawer() { return slidingDrawer; } @Override public void onRefresh() { if (medias != null) { String root = null; for (Media media : medias) { if (root == null) { root = media.getFolderPath(); } else if (!media.getFolderPath().startsWith(root)) { while (root.length() > 1 && !media.getFolderPath().startsWith(root)) { root = ToolString.getParentPath(root); } if (root.length() <= 1) { break; } } } if (root != null) { LOG.debug("rescanning " + root); MediaScannerConnection.scanFile(getApplicationContext(), new String[]{root}, null, new OnScanCompletedListener() { @Override public void onScanCompleted(String path, Uri uri) { LOG.debug("file " + path + " was scanned seccessfully: " + uri); load(true); } }); } else { load(true); } } } public static void onNewFiles() { if (instance != null && !instance.isPaused() && instance.swipeContainer != null && !instance.swipeContainer.isRefreshing()) { instance.load(); } } }