/** * Copyright (c) 2012 Todoroo Inc * * See the file "LICENSE" for the full license governing this code. */ package com.todoroo.astrid.actfm; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; import android.os.Bundle; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup.LayoutParams; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.Window; import com.timsu.astrid.R; import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.service.ExceptionService; import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.actfm.ActFmCameraModule.CameraResultCallback; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.actfm.sync.ActFmSyncService; import com.todoroo.astrid.activity.FilterListFragment; import com.todoroo.astrid.activity.ShortcutActivity; import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.dao.TagMetadataDao; import com.todoroo.astrid.dao.TagMetadataDao.TagMetadataCriteria; import com.todoroo.astrid.dao.UserDao; import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagMetadata; import com.todoroo.astrid.data.User; import com.todoroo.astrid.helper.AsyncImageView; import com.todoroo.astrid.helper.UUIDHelper; import com.todoroo.astrid.service.StatisticsConstants; import com.todoroo.astrid.service.StatisticsService; import com.todoroo.astrid.service.TagDataService; import com.todoroo.astrid.service.ThemeService; import com.todoroo.astrid.tags.TagFilterExposer; import com.todoroo.astrid.tags.TagMemberMetadata; import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.ui.PeopleContainer; import com.todoroo.astrid.ui.PeopleContainer.ParseSharedException; import com.todoroo.astrid.utility.AstridPreferences; import com.todoroo.astrid.utility.ResourceDrawableCache; import com.todoroo.astrid.welcome.HelpInfoPopover; import edu.mit.mobile.android.imagecache.ImageCache; public class TagSettingsActivity extends SherlockFragmentActivity { public static final String TOKEN_NEW_FILTER = "newFilter"; //$NON-NLS-1$ private static final int MENU_SAVE_ID = R.string.TEA_menu_save; private static final int MENU_DISCARD_ID = R.string.TEA_menu_discard; public static final int REQUEST_ACTFM_LOGIN = 3; public static final String TOKEN_AUTOPOPULATE_MEMBERS = "autopopulateMembers"; //$NON-NLS-1$ public static final String TOKEN_AUTOPOPULATE_NAME = "autopopulateName"; //$NON-NLS-1$ private static final String MEMBERS_IN_PROGRESS = "members"; //$NON-NLS-1$ private TagData tagData; private Filter filter; // Used for creating shortcuts, only initialized if necessary @Autowired TagService tagService; @Autowired TagDataService tagDataService; @Autowired ActFmSyncService actFmSyncService; @Autowired ActFmPreferenceService actFmPreferenceService; @Autowired ExceptionService exceptionService; @Autowired UserDao userDao; @Autowired TagMetadataDao tagMetadataDao; private PeopleContainer tagMembers; private AsyncImageView picture; private EditText tagName; private EditText tagDescription; private CheckBox isSilent; private Bitmap setBitmap; private final ImageCache imageCache; private boolean isNewTag = false; private boolean isDialog; public TagSettingsActivity() { DependencyInjectionService.getInstance().inject(this); imageCache = AsyncImageView.getImageCache(); } @Override protected void onCreate(Bundle savedInstanceState) { setupForDialogOrFullscreen(); super.onCreate(savedInstanceState); setContentView(R.layout.tag_settings_activity); if (isDialog) { LayoutParams params = getWindow().getAttributes(); params.width = LayoutParams.FILL_PARENT; params.height = LayoutParams.WRAP_CONTENT; DisplayMetrics metrics = getResources().getDisplayMetrics(); if ((metrics.widthPixels / metrics.density) >= AndroidUtilities.MIN_TABLET_HEIGHT) params.width = (3 * metrics.widthPixels) / 5; else if ((metrics.widthPixels / metrics.density) >= AndroidUtilities.MIN_TABLET_WIDTH) params.width = (4 * metrics.widthPixels) / 5; getWindow().setAttributes((android.view.WindowManager.LayoutParams) params); } tagData = getIntent().getParcelableExtra(TagViewFragment.EXTRA_TAG_DATA); if (tagData == null) { isNewTag = true; tagData = new TagData(); tagData.setValue(TagData.UUID, UUIDHelper.newUUID()); } ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayShowTitleEnabled(false); actionBar.setDisplayShowCustomEnabled(true); actionBar.setCustomView(R.layout.header_title_view); } setUpSettingsPage(); if(savedInstanceState != null && savedInstanceState.containsKey(MEMBERS_IN_PROGRESS)) { final String members = savedInstanceState.getString(MEMBERS_IN_PROGRESS); new Thread(new Runnable() { @Override public void run() { AndroidUtilities.sleepDeep(500); runOnUiThread(new Runnable() { @Override public void run() { updateMembers(members, RemoteModel.NO_UUID); } }); } }).start(); } showCollaboratorsPopover(); } private void setupForDialogOrFullscreen() { isDialog = AstridPreferences.useTabletLayout(this); if (isDialog) { setTheme(ThemeService.getDialogTheme()); if (AndroidUtilities.getSdkVersion() < 14) requestWindowFeature(Window.FEATURE_NO_TITLE); } else { ThemeService.applyTheme(this); ActionBar actionBar = getSupportActionBar(); if (Preferences.getBoolean(R.string.p_save_and_cancel, false)) { if (ThemeService.getTheme() == R.style.Theme_White_Alt) actionBar.setLogo(R.drawable.ic_menu_save_blue_alt); else actionBar.setLogo(R.drawable.ic_menu_save); } else { actionBar.setLogo(null); } } } private void showCollaboratorsPopover() { if (!Preferences.getBoolean(R.string.p_showed_collaborators_help, false)) { View members = findViewById(R.id.members_container); HelpInfoPopover.showPopover(this, members, R.string.help_popover_collaborators, null); Preferences.setBoolean(R.string.p_showed_collaborators_help, true); } } protected void setUpSettingsPage() { if (isDialog) { findViewById(R.id.save_and_cancel).setVisibility(View.VISIBLE); findViewById(R.id.cancel).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { finish(); } }); findViewById(R.id.save).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { saveSettings(); } }); } tagMembers = (PeopleContainer) findViewById(R.id.members_container); tagName = (EditText) findViewById(R.id.tag_name); tagDescription = (EditText) findViewById(R.id.tag_description); picture = (AsyncImageView) findViewById(R.id.picture); isSilent = (CheckBox) findViewById(R.id.tag_silenced); isSilent.setChecked(tagData.getFlag(TagData.FLAGS, TagData.FLAG_SILENT)); Button leaveListButton = (Button) findViewById(R.id.leave_list); leaveListButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showDeleteDialog(tagData); } }); if (isNewTag) { leaveListButton.setVisibility(View.GONE); } else if (tagData.getValue(TagData.MEMBER_COUNT) > 0) { leaveListButton.setText(getString(R.string.tag_leave_button)); } if(actFmPreferenceService.isLoggedIn()) { findViewById(R.id.tag_silenced_container).setVisibility(View.VISIBLE); } picture.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(getResources(), TagService.getDefaultImageIDForTag(tagData.getUuid()))); picture.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { ActFmCameraModule.showPictureLauncher(TagSettingsActivity.this, null); } }); if (isNewTag) { findViewById(R.id.create_shortcut_container).setVisibility(View.GONE); } else { findViewById(R.id.create_shortcut_container).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (filter == null) { filter = TagFilterExposer.filterFromTagData(TagSettingsActivity.this, tagData); } filter.listingIcon = picture.getImageBitmap(); FilterListFragment.showCreateShortcutDialog(TagSettingsActivity.this, ShortcutActivity.createIntent(filter), filter); } }); } refreshSettingsPage(); String autopopulateMembers = getIntent().getStringExtra(TOKEN_AUTOPOPULATE_MEMBERS); if (!TextUtils.isEmpty(autopopulateMembers)) { updateMembers(autopopulateMembers, RemoteModel.NO_UUID); getIntent().removeExtra(TOKEN_AUTOPOPULATE_MEMBERS); } String autopopulateName = getIntent().getStringExtra(TOKEN_AUTOPOPULATE_NAME); if (!TextUtils.isEmpty(autopopulateName)) { tagName.setText(autopopulateName); getIntent().removeExtra(TOKEN_AUTOPOPULATE_NAME); } } @SuppressWarnings("nls") private void saveSettings() { String oldName = tagData.getValue(TagData.NAME); String newName = tagName.getText().toString().trim(); if (TextUtils.isEmpty(newName)) { return; } boolean nameChanged = !oldName.equals(newName); TagService service = TagService.getInstance(); if (nameChanged) { if (oldName.equalsIgnoreCase(newName)) { // Change the capitalization of a list manually tagData.setValue(TagData.NAME, newName); service.rename(tagData.getUuid(), newName); } else { // Rename list--check for existing name newName = service.getTagWithCase(newName); tagName.setText(newName); if (!newName.equals(oldName)) { tagData.setValue(TagData.NAME, newName); service.rename(tagData.getUuid(), newName); } else { nameChanged = false; } } } //handles description part String newDesc = tagDescription.getText().toString(); tagData.setValue(TagData.TAG_DESCRIPTION, newDesc); if (setBitmap != null) { JSONObject pictureJson = RemoteModel.PictureHelper.savePictureJson(this, setBitmap); if (pictureJson != null) tagData.setValue(TagData.PICTURE, pictureJson.toString()); } JSONArray members; try { members = tagMembers.parseSharedWithAndTags(this, true).optJSONArray("p"); } catch (JSONException e) { exceptionService.displayAndReportError(this, "save-people", e); return; } catch (ParseSharedException e) { if(e.view != null) { e.view.setTextColor(Color.RED); e.view.requestFocus(); } DialogUtilities.okDialog(this, e.message, null); return; } if (members == null) members = new JSONArray(); if(members.length() > 0 && !actFmPreferenceService.isLoggedIn()) { if(newName.length() > 0 && oldName.length() == 0) { tagDataService.save(tagData); } DialogInterface.OnClickListener okListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface d, int which) { startActivityForResult(new Intent(TagSettingsActivity.this, ActFmLoginActivity.class), REQUEST_ACTFM_LOGIN); } }; DialogInterface.OnClickListener cancelListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface d, int which) { tagMembers.removeAllViews(); tagMembers.addPerson("", "", false); //$NON-NLS-1$ } }; DialogUtilities.okCancelCustomDialog(TagSettingsActivity.this, getString(R.string.actfm_EPA_login_button), getString(R.string.actfm_TVA_login_to_share), R.string.actfm_EPA_login_button, R.string.actfm_EPA_dont_share_button, android.R.drawable.ic_dialog_alert, okListener, cancelListener); return; } int oldMemberCount = tagData.getValue(TagData.MEMBER_COUNT); if (members.length() > oldMemberCount) { StatisticsService.reportEvent(StatisticsConstants.ACTFM_LIST_SHARED); } tagData.setValue(TagData.MEMBER_COUNT, members.length()); tagData.setFlag(TagData.FLAGS, TagData.FLAG_SILENT, isSilent.isChecked()); InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(tagName.getWindowToken(), 0); tagDataService.save(tagData); tagMetadataDao.synchronizeMembers(tagData, tagData.getValue(TagData.MEMBERS), tagData.getUuid(), members); if (isNewTag) { setResult(RESULT_OK, new Intent().putExtra(TOKEN_NEW_FILTER, TagFilterExposer.filterFromTagData(TagSettingsActivity.this, tagData))); } else { setResult(RESULT_OK); } refreshSettingsPage(); finish(); } private void saveTagPictureLocally(Bitmap bitmap) { if (bitmap == null) return; try { String tagPicture = RemoteModel.PictureHelper.getPictureHash(tagData); imageCache.put(tagPicture, bitmap); tagData.setValue(TagData.PICTURE, tagPicture); } catch (Exception e) { e.printStackTrace(); } } @Override public void finish() { finishWithAnimation(!isDialog); } private void finishWithAnimation(boolean backAnimation) { super.finish(); if (backAnimation) { AndroidUtilities.callOverridePendingTransition(this, R.anim.slide_right_in, R.anim.slide_right_out); } } private void refreshSettingsPage() { tagName.setText(tagData.getValue(TagData.NAME)); ActionBar ab = getSupportActionBar(); if (ab != null) { View customView = ab.getCustomView(); TextView titleView = (TextView) customView.findViewById(R.id.title); if (isNewTag) { titleView.setText(getString(R.string.tag_new_list)); } else { titleView.setText(getString(R.string.tag_settings_title)); } } else { if (isNewTag) { setTitle(getString(R.string.tag_new_list)); } else { setTitle(getString(R.string.tag_settings_title)); } } String imageUrl = tagData.getPictureUrl(TagData.PICTURE, RemoteModel.PICTURE_MEDIUM); Bitmap imageBitmap = null; if (TextUtils.isEmpty(imageUrl)) imageBitmap = tagData.getPictureBitmap(TagData.PICTURE); if (imageBitmap != null) picture.setImageBitmap(imageBitmap); else picture.setUrl(imageUrl); if (!isNewTag) { ImageView shortcut = (ImageView) findViewById(R.id.create_shortcut); shortcut.setImageBitmap(FilterListFragment.superImposeListIcon(this, picture.getImageBitmap(), tagData.getUuid())); } String peopleJson = tagData.getValue(TagData.MEMBERS); updateMembers(peopleJson, tagData.getUuid()); tagDescription.setText(tagData.getValue(TagData.TAG_DESCRIPTION)); } @SuppressWarnings("nls") private void updateMembers(String peopleJson, String tagUuid) { tagMembers.removeAllViews(); JSONArray people = null; try { people = new JSONArray(peopleJson); } catch (JSONException e) { if (!RemoteModel.isUuidEmpty(tagUuid)) { people = new JSONArray(); TodorooCursor<User> members = userDao.query(Query.select(User.PROPERTIES) .where(User.UUID.in(Query.select(TagMemberMetadata.USER_UUID) .from(TagMetadata.TABLE).where(Criterion.and(TagMetadataCriteria.byTagAndWithKey(tagUuid, TagMemberMetadata.KEY), TagMetadata.DELETION_DATE.eq(0)))))); try { User user = new User(); for (members.moveToFirst(); !members.isAfterLast(); members.moveToNext()) { user.clear(); user.readFromCursor(members); try { JSONObject userJson = new JSONObject(); ActFmSyncService.JsonHelper.jsonFromUser(userJson, user); people.put(userJson); } catch (JSONException e2) { // } } } finally { members.close(); } TodorooCursor<TagMetadata> emailMembers = tagMetadataDao.query(Query.select(TagMemberMetadata.USER_UUID) .where(Criterion.and(TagMetadataCriteria.byTagAndWithKey(tagUuid, TagMemberMetadata.KEY), TagMetadata.DELETION_DATE.eq(0), TagMemberMetadata.USER_UUID.like("%@%")))); try { TagMetadata m = new TagMetadata(); for (emailMembers.moveToFirst(); !emailMembers.isAfterLast(); emailMembers.moveToNext()) { m.clear(); m.readFromCursor(emailMembers); try { JSONObject userJson = new JSONObject(); userJson.put("email", m.getValue(TagMemberMetadata.USER_UUID)); people.put(userJson); } catch (JSONException e2) { // } } } finally { emailMembers.close(); } User u = userDao.fetch(tagData.getValue(TagData.USER_ID), User.PROPERTIES); if (u != null) { try { JSONObject owner = new JSONObject(); ActFmSyncService.JsonHelper.jsonFromUser(owner, u); owner.put("owner", true); people.put(owner); } catch (JSONException e2) { // } } } } if (people != null) { try { tagMembers.fromJSONArray(people); } catch (JSONException e) { Log.e("tag-settings", "Error parsing tag members: " + people, e); } } tagMembers.addPerson("", "", false); //$NON-NLS-1$ } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if(tagMembers.getChildCount() > 1) { JSONArray members = tagMembers.toJSONArray(); outState.putString(MEMBERS_IN_PROGRESS, members.toString()); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { CameraResultCallback callback = new CameraResultCallback() { @Override public void handleCameraResult(Bitmap bitmap) { picture.setImageBitmap(bitmap); setBitmap = bitmap; saveTagPictureLocally(bitmap); } }; if (ActFmCameraModule.activityResult(this, requestCode, resultCode, data, callback)) { // Handled } else if(requestCode == REQUEST_ACTFM_LOGIN && resultCode == Activity.RESULT_OK) { saveSettings(); } else { super.onActivityResult(requestCode, resultCode, data); } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuItem item; if (Preferences.getBoolean(R.string.p_save_and_cancel, false)) { item = menu.add(Menu.NONE, MENU_DISCARD_ID, 0, R.string.TEA_menu_discard); item.setIcon(ThemeService.getDrawable(R.drawable.ic_menu_close)); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } if (isDialog) { item = menu.add(Menu.NONE, MENU_SAVE_ID, 0, R.string.TEA_menu_save); item.setIcon(ThemeService.getDrawable(R.drawable.ic_menu_save)); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } return super.onCreateOptionsMenu(menu); } @Override public void onBackPressed() { if (tagName.getText().length() == 0) { finish(); } else { saveSettings(); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case MENU_DISCARD_ID: finish(); break; case MENU_SAVE_ID: saveSettings(); break; case android.R.id.home: saveSettings(); if (!isFinishing()) finish(); break; } return super.onOptionsItemSelected(item); } protected void showDeleteDialog(TagData td) { if(td == null) return; int string; if (td.getValue(TagData.MEMBER_COUNT) > 0) string = R.string.DLG_leave_this_shared_tag_question; else string = R.string.DLG_delete_this_tag_question; DialogUtilities.okCancelDialog(this, getString(string, td.getValue(TagData.NAME)), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { deleteTag(); } }, null ); } protected void deleteTag() { Intent result = tagService.deleteOrLeaveTag(this, tagData.getValue(TagData.NAME), tagData.getUuid()); setResult(Activity.RESULT_OK, result); finish(); } }