mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
Add proper categorization view on post upload
This commit is contained in:
parent
36f90b51e1
commit
de5968d75e
10 changed files with 395 additions and 47 deletions
|
|
@ -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>
|
||||
37
commons/res/layout/fragment_categorization.xml
Normal file
37
commons/res/layout/fragment_categorization.xml
Normal 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>
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
12
commons/res/layout/layout_categories_item.xml
Normal file
12
commons/res/layout/layout_categories_item.xml
Normal 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>
|
||||
8
commons/res/menu/fragment_categorization.xml
Normal file
8
commons/res/menu/fragment_categorization.xml
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -140,6 +175,10 @@ public class ShareActivity extends AuthenticatedActivity implements SingleUpload
|
|||
|
||||
ImageLoader.getInstance().displayImage(mediaUri.toString(), backgroundImageView);
|
||||
|
||||
if(savedInstanceState != null) {
|
||||
contribution = savedInstanceState.getParcelable("contribution");
|
||||
}
|
||||
|
||||
requestAuthToken();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue