diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/BlogPreferencesActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/prefs/BlogPreferencesActivity.java index db2316c62e28..8734a732d5bc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/BlogPreferencesActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/BlogPreferencesActivity.java @@ -1,34 +1,17 @@ package org.wordpress.android.ui.prefs; -import android.app.AlertDialog; -import android.content.DialogInterface; +import android.app.Fragment; import android.os.Bundle; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.TextView; import android.widget.Toast; import org.wordpress.android.R; import org.wordpress.android.WordPress; -import org.wordpress.android.models.AccountHelper; import org.wordpress.android.models.Blog; import org.wordpress.android.ui.ActivityLauncher; -import org.wordpress.android.ui.stats.datasets.StatsTable; -import org.wordpress.android.util.AnalyticsUtils; -import org.wordpress.android.util.CoreEvents.UserSignedOutCompletely; import org.wordpress.android.util.StringUtils; -import org.wordpress.android.util.ToastUtils; - -import de.greenrobot.event.EventBus; /** * Activity for configuring blog specific settings. @@ -39,20 +22,10 @@ public class BlogPreferencesActivity extends AppCompatActivity { // The blog this activity is managing settings for. private Blog blog; - private boolean mBlogDeleted; - private EditText mUsernameET; - private EditText mPasswordET; - private EditText mHttpUsernameET; - private EditText mHttpPasswordET; - private CheckBox mFullSizeCB; - private CheckBox mScaledCB; - private Spinner mImageWidthSpinner; - private EditText mScaledImageWidthET; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.blog_preferences); Integer id = getIntent().getIntExtra(ARG_LOCAL_BLOG_ID, -1); blog = WordPress.getBlog(id); @@ -63,39 +36,28 @@ public void onCreate(Bundle savedInstanceState) { return; } + Fragment siteSettingsFragment = new SiteSettingsFragment(); + siteSettingsFragment.setArguments(getIntent().getExtras()); + getFragmentManager().beginTransaction() + .replace(android.R.id.content, siteSettingsFragment) + .commit(); + ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setElevation(0.0f); actionBar.setTitle(StringUtils.unescapeHTML(blog.getNameOrHostUrl())); actionBar.setDisplayHomeAsUpEnabled(true); } + } - mUsernameET = (EditText) findViewById(R.id.username); - mPasswordET = (EditText) findViewById(R.id.password); - mHttpUsernameET = (EditText) findViewById(R.id.httpuser); - mHttpPasswordET = (EditText) findViewById(R.id.httppassword); - mScaledImageWidthET = (EditText) findViewById(R.id.scaledImageWidth); - mFullSizeCB = (CheckBox) findViewById(R.id.fullSizeImage); - mScaledCB = (CheckBox) findViewById(R.id.scaledImage); - mImageWidthSpinner = (Spinner) findViewById(R.id.maxImageWidth); - Button removeBlogButton = (Button) findViewById(R.id.remove_account); + @Override + public void setTitle(CharSequence title) { + super.setTitle(title); - // remove blog & credentials apply only to dot org - if (blog.isDotcomFlag()) { - View credentialsRL = findViewById(R.id.sectionContent); - credentialsRL.setVisibility(View.GONE); - removeBlogButton.setVisibility(View.GONE); - } else { - removeBlogButton.setVisibility(View.VISIBLE); - removeBlogButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - removeBlogWithConfirmation(); - } - }); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setTitle(title); } - - loadSettingsForBlog(); } @Override @@ -108,50 +70,6 @@ public void finish() { protected void onPause() { super.onPause(); - if (mBlogDeleted) { - return; - } - - blog.setUsername(mUsernameET.getText().toString()); - blog.setPassword(mPasswordET.getText().toString()); - blog.setHttpuser(mHttpUsernameET.getText().toString()); - blog.setHttppassword(mHttpPasswordET.getText().toString()); - - blog.setFullSizeImage(mFullSizeCB.isChecked()); - blog.setScaledImage(mScaledCB.isChecked()); - if (blog.isScaledImage()) { - EditText scaledImgWidth = (EditText) findViewById(R.id.scaledImageWidth); - - boolean error = false; - int width = 0; - try { - width = Integer.parseInt(scaledImgWidth.getText().toString().trim()); - } catch (NumberFormatException e) { - error = true; - } - - if (width == 0) { - error = true; - } - - if (error) { - AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(BlogPreferencesActivity.this); - dialogBuilder.setTitle(getResources().getText(R.string.error)); - dialogBuilder.setMessage(getResources().getText(R.string.scaled_image_error)); - dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - } - }); - dialogBuilder.setCancelable(true); - dialogBuilder.create().show(); - return; - } else { - blog.setScaledImageWidth(width); - } - } - - blog.setMaxImageWidth(mImageWidthSpinner.getSelectedItem().toString()); - WordPress.wpDB.saveBlog(blog); if (WordPress.getCurrentBlog().getLocalTableBlogId() == blog.getLocalTableBlogId()) { @@ -169,135 +87,4 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } - - private void loadSettingsForBlog() { - ArrayAdapter spinnerArrayAdapter = new ArrayAdapter(this, - R.layout.simple_spinner_item, new String[]{ - "Original Size", "100", "200", "300", "400", "500", "600", "700", "800", - "900", "1000", "1100", "1200", "1300", "1400", "1500", "1600", "1700", - "1800", "1900", "2000" - }); - spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mImageWidthSpinner.setAdapter(spinnerArrayAdapter); - mImageWidthSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - CheckBox fullSizeImageCheckBox = (CheckBox) findViewById(R.id.fullSizeImage); - // Original size selected. Do not show the link to full image. - if (id == 0) { - fullSizeImageCheckBox.setVisibility(View.GONE); - } else { - fullSizeImageCheckBox.setVisibility(View.VISIBLE); - } - } - - @Override - public void onNothingSelected(AdapterView arg0) { - } - }); - - mUsernameET.setText(blog.getUsername()); - mPasswordET.setText(blog.getPassword()); - mHttpUsernameET.setText(blog.getHttpuser()); - mHttpPasswordET.setText(blog.getHttppassword()); - TextView httpUserLabel = (TextView) findViewById(R.id.l_httpuser); - if (blog.isDotcomFlag()) { - mHttpUsernameET.setVisibility(View.GONE); - mHttpPasswordET.setVisibility(View.GONE); - httpUserLabel.setVisibility(View.GONE); - } else { - mHttpUsernameET.setVisibility(View.VISIBLE); - mHttpPasswordET.setVisibility(View.VISIBLE); - httpUserLabel.setVisibility(View.VISIBLE); - } - - mFullSizeCB.setChecked(blog.isFullSizeImage()); - mScaledCB.setChecked(blog.isScaledImage()); - - this.mScaledImageWidthET.setText("" + blog.getScaledImageWidth()); - showScaledSetting(blog.isScaledImage()); - - CheckBox scaledImage = (CheckBox) findViewById(R.id.scaledImage); - scaledImage.setChecked(false); - scaledImage.setVisibility(View.GONE); - - // sets up a state listener for the full-size checkbox - CheckBox fullSizeImageCheckBox = (CheckBox) findViewById(R.id.fullSizeImage); - fullSizeImageCheckBox.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - CheckBox fullSize = (CheckBox) findViewById(R.id.fullSizeImage); - if (fullSize.isChecked()) { - CheckBox scaledImage = (CheckBox) findViewById(R.id.scaledImage); - if (scaledImage.isChecked()) { - scaledImage.setChecked(false); - showScaledSetting(false); - } - } - } - }); - - int imageWidthPosition = spinnerArrayAdapter.getPosition(blog.getMaxImageWidth()); - mImageWidthSpinner.setSelection((imageWidthPosition >= 0) ? imageWidthPosition : 0); - if (mImageWidthSpinner.getSelectedItemPosition() == - 0) //Original size selected. Do not show the link to full image. - { - fullSizeImageCheckBox.setVisibility(View.GONE); - } else { - fullSizeImageCheckBox.setVisibility(View.VISIBLE); - } - } - - /** - * Hides / shows the scaled image settings - */ - private void showScaledSetting(boolean show) { - TextView tw = (TextView) findViewById(R.id.l_scaledImage); - EditText et = (EditText) findViewById(R.id.scaledImageWidth); - tw.setVisibility(show ? View.VISIBLE : View.GONE); - et.setVisibility(show ? View.VISIBLE : View.GONE); - } - - /** - * Remove the blog this activity is managing settings for. - */ - private void removeBlogWithConfirmation() { - AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); - dialogBuilder.setTitle(getResources().getText(R.string.remove_account)); - dialogBuilder.setMessage(getResources().getText(R.string.sure_to_remove_account)); - dialogBuilder.setPositiveButton(getResources().getText(R.string.yes), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - removeBlog(); - } - }); - dialogBuilder.setNegativeButton(getResources().getText(R.string.no), null); - dialogBuilder.setCancelable(false); - dialogBuilder.create().show(); - } - - private void removeBlog() { - if (WordPress.wpDB.deleteBlog(this, blog.getLocalTableBlogId())) { - StatsTable.deleteStatsForBlog(this,blog.getLocalTableBlogId()); // Remove stats data - AnalyticsUtils.refreshMetadata(); - ToastUtils.showToast(this, R.string.blog_removed_successfully); - WordPress.wpDB.deleteLastBlogId(); - WordPress.currentBlog = null; - mBlogDeleted = true; - setResult(RESULT_BLOG_REMOVED); - - // If the last blog is removed and the user is not signed in wpcom, broadcast a UserSignedOut event - if (!AccountHelper.isSignedIn()) { - EventBus.getDefault().post(new UserSignedOutCompletely()); - } - - finish(); - } else { - AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); - dialogBuilder.setTitle(getResources().getText(R.string.error)); - dialogBuilder.setMessage(getResources().getText(R.string.could_not_remove_account)); - dialogBuilder.setPositiveButton("OK", null); - dialogBuilder.setCancelable(true); - dialogBuilder.create().show(); - } - } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/SiteSettingsFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/prefs/SiteSettingsFragment.java new file mode 100644 index 000000000000..fd321807b10c --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/SiteSettingsFragment.java @@ -0,0 +1,337 @@ +package org.wordpress.android.ui.prefs; + +import android.os.Bundle; +import android.preference.EditTextPreference; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.PreferenceFragment; + +import com.android.volley.VolleyError; +import com.wordpress.rest.RestRequest; + +import org.json.JSONObject; +import org.wordpress.android.R; +import org.wordpress.android.WordPress; +import org.wordpress.android.models.Blog; +import org.wordpress.android.networking.RestClientUtils; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.ToastUtils; + +import java.util.HashMap; +import java.util.Locale; + +/** + * Handles changes to WordPress site settings. Syncs with host automatically when user leaves. + */ + +public class SiteSettingsFragment extends PreferenceFragment + implements Preference.OnPreferenceChangeListener { + private HashMap mLanguageCodes = new HashMap<>(); + private Blog mBlog; + private EditTextPreference mTitlePreference; + private EditTextPreference mTaglinePreference; + private EditTextPreference mAddressPreference; + private ListPreference mLanguagePreference; + private ListPreference mPrivacyPreference; + + // Most recent remote site data. Current local data is used if remote data cannot be fetched. + private String mRemoteTitle; + private String mRemoteTagline; + private String mRemoteAddress; + private int mRemotePrivacy; + private String mRemoteLanguage; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // make sure we have local site data + mBlog = WordPress.getBlog( + getArguments().getInt(BlogPreferencesActivity.ARG_LOCAL_BLOG_ID, -1)); + if (mBlog == null) return; + + // inflate Site Settings preferences from XML + addPreferencesFromResource(R.xml.site_settings); + + // set preference references, add change listeners, and setup various entries and values + initPreferences(); + + // fetch remote site data + fetchRemoteData(); + } + + @Override + public void onPause() { + super.onPause(); + + // Assume user wanted changes propagated when they leave + applyChanges(); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (newValue == null) return false; + + if (preference == mTitlePreference) { + // update the Activity title to reflect the changes + String titleFormat = getString(R.string.site_settings_title_format, "%s"); + getActivity().setTitle(String.format(titleFormat, newValue)); + + changeEditTextPreferenceValue(mTitlePreference, newValue.toString()); + return true; + } else if (preference == mTaglinePreference) { + changeEditTextPreferenceValue(mTaglinePreference, newValue.toString()); + return true; + } else if (preference == mAddressPreference) { + changeEditTextPreferenceValue(mAddressPreference, newValue.toString()); + return true; + } else if (preference == mLanguagePreference) { + changeLanguageValue(newValue.toString()); + return true; + } else if (preference == mPrivacyPreference) { + mPrivacyPreference.setSummary(privacyStringForValue(Integer.valueOf(newValue.toString()))); + return true; + } + + return false; + } + + private String privacyStringForValue(int value) { + switch (value) { + case -1: + return getString(R.string.site_privacy_private_desc); + case 0: + return getString(R.string.site_privacy_hidden_desc); + case 1: + return getString(R.string.site_privacy_public_desc); + default: + return ""; + } + } + + /** + * Helper method to perform validation and set multiple properties on an EditTextPreference. + * If newValue is equal to the current preference text no action will be taken. + */ + private void changeEditTextPreferenceValue(EditTextPreference pref, String newValue) { + if (pref != null && newValue != null && !newValue.equals(pref.getSummary())) { + pref.setText(newValue); + pref.setSummary(newValue); + } + } + + private void changeLanguageValue(String newValue) { + if (mLanguagePreference != null && !newValue.equals(mLanguagePreference.getValue())) { + mLanguagePreference.setValue(newValue); + mLanguagePreference.setSummary(getLanguageString(newValue, Locale.getDefault())); + } + } + + private void changePrivacyValue(int newValue) { + if (mPrivacyPreference != null && Integer.valueOf(mPrivacyPreference.getValue()) == newValue) { + mPrivacyPreference.setValue(String.valueOf(newValue)); + mPrivacyPreference.setSummary(privacyStringForValue(newValue)); + } + } + + /** + * Request remote site data via the WordPress REST API. + */ + private void fetchRemoteData() { + WordPress.getRestClientUtils().getGeneralSettings( + String.valueOf(mBlog.getRemoteBlogId()), new RestRequest.Listener() { + @Override + public void onResponse(JSONObject response) { + handleResponseToGeneralSettingsRequest(response); + } + }, new RestRequest.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + AppLog.w(AppLog.T.API, "Error GETing site settings: " + error); + if (isAdded()) { + ToastUtils.showToast(getActivity(), getString(R.string.error_fetch_remote_site_settings)); + getActivity().finish(); + } + } + }); + } + + /** + * Helper method to parse JSON response to REST request. + */ + private void handleResponseToGeneralSettingsRequest(JSONObject response) { + mRemoteTitle = response.optString(RestClientUtils.SITE_TITLE_KEY); + changeEditTextPreferenceValue(mTitlePreference, mRemoteTitle); + + mRemoteTagline = response.optString(RestClientUtils.SITE_DESC_KEY); + changeEditTextPreferenceValue(mTaglinePreference, mRemoteTagline); + + mRemoteAddress = response.optString(RestClientUtils.SITE_URL_KEY); + changeEditTextPreferenceValue(mAddressPreference, mRemoteAddress); + + mRemoteLanguage = response.optString(RestClientUtils.SITE_LANGUAGE_KEY); + if (mLanguagePreference != null) { + changeLanguageValue(mRemoteLanguage); + mLanguagePreference.setSummary(getLanguageString(mRemoteLanguage, Locale.getDefault())); + } + + mRemotePrivacy = response.optJSONObject("settings").optInt("blog_public"); + if (mPrivacyPreference != null) { + mPrivacyPreference.setValue(String.valueOf(mRemotePrivacy)); + } + changePrivacyValue(mRemotePrivacy); + } + + /** + * Helper method to create the parameters for the site settings POST request + */ + private HashMap generatePostParams() { + HashMap params = new HashMap<>(); + + // Using undocumented endpoint WPCOM_JSON_API_Site_Settings_Endpoint + // https://wpcom.trac.automattic.com/browser/trunk/public.api/rest/json-endpoints.php#L1903 + if (mTitlePreference != null && !mTitlePreference.getText().equals(mRemoteTitle)) { + params.put("blogname", mTitlePreference.getText()); + } + + if (mTaglinePreference != null && !mTaglinePreference.getText().equals(mRemoteTagline)) { + params.put("blogdescription", mTaglinePreference.getText()); + } + + if (mAddressPreference != null && !mAddressPreference.getText().equals(mRemoteAddress)) { + // TODO + } + + if (mLanguagePreference != null && + mLanguageCodes.containsKey(mLanguagePreference.getValue()) && + !mRemoteLanguage.equals(mLanguageCodes.get(mLanguagePreference.getValue()))) { + params.put("lang_id", String.valueOf(mLanguageCodes.get(mLanguagePreference.getValue()))); + } + + if (mPrivacyPreference != null && Integer.valueOf(mPrivacyPreference.getValue()) != mRemotePrivacy) { + params.put("blog_public", mPrivacyPreference.getValue()); + } + + return params; + } + + /** + * Reverts changed preferences + */ + private void undoChanges() { + changeEditTextPreferenceValue(mTitlePreference, mRemoteTitle); + changeEditTextPreferenceValue(mTaglinePreference, mRemoteTagline); + changeEditTextPreferenceValue(mAddressPreference, mRemoteAddress); + + // Privacy must exist in the set {-1, 0, 1} to be valid + if (mRemotePrivacy > -2 && mRemotePrivacy < 2 && + mRemotePrivacy != Integer.valueOf(mPrivacyPreference.getValue())) { + mPrivacyPreference.setValue(String.valueOf(mRemotePrivacy)); + } + + if (mRemoteLanguage != null && !mRemoteLanguage.equals(getLanguageString(mLanguagePreference.getValue(), Locale.getDefault()))) { + mLanguagePreference.setValue(mRemoteLanguage); + } + } + + /** + * Persists changed settings remotely + */ + private void applyChanges() { + final HashMap params = generatePostParams(); + + if (params.size() > 0) { + WordPress.getRestClientUtils().setGeneralSiteSettings( + String.valueOf(mBlog.getRemoteBlogId()), new RestRequest.Listener() { + @Override + public void onResponse(JSONObject response) { + // Update local Blog name + if (params.containsKey("blogname")) { + mBlog.setBlogName(params.get("blogname")); + } + } + }, new RestRequest.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + AppLog.w(AppLog.T.API, "Error POSTing site settings changes: " + error); + if (isAdded()) { + ToastUtils.showToast(getActivity(), getString(R.string.error_post_remote_site_settings)); + } + } + }, params); + } + } + + /** + * Helper method to setup preferences and set initial values + */ + private void initPreferences() { + mTitlePreference = + (EditTextPreference) findPreference(getString(R.string.pref_key_site_title)); + mTaglinePreference = + (EditTextPreference) findPreference(getString(R.string.pref_key_site_tagline)); + mAddressPreference = + (EditTextPreference) findPreference(getString(R.string.pref_key_site_address)); + mPrivacyPreference = + (ListPreference) findPreference(getString(R.string.pref_key_site_visibility)); + mLanguagePreference = + (ListPreference) findPreference(getString(R.string.pref_key_site_language)); + + if (mTitlePreference != null) { + mTitlePreference.setOnPreferenceChangeListener(this); + } + + if (mTaglinePreference != null) { + mTaglinePreference.setOnPreferenceChangeListener(this); + } + + if (mAddressPreference != null) { + mAddressPreference.setOnPreferenceChangeListener(this); + } + + if (mPrivacyPreference != null) { + mRemotePrivacy = -2; + mPrivacyPreference.setOnPreferenceChangeListener(this); + } + + if (mLanguagePreference != null) { + // Generate map of language codes + String[] languageIds = getResources().getStringArray(R.array.lang_ids); + String[] languageCodes = getResources().getStringArray(R.array.language_codes); + for (int i = 0; i < languageIds.length && i < languageCodes.length; ++i) { + mLanguageCodes.put(languageCodes[i], languageIds[i]); + } + + mLanguagePreference.setEntries( + createLanguageDisplayStrings(mLanguagePreference.getEntryValues())); + mLanguagePreference.setOnPreferenceChangeListener(this); + } + } + + /** + * Generates display strings for given language codes. Used as entries in language preference. + */ + private CharSequence[] createLanguageDisplayStrings(CharSequence[] languageCodes) { + if (languageCodes == null || languageCodes.length < 1) return null; + + CharSequence[] displayStrings = new CharSequence[languageCodes.length]; + + for (int i = 0; i < languageCodes.length; ++i) { + displayStrings[i] = getLanguageString(String.valueOf(languageCodes[i]), Locale.getDefault()); + } + + return displayStrings; + } + + /** + * Return a non-null display string for a given language code. + */ + private String getLanguageString(String languageCode, Locale displayLocale) { + if (languageCode == null || languageCode.length() < 2 || languageCode.length() > 6) { + return ""; + } + + Locale languageLocale = new Locale(languageCode.substring(0, 2)); + return languageLocale.getDisplayLanguage(displayLocale) + languageCode.substring(2); + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/SummaryEditTextPreference.java b/WordPress/src/main/java/org/wordpress/android/ui/prefs/SummaryEditTextPreference.java new file mode 100644 index 000000000000..19d8b5ba36d9 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/SummaryEditTextPreference.java @@ -0,0 +1,69 @@ +package org.wordpress.android.ui.prefs; + +import android.content.Context; +import android.content.res.TypedArray; +import android.preference.EditTextPreference; +import android.support.annotation.NonNull; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.widget.TextView; + +import org.wordpress.android.R; + +/** + * Standard EditTextPreference that has attributes to limit summary length. + * + * Created for and used by {@link SiteSettingsFragment} to style some Preferences. + * + * When declaring this class in a layout file you can use the following attributes: + * - app:summaryLines : sets the number of lines to display in the Summary field + * (see {@link TextView#setLines(int)} for details) + * - app:maxSummaryLines : sets the maximum number of lines the Summary field can display + * (see {@link TextView#setMaxLines(int)} for details) + */ + +public class SummaryEditTextPreference extends EditTextPreference { + private int mLines; + private int mMaxLines; + + public SummaryEditTextPreference(Context context) { + super(context); + } + + public SummaryEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public SummaryEditTextPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + mLines = -1; + mMaxLines = -1; + + TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SummaryEditTextPreference); + + for (int i = 0; i < array.getIndexCount(); ++i) { + int index = array.getIndex(i); + if (index == R.styleable.SummaryEditTextPreference_summaryLines) { + mLines = array.getInt(index, -1); + } else if (index == R.styleable.SummaryEditTextPreference_maxSummaryLines) { + mMaxLines = array.getInt(index, -1); + } + } + + array.recycle(); + } + + @Override + public void onBindView(@NonNull View view) { + super.onBindView(view); + + TextView summary = (TextView) view.findViewById(android.R.id.summary); + if (summary != null) { + summary.setEllipsize(TextUtils.TruncateAt.END); + if (mLines != -1) summary.setLines(mLines); + if (mMaxLines != -1) summary.setMaxLines(mMaxLines); + } + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/util/WPRestClient.java b/WordPress/src/main/java/org/wordpress/android/util/WPRestClient.java index d82f161e6c3c..4d6d327d49af 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/WPRestClient.java +++ b/WordPress/src/main/java/org/wordpress/android/util/WPRestClient.java @@ -255,6 +255,13 @@ public void getStatsVideoSummary(String siteId, Listener listener, ErrorListener getXL(path, params, listener, errorListener); } + public void getSiteDescription(String siteId, Listener listener, ErrorListener errorListener) { + String path = String.format("rest/v1.1/sites/%s", siteId); + Map params = new HashMap(); + params.put("fields", "description"); + get(path, params, null, listener, errorListener); + } + /** * This method is for simulating stats APIs using the XL Studio API simulator. It should be removed once the other APIs are implemented. **/ diff --git a/WordPress/src/main/res/values/attrs.xml b/WordPress/src/main/res/values/attrs.xml index 2a9dfa05d2c6..699426dc697f 100644 --- a/WordPress/src/main/res/values/attrs.xml +++ b/WordPress/src/main/res/values/attrs.xml @@ -1,5 +1,12 @@ + + + + + + + diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index b3bd58bd9151..74fd58c4f406 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -399,6 +399,32 @@ wp_pref_notification_blogs wp_pref_notifications_enabled wp_pref_notification_types + wp_pref_site_title + wp_pref_site_tagline + wp_pref_site_address + wp_pref_site_language + wp_pref_site_visibility + wp_pref_site_related_posts + wp_pref_site_location + wp_pref_site_default_category + wp_pref_site_default_format + wp_pref_site_discussion + wp_pref_site_start_over + wp_pref_site_delete_site + + + Settings - %s + General + Site Title + Tagline + Address + Privacy + @string/language + What\'s this site about + Words to live by + Related Posts + Related Posts + Show related content after posts Open source licenses @@ -612,6 +638,94 @@ Video + + + Public + Hidden + Private + + + + + 1 + 0 + -1 + + + + + az + en + de + el + es + fr + gd + hi + hu + id + it + ja + ko + nl + pl + ru + sv + th + uz + zh_CN + zh_TW + en-GB + tr + eu + he + pt-BR + ar + ro + mk + sr + sk + cy + da + + + + + 79 + 1 + 15 + 17 + 19 + 24 + 476 + 30 + 31 + 33 + 35 + 36 + 40 + 49 + 58 + 62 + 68 + 71 + 458 + 449 + 452 + 482 + 78 + 429 + 29 + 438 + 3 + 61 + 435 + 67 + 64 + 13 + 14 + + New post New media @@ -669,6 +783,8 @@ This blog is hidden and couldn\'t be loaded. Enable it again in settings and try again. An error occurred while creating the app database. Try reinstalling the app. An error occurred while copying text to clipboard + Couldn\'t retrieve site info + Couldn\'t save site info Add media @@ -926,5 +1042,8 @@ My Site Me + I would like my site to be private, visible only to users I choose + Discourage search engines from indexing this site + Allow search engines to index this site diff --git a/WordPress/src/main/res/xml/site_settings.xml b/WordPress/src/main/res/xml/site_settings.xml new file mode 100644 index 000000000000..9af86660258c --- /dev/null +++ b/WordPress/src/main/res/xml/site_settings.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientUtils.java b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientUtils.java index 05deeb0882b4..2d2aab35949b 100644 --- a/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientUtils.java +++ b/libs/networking/WordPressNetworking/src/main/java/org/wordpress/android/networking/RestClientUtils.java @@ -22,6 +22,11 @@ import java.util.concurrent.TimeoutException; public class RestClientUtils { + public static final String SITE_TITLE_KEY = "name"; + public static final String SITE_DESC_KEY = "description"; + public static final String SITE_LANGUAGE_KEY = "lang"; + public static final String SITE_URL_KEY = "URL"; + private static final String NOTIFICATION_FIELDS = "id,type,unread,body,subject,timestamp,meta"; private static final String COMMENT_REPLY_CONTENT_FIELD = "content"; private static String sUserAgent = "WordPress Networking Android"; @@ -218,6 +223,19 @@ public void getCurrentTheme(String siteId, Listener listener, ErrorListener erro get(path, listener, errorListener); } + public void getGeneralSettings(String siteId, Listener listener, ErrorListener errorListener) { + String path = String.format("sites/%s/settings", siteId); + Map params = new HashMap(); +// params.put("fields", "blogname,blogdescription,lang_id,blog_public"); + get(path, params, null, listener, errorListener); + } + + public void setGeneralSiteSettings(String siteId, Listener listener, ErrorListener errorListener, + Map params) { + String path = String.format("sites/%s/settings", siteId); + post(path, params, null, listener, errorListener); + } + /** * Make GET request */ diff --git a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/StringUtils.java b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/StringUtils.java index 68e3113c3d5d..6f73e6dd6ad2 100644 --- a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/StringUtils.java +++ b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/StringUtils.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; public class StringUtils { public static String[] mergeStringArrays(String array1[], String array2[]) { @@ -228,6 +229,28 @@ public static String replaceUnicodeSurrogateBlocksWithHTMLEntities(final String return out.toString(); } + /** + * Used to convert a language code ([lc]_[rc] where lc is language code (en, fr, es, etc...) + * and rc is region code (zh-CN, zh-HK, zh-TW, etc...) to a displayable string with the languages + * name. + * + * The input string must be between 2 and 6 characters, inclusive. An empty string is returned + * if that is not the case. + * + * If the input string is recognized by {@link Locale} the result of this method is the given + * + * @return + * non-null + */ + public static String getLanguageString(String languagueCode, Locale displayLocale) { + if (languagueCode == null || languagueCode.length() < 2 || languagueCode.length() > 6) { + return ""; + } + + Locale languageLocale = new Locale(languagueCode.substring(0, 2)); + return languageLocale.getDisplayLanguage(displayLocale) + languagueCode.substring(2); + } + /** * This method ensures that the output String has only * valid XML unicode characters as specified by the