Add proper categorization view on post upload

This commit is contained in:
YuviPanda 2013-03-30 03:48:15 +05:30
parent 36f90b51e1
commit de5968d75e
10 changed files with 395 additions and 47 deletions

View file

@ -16,6 +16,11 @@
android:id="@+id/single_upload_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
android:background="#AA000000"
android:paddingBottom="8dip"
android:paddingLeft="16dip"
android:paddingRight="16dip"
android:paddingTop="8dip"
/>
</FrameLayout>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
>
<EditText
android:id="@+id/categoriesSearchBox"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:hint="@string/categories_search_text_hint"
/>
<ProgressBar
android:id="@+id/categoriesSearchInProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:indeterminateOnly="true"
android:layout_marginRight="4dp"
android:layout_gravity="center_vertical|right"
style="?android:progressBarStyleSmall"
android:visibility="gone"
/>
</FrameLayout>
<ListView
android:id="@+id/categoriesListBox"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:fadingEdge="none"
/>
</LinearLayout>

View file

@ -4,12 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill"
android:background="#AA000000"
android:orientation="vertical"
android:paddingBottom="8dip"
android:paddingLeft="16dip"
android:paddingRight="16dip"
android:paddingTop="8dip" >
android:orientation="vertical">
<EditText
android:id="@+id/titleEdit"

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:checkMark="?android:attr/textCheckMark"
android:checked="false"
android:gravity="center_vertical"
>
</CheckedTextView>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_save_categories"
android:title="@string/menu_save_categories"
android:icon="@android:drawable/ic_menu_save"
android:showAsAction="always" />
</menu>

View file

@ -52,6 +52,8 @@
<string name="multiple_share_base_title">Name this set</string>
<string name="provider_modifications">Modifications</string>
<string name="menu_upload_single">Upload</string>
<string name="categories_search_text_hint">Search categories</string>
<string name="menu_save_categories">Save</string>
<plurals name="contributions_subtitle">
<item quantity="zero">No uploads yet</item>

View file

@ -0,0 +1,277 @@
package org.wikimedia.commons;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.*;
import android.view.MenuInflater;
import android.widget.*;
import com.actionbarsherlock.app.SherlockFragment;
import com.actionbarsherlock.view.*;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import org.mediawiki.api.ApiResult;
import org.mediawiki.api.MWApi;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.ScheduledThreadPoolExecutor;
public class CategorizationFragment extends SherlockFragment{
public static interface OnCategoriesSaveHandler {
public void onCategoriesSave(ArrayList<String> categories);
}
ListView categoriesList;
EditText categoriesFilter;
ProgressBar categoriesSearchInProgress;
CategoriesAdapter categoriesAdapter;
CategoriesUpdater lastUpdater = null;
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
private OnCategoriesSaveHandler onCategoriesSaveHandler;
private HashMap<String, ArrayList<String>> categoriesCache;
public static class CategoryItem implements Parcelable {
public String name;
public boolean selected;
public static Creator<CategoryItem> CREATOR = new Creator<CategoryItem>() {
public CategoryItem createFromParcel(Parcel parcel) {
return new CategoryItem(parcel);
}
public CategoryItem[] newArray(int i) {
return new CategoryItem[0];
}
};
public CategoryItem(String name, boolean selected) {
this.name = name;
this.selected = selected;
}
public CategoryItem(Parcel in) {
name = in.readString();
selected = in.readInt() == 1;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(name);
parcel.writeInt(selected ? 1 : 0);
}
}
private class CategoriesUpdater extends AsyncTask<Void, Void, ArrayList<String>> {
private String filter;
@Override
protected void onPreExecute() {
super.onPreExecute();
filter = categoriesFilter.getText().toString();
categoriesSearchInProgress.setVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(ArrayList<String> categories) {
super.onPostExecute(categories);
ArrayList<CategoryItem> items = new ArrayList<CategoryItem>();
HashSet<String> existingKeys = new HashSet<String>();
for(CategoryItem item : categoriesAdapter.getItems()) {
if(item.selected) {
items.add(item);
existingKeys.add(item.name);
}
}
for(String category : categories) {
if(!existingKeys.contains(category)) {
items.add(new CategoryItem(category, false));
}
}
categoriesAdapter.setItems(items);
categoriesAdapter.notifyDataSetInvalidated();
categoriesSearchInProgress.setVisibility(View.GONE);
}
@Override
protected ArrayList<String> doInBackground(Void... voids) {
if(categoriesCache.containsKey(filter)) {
return categoriesCache.get(filter);
}
MWApi api = CommonsApplication.createMWApi();
ApiResult result;
ArrayList<String> categories = new ArrayList<String>();
try {
result = api.action("query")
.param("list", "allcategories")
.param("acprefix", filter)
.param("aclimit", 25)
.get();
} catch (IOException e) {
throw new RuntimeException(e);
}
ArrayList<ApiResult> categoryNodes = result.getNodes("/api/query/allcategories/c");
for(ApiResult categoryNode: categoryNodes) {
categories.add(categoryNode.getDocument().getTextContent());
}
categoriesCache.put(filter, categories);
return categories;
}
}
private class CategoriesAdapter extends BaseAdapter {
private Context context;
private ArrayList<CategoryItem> items;
private CategoriesAdapter(Context context, ArrayList<CategoryItem> items) {
this.context = context;
this.items = items;
}
public int getCount() {
return items.size();
}
public Object getItem(int i) {
return items.get(i);
}
public ArrayList<CategoryItem> getItems() {
return items;
}
public void setItems(ArrayList<CategoryItem> items) {
this.items = items;
}
public long getItemId(int i) {
return i;
}
public View getView(int i, View view, ViewGroup viewGroup) {
CheckedTextView checkedView;
if(view == null) {
checkedView = (CheckedTextView) getSherlockActivity().getLayoutInflater().inflate(R.layout.layout_categories_item, null);
} else {
checkedView = (CheckedTextView) view;
}
CategoryItem item = (CategoryItem) this.getItem(i);
checkedView.setChecked(item.selected);
checkedView.setText(item.name);
checkedView.setTag(i);
return checkedView;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_categorization, null);
categoriesList = (ListView) rootView.findViewById(R.id.categoriesListBox);
categoriesFilter = (EditText) rootView.findViewById(R.id.categoriesSearchBox);
categoriesSearchInProgress = (ProgressBar) rootView.findViewById(R.id.categoriesSearchInProgress);
ArrayList<CategoryItem> items;
if(savedInstanceState == null) {
items = new ArrayList<CategoryItem>();
categoriesCache = new HashMap<String, ArrayList<String>>();
} else {
items = savedInstanceState.getParcelableArrayList("currentCategories");
categoriesCache = (HashMap<String, ArrayList<String>>) savedInstanceState.getSerializable("categoriesCache");
}
categoriesAdapter = new CategoriesAdapter(getActivity(), items);
categoriesList.setAdapter(categoriesAdapter);
categoriesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> adapterView, View view, int index, long id) {
CheckedTextView checkedView = (CheckedTextView) view;
CategoryItem item = (CategoryItem) adapterView.getAdapter().getItem(index);
item.selected = !item.selected;
checkedView.setChecked(item.selected);
}
});
categoriesFilter.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
if(lastUpdater != null) {
lastUpdater.cancel(true);
}
lastUpdater = new CategoriesUpdater();
lastUpdater.executeOnExecutor(executor);
}
public void afterTextChanged(Editable editable) {
}
});
return rootView;
}
@Override
public void onCreateOptionsMenu(Menu menu, com.actionbarsherlock.view.MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.fragment_categorization, menu);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("currentCategories", categoriesAdapter.getItems());
outState.putSerializable("categoriesCache", categoriesCache);
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch(menuItem.getItemId()) {
case R.id.menu_save_categories:
ArrayList<String> selectedCategories = new ArrayList<String>();
for(CategoryItem item: categoriesAdapter.getItems()) {
if(item.selected) {
selectedCategories.add(item.name);
}
}
onCategoriesSaveHandler.onCategoriesSave(selectedCategories);
return true;
}
return super.onOptionsItemSelected(menuItem);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
onCategoriesSaveHandler = (OnCategoriesSaveHandler) activity;
}
}

View file

