package net.coding.program.maopao; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.ActionBar; import android.text.Editable; import android.text.TextUtils; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.EditText; import android.widget.GridView; import android.widget.ImageView; import android.widget.TextView; import com.loopj.android.http.RequestParams; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.ImageSize; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; import net.coding.program.ImagePagerActivity_; import net.coding.program.ImagePagerFragment; import net.coding.program.LoginActivity_; import net.coding.program.MyApp; import net.coding.program.R; import net.coding.program.common.Global; import net.coding.program.common.ListModify; import net.coding.program.common.PhoneType; import net.coding.program.common.PhotoOperate; import net.coding.program.common.StartActivity; import net.coding.program.common.TextWatcherAt; import net.coding.program.common.WeakRefHander; import net.coding.program.common.enter.EnterEmojiLayout; import net.coding.program.common.enter.EnterLayout; import net.coding.program.common.enter.SimpleTextWatcher; import net.coding.program.common.photopick.ImageInfo; import net.coding.program.common.photopick.PhotoPickActivity; import net.coding.program.common.ui.BackActivity; import net.coding.program.common.umeng.UmengEvent; import net.coding.program.common.util.FileUtil; import net.coding.program.maopao.item.LocationCoord; import net.coding.program.message.EmojiFragment; import net.coding.program.model.AccountInfo; import net.coding.program.model.LocationObject; import net.coding.program.model.Maopao; import net.coding.program.subject.SubjectNewActivity_; import net.coding.program.third.EmojiFilter; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.Click; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.InstanceState; import org.androidannotations.annotations.OnActivityResult; import org.androidannotations.annotations.OptionsItem; import org.androidannotations.annotations.ViewById; import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.Serializable; import java.util.ArrayList; @EActivity(R.layout.activity_maopao_add) public class MaopaoAddActivity extends BackActivity implements StartActivity, EmojiFragment.EnterEmojiLayout { public static final int PHOTO_MAX_COUNT = 6; public static final int RESULT_REQUEST_FOLLOW = 1002; public static final int RESULT_REQUEST_TOPIC = 1008; public static final int RESULT_REQUEST_PICK_PHOTO = 1003; public static final int RESULT_REQUEST_PHOTO = 1005; public static final int RESULT_REQUEST_LOCATION = 1006; public static final int RESULT_REQUEST_IMAGE = 1007; final String sendUrl = Global.HOST_API + "/tweet"; final String HOST_IMAGE = Global.HOST_API + "/tweet/insert_image"; String mIntentExtraString = null; @ViewById GridView gridView; @ViewById TextView locationText; @InstanceState LocationObject currentLocation = LocationObject.undefined(); ImageSize mSize; PhotoOperate photoOperate = new PhotoOperate(this); EnterEmojiLayout mEnterLayout; EditText message; ArrayList<PhotoData> mData = new ArrayList<>(); android.os.Handler mHandler = new android.os.Handler() { @Override public void handleMessage(Message msg) { uploadMaopao(); } }; BaseAdapter adapter = new BaseAdapter() { ArrayList<ViewHolder> holderList = new ArrayList<>(); public int getCount() { return mData.size() + 1; } public Object getItem(int position) { return null; } public long getItemId(int position) { return position; } // create a new ImageView for each item referenced by the Adapter public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { holder = new ViewHolder(); holder.image = (ImageView) mInflater.inflate(R.layout.image_make_maopao, parent, false); holderList.add(holder); holder.image.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } if (position == getCount() - 1) { if (getCount() == (PHOTO_MAX_COUNT + 1)) { holder.image.setVisibility(View.INVISIBLE); } else { holder.image.setVisibility(View.VISIBLE); holder.image.setImageResource(R.drawable.make_maopao_add); holder.uri = ""; } } else { holder.image.setVisibility(View.VISIBLE); PhotoData photoData = mData.get(position); Uri data = photoData.uri; holder.uri = data.toString(); ImageLoader.getInstance().loadImage(data.toString(), mSize, new SimpleImageLoadingListener() { @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { for (ViewHolder item : holderList) { if (item.uri.equals(imageUri)) { item.image.setImageBitmap(loadedImage); } } } }); } return holder.image; } @Override public void notifyDataSetChanged() { super.notifyDataSetChanged(); gridView.setVisibility(getCount() > 1 ? View.VISIBLE : View.GONE); } class ViewHolder { ImageView image; String uri = ""; } }; private Uri fileUri; private MenuItem mMenuAdd; private static String ensureLength(String src, int maxLength) { if (TextUtils.isEmpty(src)) return ""; if (src.length() <= maxLength) return src; if (maxLength < 1) throw new IllegalArgumentException("maxLength"); return src.substring(0, maxLength - 1) + "…"; } @AfterViews protected final void initMaopaoAddActivity() { int px = (int) getResources().getDimension(R.dimen.image_add_maopao_width); mSize = new ImageSize(px, px); ActionBar supportActionBar = getSupportActionBar(); if (supportActionBar != null) { supportActionBar.setDisplayHomeAsUpEnabled(true); } mEnterLayout = new EnterEmojiLayout(this, null); message = mEnterLayout.content; if (mIntentExtraString != null) { message.setText(mIntentExtraString); } gridView.setAdapter(adapter); adapter.notifyDataSetChanged(); gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (position == mData.size()) { startPhotoPickActivity(); } else { Intent intent = new Intent(MaopaoAddActivity.this, ImagePagerActivity_.class); ArrayList<String> arrayUri = new ArrayList<>(); for (PhotoData item : mData) { arrayUri.add(item.uri.toString()); } intent.putExtra("mArrayUri", arrayUri); intent.putExtra("mPagerPosition", position); intent.putExtra("needEdit", true); startActivityForResult(intent, RESULT_REQUEST_IMAGE); } } }); gridView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Global.popSoftkeyboard(MaopaoAddActivity.this, mEnterLayout.content, false); return false; } }); message.addTextChangedListener(new SimpleTextWatcher() { @Override public void afterTextChanged(Editable s) { updateAddButton(); } }); MaopaoDraft draft = AccountInfo.loadMaopaoDraft(this); if (!draft.isEmpty()) { mEnterLayout.setText(draft.getInput()); mData = draft.getPhotos(); adapter.notifyDataSetChanged(); currentLocation = draft.getLocation(); updateLocationText(); } locationText.setText(currentLocation.name); setPopTopicIconShow(); mEnterLayout.content.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mEnterLayout.popKeyboard(); } }); mEnterLayout.content.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (mFirstFocus && hasFocus) { mFirstFocus = false; mEnterLayout.popKeyboard(); } } }); WeakRefHander hander = new WeakRefHander(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (MaopaoAddActivity.this.isFinishing()) { return false; } mEnterLayout.popKeyboard(); return false; } }); hander.start(0, 500); } private boolean mFirstFocus = true; @Override public EnterLayout getEnterLayout() { return mEnterLayout; } private void setPopTopicIconShow() { int icon = R.drawable.pop_topic; ((ImageView) findViewById(R.id.popTopic)).setImageResource(icon); } private void startPhotoPickActivity() { int count = PHOTO_MAX_COUNT - mData.size(); if (count <= 0) { showButtomToast(String.format("最多能添加%d张图片", PHOTO_MAX_COUNT)); return; } Intent intent = new Intent(MaopaoAddActivity.this, PhotoPickActivity.class); intent.putExtra(PhotoPickActivity.EXTRA_MAX, PHOTO_MAX_COUNT); ArrayList<ImageInfo> pickImages = new ArrayList<>(); for (PhotoData item : mData) { pickImages.add(item.mImageinfo); } intent.putExtra(PhotoPickActivity.EXTRA_PICKED, pickImages); startActivityForResult(intent, RESULT_REQUEST_PICK_PHOTO); } private void updateAddButton() { enableSendButton(!Global.isEmptyContainSpace(message) || mData.size() > 0); } @Override protected void onStop() { MaopaoDraft draft = new MaopaoDraft(mEnterLayout.getContent(), mData, currentLocation); AccountInfo.saveMaopaoDraft(this, draft); mEnterLayout.closeEnterPanel(); super.onStop(); } private void enableSendButton(boolean enable) { if (mMenuAdd == null) { return; } if (enable) { mMenuAdd.setIcon(R.drawable.ic_menu_ok); mMenuAdd.setEnabled(true); } else { mMenuAdd.setIcon(R.drawable.ic_menu_ok_unable); mMenuAdd.setEnabled(false); } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.add_maopao, menu); mMenuAdd = menu.findItem(R.id.action_add); updateAddButton(); return super.onCreateOptionsMenu(menu); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == RESULT_REQUEST_PICK_PHOTO) { if (resultCode == Activity.RESULT_OK) { try { mData.clear(); @SuppressWarnings("unchecked") ArrayList<ImageInfo> pickPhots = (ArrayList<ImageInfo>) data.getSerializableExtra("data"); for (ImageInfo item : pickPhots) { File outputFile = photoOperate.scal(item.path); mData.add(new MaopaoAddActivity.PhotoData(outputFile, item)); } } catch (Exception e) { showMiddleToast("缩放图片失败"); Global.errorLog(e); } adapter.notifyDataSetChanged(); } } else if (requestCode == RESULT_REQUEST_PHOTO) { if (resultCode == RESULT_OK) { try { ImageInfo imageInfo = new ImageInfo(fileUri.getPath()); File outputFile = photoOperate.scal(fileUri); mData.add(new MaopaoAddActivity.PhotoData(outputFile, imageInfo)); adapter.notifyDataSetChanged(); } catch (Exception e) { showMiddleToast("缩放图片失败"); Global.errorLog(e); } } } else if (requestCode == RESULT_REQUEST_IMAGE) { if (resultCode == RESULT_OK) { ArrayList<String> delUris = data.getStringArrayListExtra("mDelUrls"); for (String item : delUris) { for (int i = 0; i < mData.size(); ++i) { if (mData.get(i).uri.toString().equals(item)) { mData.remove(i); } } adapter.notifyDataSetChanged(); } } } else if (requestCode == RESULT_REQUEST_FOLLOW) { if (resultCode == RESULT_OK) { String name = data.getStringExtra("name"); mEnterLayout.insertText("@" + name); } } else if (requestCode == RESULT_REQUEST_TOPIC) { if (resultCode == RESULT_OK) { String topicName = data.getStringExtra("topic_name"); if (!TextUtils.isEmpty(topicName) && message != null) { // message.setText(topicName); // message.setSelection(topicName.length()); message.getEditableText().insert(0, topicName); } } } else { super.onActivityResult(requestCode, resultCode, data); } updateAddButton(); } @Override public void onBackPressed() { if (message.getText().toString().isEmpty() && adapter.getCount() <= 1) { finish(); } else { showDialog("冒泡", "保存为草稿?", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finishWithoutSave(); } }, "保存", "不保存" ); } } @OptionsItem void action_add() { showProgressBar(true, "正在发表冒泡..."); uploadMaopao(); } void uploadMaopao() { for (PhotoData item : mData) { if (item.serviceUri.isEmpty()) { uploadImage(item.uri); return; } } uploadText(); } void uploadImage(Uri uri) { RequestParams requestParams = new RequestParams(); try { File file = new File(FileUtil.getPath(this, uri)); requestParams.put("tweetImg", file); postNetwork(HOST_IMAGE, requestParams, HOST_IMAGE, -1, uri.toString()); } catch (Exception e) { Global.errorLog(e); showProgressBar(false); } } void uploadText() { RequestParams params = new RequestParams(); String content = message.getText().toString(); if (EmojiFilter.containsEmoji(this, content)) { showProgressBar(false); return; } String photoTemplate = "\n![图片](%s)"; for (PhotoData item : mData) { content += String.format(photoTemplate, item.serviceUri); } params.put("content", content); params.put("device", Build.MODEL); if (currentLocation != null && !TextUtils.isEmpty(locationText.getText())) { String locationName = currentLocation.type == LocationObject.Type.City ? currentLocation.name : currentLocation.city + MaopaoLocationArea.MAOPAO_LOCATION_DIVIDE + currentLocation.name; params.put("location", ensureLength(locationName, 32)); params.put("coord", ensureLength(LocationCoord.from(currentLocation).toString(), 32)); params.put("address", ensureLength(currentLocation.address, 64)); } postNetwork(sendUrl, params, sendUrl); } private void finishWithoutSave() { // 清空输入的数据,因为在onDestroy时如果检测到有数据会保存 mEnterLayout.clearContent(); mData.clear(); finish(); } @Override public void parseJson(int code, JSONObject respanse, String tag, int pos, Object data) throws JSONException { if (tag.equals(sendUrl)) { showProgressBar(false); if (code == 0) { umengEvent(UmengEvent.MAOPAO, "发冒泡"); JSONObject jsonData = respanse.getJSONObject("data"); Maopao.MaopaoObject maopaoObject = new Maopao.MaopaoObject(jsonData); maopaoObject.owner = MyApp.sUserObject; maopaoObject.owner_id = MyApp.sUserObject.id; Intent intent = new Intent(); intent.putExtra(ListModify.TYPE, ListModify.Add); intent.putExtra(ListModify.DATA, maopaoObject); setResult(Activity.RESULT_OK, intent); showMiddleToast("发表成功"); finishWithoutSave(); } else { showErrorMsg(code, respanse); } } else if (tag.equals(HOST_IMAGE)) { if (code == 0) { String fileUri = (String) data; for (int i = 0; i < mData.size(); ++i) { PhotoData item = mData.get(i); if (item.uri.toString().equals(fileUri)) { item.serviceUri = respanse.getString("data"); break; } } mHandler.sendEmptyMessage(0); } else { showProgressBar(false); showMiddleToast("上传图片失败"); } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String mGlobalKey = AccountInfo.loadAccount(this).global_key; if (mGlobalKey.isEmpty()) { Intent intent = new Intent(this, LoginActivity_.class); this.startActivity(intent); } Intent intent = getIntent(); String action = intent.getAction(); String type = intent.getType(); if (Intent.ACTION_SEND.equals(action) && type != null) { if (type.startsWith("image/")) { Uri imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); if (imageUri != null) { File outputFile; try { outputFile = photoOperate.scal(imageUri); mData.add(mData.size(), new MaopaoAddActivity.PhotoData(outputFile, new ImageInfo(imageUri.toString()))); adapter.notifyDataSetChanged(); } catch (Exception e) { showMiddleToast("缩放图片失败"); Global.errorLog(e); } } mIntentExtraString = intent.getStringExtra(Intent.EXTRA_TEXT); } else if (type.startsWith("text/")) { mIntentExtraString = intent.getStringExtra(Intent.EXTRA_TEXT); } } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { if (type.startsWith("image/")) { ArrayList<Uri> imagesUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); if (imagesUris != null) { try { for (Uri uri : imagesUris) { File outputFile = photoOperate.scal(uri); mData.add(new MaopaoAddActivity.PhotoData(outputFile, new ImageInfo(uri.toString()))); } } catch (Exception e) { showMiddleToast("缩放图片失败"); Global.errorLog(e); } adapter.notifyDataSetChanged(); } mIntentExtraString = intent.getStringExtra(Intent.EXTRA_TEXT); } } else if ("android.intent.action.SEND.net.coding.program".equals(action) && type != null) { if (type.startsWith("image/")) { String imageUri = intent.getStringExtra(Intent.EXTRA_STREAM); if (imageUri != null) { // File outputFile; // try { // outputFile = photoOperate.scal(imageUri); // mData.add(mData.size(), new MaopaoAddActivity.PhotoData(outputFile, new ImageInfo(imageUri.toString()))); // adapter.notifyDataSetChanged(); // } catch (Exception e) { // showMiddleToast("缩放图片失败"); // Global.errorLog(e); // } ImageSize size = new ImageSize(MyApp.sWidthPix, MyApp.sHeightPix); ImageLoader.getInstance().loadImage(imageUri, size, ImagePagerFragment.optionsImage, new SimpleImageLoadingListener() { @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { if (isFinishing()) { return; } try { File imageFile = ImageLoader.getInstance().getDiskCache().get(imageUri); String path = "file://" + imageFile.getPath(); ImageInfo imageInfo = new ImageInfo(path); File outputFile = photoOperate.scal(Uri.parse(path)); mData.add(new MaopaoAddActivity.PhotoData(outputFile, imageInfo)); adapter.notifyDataSetChanged(); } catch (Exception e) { showMiddleToast("缩放图片失败"); Global.errorLog(e); } } }); } // TODO 因为mart app那边的bug,项目链接有两个,这里做了一下去重处理 String stringExtra = intent.getStringExtra(Intent.EXTRA_TEXT); String martHost = "https://mart.coding.net/"; int urlStart = stringExtra.lastIndexOf(martHost); if (urlStart != -1) { String martUrl = stringExtra.substring(urlStart, stringExtra.length()); String splitLastUrl = stringExtra.substring(0, urlStart); int urlStart2 = splitLastUrl.lastIndexOf(martUrl); if (urlStart2 != -1) { stringExtra = splitLastUrl; } } mIntentExtraString = stringExtra; } } } @Click(R.id.locationText) void chooseLocation() { if (PhoneType.isX86or64()) { showMiddleToast("定位功能不支持x86或64位的手机"); return; } LocationSearchActivity_.intent(this).selectedLocation(currentLocation).startForResult(RESULT_REQUEST_LOCATION); } @OnActivityResult(RESULT_REQUEST_LOCATION) void on_RESULT_REQUEST_LOCATION(int result, @OnActivityResult.Extra LocationObject location) { if (result == RESULT_OK) { currentLocation = location; updateLocationText(); } } private void updateLocationText() { locationText.setText(currentLocation.name); locationText.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable( currentLocation.type == LocationObject.Type.Undefined ? R.drawable.ic_location_inactive : R.drawable.ic_location_active), null, null, null); } @Click protected final void popPhoto() { startPhotoPickActivity(); } @Click protected final void popAt() { TextWatcherAt.startActivityAt(this, this, RESULT_REQUEST_FOLLOW); } @Click protected final void popTopic() { Intent intent = new Intent(this, SubjectNewActivity_.class); startActivityForResult(intent, RESULT_REQUEST_TOPIC); } public static class PhotoData { ImageInfo mImageinfo; Uri uri = Uri.parse(""); String serviceUri = ""; public PhotoData(File file, ImageInfo info) { uri = Uri.fromFile(file); mImageinfo = info; } public PhotoData(PhotoDataSerializable data) { uri = Uri.parse(data.uriString); serviceUri = data.serviceUri; mImageinfo = data.mImageInfo; } } // 因为PhotoData包含Uri,不能直接序列化,所以有了这个类 public static class PhotoDataSerializable implements Serializable { String uriString = ""; String serviceUri = ""; ImageInfo mImageInfo; public PhotoDataSerializable(PhotoData data) { uriString = data.uri.toString(); serviceUri = data.serviceUri; mImageInfo = data.mImageinfo; } } public static class MaopaoDraft implements Serializable { private String input = ""; private LocationObject locationObject = LocationObject.undefined(); private ArrayList<PhotoDataSerializable> photos = new ArrayList<>(); public MaopaoDraft() { } public MaopaoDraft(String input, ArrayList<PhotoData> photos, LocationObject locationObject) { this.input = input; this.photos = new ArrayList<>(); for (PhotoData item : photos) { this.photos.add(new PhotoDataSerializable(item)); } this.locationObject = locationObject; } public boolean isEmpty() { return input.isEmpty() && photos.isEmpty(); } public String getInput() { return input; } public LocationObject getLocation() { return locationObject; } public ArrayList<PhotoData> getPhotos() { ArrayList<PhotoData> data = new ArrayList<>(); for (PhotoDataSerializable item : photos) { data.add(new PhotoData(item)); } return data; } } }