@ -14,12 +14,21 @@ import android.view.*;
import org.wikimedia.commons.contributions.*;
import org.wikimedia.commons.auth.*;
import org.wikimedia.commons.modifications.CategoryModifier;
import org.wikimedia.commons.modifications.ModificationsContentProvider;
import org.wikimedia.commons.modifications.ModifierSequence;
import org.wikimedia.commons.modifications.PostUploadActivity;
import java.util.ArrayList;
public class ShareActivity extends AuthenticatedActivity implements SingleUploadFragment.OnUploadActionInitiated {
public class ShareActivity
extends AuthenticatedActivity
implements SingleUploadFragment.OnUploadActionInitiated,
CategorizationFragment.OnCategoriesSaveHandler {
private SingleUploadFragment shareView;
private CategorizationFragment categorizationFragment;
public ShareActivity() {
super(WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE);
@ -32,6 +41,8 @@ public class ShareActivity extends AuthenticatedActivity implements SingleUpload
private Uri mediaUri;
private Contribution contribution;
private ImageView backgroundImageView;
private UploadService uploadService;
@ -51,7 +62,23 @@ public class ShareActivity extends AuthenticatedActivity implements SingleUpload
public void uploadActionInitiated(String title, String description) {
StartUploadTask task = new SingleStartUploadTask(ShareActivity.this, uploadService, title, mediaUri, description, mimeType, source);
task.execute();
}
private void showPostUpload() {
if(categorizationFragment == null) {
categorizationFragment = new CategorizationFragment();
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.single_upload_fragment_container, categorizationFragment, "categorization")
.commit();
}
public void onCategoriesSave(ArrayList<String> categories) {
ModifierSequence categoriesSequence = new ModifierSequence(contribution.getContentUri());
categoriesSequence.queueModifier(new CategoryModifier(categories.toArray(new String[]{})));
categoriesSequence.setContentProviderClient(getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY));
categoriesSequence.save();
finish();
}
private class SingleStartUploadTask extends StartUploadTask {
@ -69,10 +96,16 @@ public class ShareActivity extends AuthenticatedActivity implements SingleUpload
@Override
protected void onPostExecute(Contribution contribution) {
super.onPostExecute(contribution);
Intent postUploadIntent = new Intent(ShareActivity.this, PostUploadActivity.class);
postUploadIntent.putExtra(PostUploadActivity.EXTRA_MEDIA_URI, contribution.getContentUri());
startActivity(postUploadIntent);
finish();
ShareActivity.this.contribution = contribution;
showPostUpload();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(contribution != null) {
outState.putParcelable("contribution", contribution);
}
}
@ -93,14 +126,16 @@ public class ShareActivity extends AuthenticatedActivity implements SingleUpload
shareView = (SingleUploadFragment) getSupportFragmentManager().findFragmentByTag("shareView");
if(shareView == null) {
shareView = new SingleUploadFragment();
this.getSupportFragmentManager()
.beginTransaction()
.add(R.id.single_upload_fragment_container, shareView, "shareView")
.commit();
categorizationFragment = (CategorizationFragment) getSupportFragmentManager().findFragmentByTag("categorization");
if(shareView == null && categorizationFragment == null) {
shareView = new SingleUploadFragment();
this.getSupportFragmentManager()
.beginTransaction()
.add(R.id.single_upload_fragment_container, shareView, "shareView")
.commit();
}
Intent uploadServiceIntent = new Intent(getApplicationContext(), UploadService.class);
uploadServiceIntent.setAction(UploadService.ACTION_START_SERVICE);
startService(uploadServiceIntent);
@ -139,7 +174,11 @@ public class ShareActivity extends AuthenticatedActivity implements SingleUpload
}
ImageLoader.getInstance().displayImage(mediaUri.toString(), backgroundImageView);
if(savedInstanceState != null) {
contribution = savedInstanceState.getParcelable("contribution");
}
requestAuthToken();
}

View file

@ -84,6 +84,7 @@ public class StartUploadTask extends AsyncTask<Void, Void, Contribution> {
contribution.setDateCreated(new Date(cursor.getLong(0)));
} // FIXME: Alternate way of setting dateCreated if this data is not found
}
return contribution;
}

View file

@ -1,28 +0,0 @@
package org.wikimedia.commons.modifications;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import org.wikimedia.commons.HandlerService;
import org.wikimedia.commons.R;
import org.wikimedia.commons.UploadService;
public class PostUploadActivity extends Activity {
public static String EXTRA_MEDIA_URI = "org.wikimedia.commons.modifications.PostUploadActivity.mediauri";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_upload);
Uri mediaUri = getIntent().getParcelableExtra(EXTRA_MEDIA_URI);
ModifierSequence testSequence = new ModifierSequence(mediaUri);
testSequence.queueModifier(new CategoryModifier("Hello, World!"));
testSequence.setContentProviderClient(getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY));
testSequence.save();
}
}