diff --git a/WordPress/src/main/AndroidManifest.xml b/WordPress/src/main/AndroidManifest.xml
index b57f791769d3..e23ede6219ef 100644
--- a/WordPress/src/main/AndroidManifest.xml
+++ b/WordPress/src/main/AndroidManifest.xml
@@ -101,6 +101,7 @@
loadCategories(int id) {
Cursor c = db.query(CATEGORIES_TABLE, new String[] { "id", "wp_id",
- "category_name" }, "blog_id=" + id, null, null, null, null);
+ "category_name" }, "blog_id=" + Integer.toString(id), null, null, null, null);
int numRows = c.getCount();
c.moveToFirst();
List returnVector = new Vector();
diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/SiteSettingsTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/SiteSettingsTable.java
new file mode 100644
index 000000000000..e872d4274843
--- /dev/null
+++ b/WordPress/src/main/java/org/wordpress/android/datasets/SiteSettingsTable.java
@@ -0,0 +1,104 @@
+package org.wordpress.android.datasets;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+import org.wordpress.android.WordPress;
+import org.wordpress.android.models.CategoryModel;
+import org.wordpress.android.models.SiteSettingsModel;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public final class SiteSettingsTable {
+ public static final String CATEGORIES_TABLE_NAME = "site_categories";
+
+ private static final String CREATE_CATEGORIES_TABLE_SQL =
+ "CREATE TABLE IF NOT EXISTS " +
+ CATEGORIES_TABLE_NAME +
+ " (" +
+ CategoryModel.ID_COLUMN_NAME + " INTEGER PRIMARY KEY, " +
+ CategoryModel.NAME_COLUMN_NAME + " TEXT, " +
+ CategoryModel.SLUG_COLUMN_NAME + " TEXT, " +
+ CategoryModel.DESC_COLUMN_NAME + " TEXT, " +
+ CategoryModel.PARENT_ID_COLUMN_NAME + " INTEGER, " +
+ CategoryModel.POST_COUNT_COLUMN_NAME + " INTEGER" +
+ ");";
+
+ public static void createTable(SQLiteDatabase db) {
+ if (db != null) {
+ db.execSQL(SiteSettingsModel.CREATE_SETTINGS_TABLE_SQL);
+ db.execSQL(CREATE_CATEGORIES_TABLE_SQL);
+ }
+ }
+
+ public static Map getAllCategories() {
+ String sqlCommand = sqlSelectAllCategories() + ";";
+ Cursor cursor = WordPress.wpDB.getDatabase().rawQuery(sqlCommand, null);
+
+ if (cursor == null || !cursor.moveToFirst() || cursor.getCount() == 0) return null;
+
+ Map models = new HashMap<>();
+ for (int i = 0; i < cursor.getCount(); ++i) {
+ CategoryModel model = new CategoryModel();
+ model.deserializeFromDatabase(cursor);
+ models.put(model.id, model);
+ cursor.moveToNext();
+ }
+
+ return models;
+ }
+
+ public static Cursor getCategory(long id) {
+ if (id < 0) return null;
+
+ String sqlCommand = sqlSelectAllCategories() + sqlWhere(CategoryModel.ID_COLUMN_NAME, Long.toString(id)) + ";";
+ return WordPress.wpDB.getDatabase().rawQuery(sqlCommand, null);
+ }
+
+ public static Cursor getSettings(long id) {
+ if (id < 0) return null;
+
+ String sqlCommand = sqlSelectAllSettings() + sqlWhere(SiteSettingsModel.ID_COLUMN_NAME, Long.toString(id)) + ";";
+ return WordPress.wpDB.getDatabase().rawQuery(sqlCommand, null);
+ }
+
+ public static void saveCategory(CategoryModel category) {
+ if (category == null) return;
+
+ ContentValues values = category.serializeToDatabase();
+ category.isInLocalTable = WordPress.wpDB.getDatabase().insertWithOnConflict(
+ CATEGORIES_TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE) != -1;
+ }
+
+ public static void saveCategories(CategoryModel[] categories) {
+ if (categories == null) return;
+
+ for (CategoryModel category : categories) {
+ saveCategory(category);
+ }
+ }
+
+ public static void saveSettings(SiteSettingsModel settings) {
+ if (settings == null) return;
+
+ ContentValues values = settings.serializeToDatabase();
+ settings.isInLocalTable = WordPress.wpDB.getDatabase().insertWithOnConflict(
+ SiteSettingsModel.SETTINGS_TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE) != -1;
+
+ saveCategories(settings.categories);
+ }
+
+ private static String sqlSelectAllCategories() {
+ return "SELECT * FROM " + CATEGORIES_TABLE_NAME + " ";
+ }
+
+ private static String sqlSelectAllSettings() {
+ return "SELECT * FROM " + SiteSettingsModel.SETTINGS_TABLE_NAME + " ";
+ }
+
+ private static String sqlWhere(String variable, String value) {
+ return "WHERE " + variable + "=\"" + value + "\" ";
+ }
+}
diff --git a/WordPress/src/main/java/org/wordpress/android/models/CategoryModel.java b/WordPress/src/main/java/org/wordpress/android/models/CategoryModel.java
new file mode 100644
index 000000000000..77b08bfae2ab
--- /dev/null
+++ b/WordPress/src/main/java/org/wordpress/android/models/CategoryModel.java
@@ -0,0 +1,65 @@
+package org.wordpress.android.models;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+
+/**
+ * Represents WordPress post Category data and handles local database (de)serialization.
+ */
+public class CategoryModel {
+ // Categories table column names
+ public static final String ID_COLUMN_NAME = "ID";
+ public static final String NAME_COLUMN_NAME = "name";
+ public static final String SLUG_COLUMN_NAME = "slug";
+ public static final String DESC_COLUMN_NAME = "description";
+ public static final String PARENT_ID_COLUMN_NAME = "parent";
+ public static final String POST_COUNT_COLUMN_NAME = "post_count";
+
+ public int id;
+ public String name;
+ public String slug;
+ public String description;
+ public int parentId;
+ public int postCount;
+ public boolean isInLocalTable;
+
+ public CategoryModel() {
+ id = -1;
+ name = "";
+ slug = "";
+ description = "";
+ parentId = -1;
+ postCount = 0;
+ isInLocalTable = false;
+ }
+
+ /**
+ * Sets data from a local database {@link Cursor}.
+ */
+ public void deserializeFromDatabase(Cursor cursor) {
+ if (cursor == null) return;
+
+ id = cursor.getInt(cursor.getColumnIndex(ID_COLUMN_NAME));
+ name = cursor.getString(cursor.getColumnIndex(NAME_COLUMN_NAME));
+ slug = cursor.getString(cursor.getColumnIndex(SLUG_COLUMN_NAME));
+ description = cursor.getString(cursor.getColumnIndex(DESC_COLUMN_NAME));
+ parentId = cursor.getInt(cursor.getColumnIndex(PARENT_ID_COLUMN_NAME));
+ postCount = cursor.getInt(cursor.getColumnIndex(POST_COUNT_COLUMN_NAME));
+ isInLocalTable = true;
+ }
+
+ /**
+ * Creates the {@link ContentValues} object to store this category data in a local database.
+ */
+ public ContentValues serializeToDatabase() {
+ ContentValues values = new ContentValues();
+ values.put(ID_COLUMN_NAME, id);
+ values.put(NAME_COLUMN_NAME, name);
+ values.put(SLUG_COLUMN_NAME, slug);
+ values.put(DESC_COLUMN_NAME, description);
+ values.put(PARENT_ID_COLUMN_NAME, parentId);
+ values.put(POST_COUNT_COLUMN_NAME, postCount);
+
+ return values;
+ }
+}
diff --git a/WordPress/src/main/java/org/wordpress/android/models/SiteSettingsModel.java b/WordPress/src/main/java/org/wordpress/android/models/SiteSettingsModel.java
new file mode 100644
index 000000000000..e37db5973dd7
--- /dev/null
+++ b/WordPress/src/main/java/org/wordpress/android/models/SiteSettingsModel.java
@@ -0,0 +1,411 @@
+package org.wordpress.android.models;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Holds blog settings and provides methods to (de)serialize .com and self-hosted network calls.
+ */
+
+public class SiteSettingsModel {
+ public static final int RELATED_POSTS_ENABLED_FLAG = 0x1;
+ public static final int RELATED_POST_HEADER_FLAG = 0x2;
+ public static final int RELATED_POST_IMAGE_FLAG = 0x4;
+
+ // Settings table column names
+ public static final String ID_COLUMN_NAME = "id";
+ public static final String ADDRESS_COLUMN_NAME = "address";
+ public static final String USERNAME_COLUMN_NAME = "username";
+ public static final String PASSWORD_COLUMN_NAME = "password";
+ public static final String TITLE_COLUMN_NAME = "title";
+ public static final String TAGLINE_COLUMN_NAME = "tagline";
+ public static final String LANGUAGE_COLUMN_NAME = "language";
+ public static final String PRIVACY_COLUMN_NAME = "privacy";
+ public static final String LOCATION_COLUMN_NAME = "location";
+ public static final String DEF_CATEGORY_COLUMN_NAME = "defaultCategory";
+ public static final String DEF_POST_FORMAT_COLUMN_NAME = "defaultPostFormat";
+ public static final String CATEGORIES_COLUMN_NAME = "categories";
+ public static final String POST_FORMATS_COLUMN_NAME = "postFormats";
+ public static final String CREDS_VERIFIED_COLUMN_NAME = "credsVerified";
+ public static final String RELATED_POSTS_COLUMN_NAME = "relatedPosts";
+ public static final String ALLOW_COMMENTS_COLUMN_NAME = "allowComments";
+ public static final String SEND_PINGBACKS_COLUMN_NAME = "sendPingbacks";
+ public static final String RECEIVE_PINGBACKS_COLUMN_NAME = "receivePingbacks";
+ public static final String SHOULD_CLOSE_AFTER_COLUMN_NAME = "shouldCloseAfter";
+ public static final String CLOSE_AFTER_COLUMN_NAME = "closeAfter";
+ public static final String SORT_BY_COLUMN_NAME = "sortBy";
+ public static final String SHOULD_THREAD_COLUMN_NAME = "shouldThread";
+ public static final String THREADING_COLUMN_NAME = "threading";
+ public static final String SHOULD_PAGE_COLUMN_NAME = "shouldPage";
+ public static final String PAGING_COLUMN_NAME = "paging";
+ public static final String MANUAL_APPROVAL_COLUMN_NAME = "manualApproval";
+ public static final String IDENTITY_REQUIRED_COLUMN_NAME = "identityRequired";
+ public static final String USER_ACCOUNT_REQUIRED_COLUMN_NAME = "userAccountRequired";
+ public static final String WHITELIST_COLUMN_NAME = "whitelist";
+ public static final String MODERATION_KEYS_COLUMN_NAME = "moderationKeys";
+ public static final String BLACKLIST_KEYS_COLUMN_NAME = "blacklistKeys";
+
+ public static final String SETTINGS_TABLE_NAME = "site_settings";
+ public static final String CREATE_SETTINGS_TABLE_SQL =
+ "CREATE TABLE IF NOT EXISTS " +
+ SETTINGS_TABLE_NAME +
+ " (" +
+ ID_COLUMN_NAME + " INTEGER PRIMARY KEY, " +
+ ADDRESS_COLUMN_NAME + " TEXT, " +
+ USERNAME_COLUMN_NAME + " TEXT, " +
+ PASSWORD_COLUMN_NAME + " TEXT, " +
+ TITLE_COLUMN_NAME + " TEXT, " +
+ TAGLINE_COLUMN_NAME + " TEXT, " +
+ LANGUAGE_COLUMN_NAME + " INTEGER, " +
+ PRIVACY_COLUMN_NAME + " INTEGER, " +
+ LOCATION_COLUMN_NAME + " BOOLEAN, " +
+ DEF_CATEGORY_COLUMN_NAME + " TEXT, " +
+ DEF_POST_FORMAT_COLUMN_NAME + " TEXT, " +
+ CATEGORIES_COLUMN_NAME + " TEXT, " +
+ POST_FORMATS_COLUMN_NAME + " TEXT, " +
+ CREDS_VERIFIED_COLUMN_NAME + " BOOLEAN, " +
+ RELATED_POSTS_COLUMN_NAME + " INTEGER, " +
+ ALLOW_COMMENTS_COLUMN_NAME + " BOOLEAN, " +
+ SEND_PINGBACKS_COLUMN_NAME + " BOOLEAN, " +
+ RECEIVE_PINGBACKS_COLUMN_NAME + " BOOLEAN, " +
+ SHOULD_CLOSE_AFTER_COLUMN_NAME + " BOOLEAN, " +
+ CLOSE_AFTER_COLUMN_NAME + " INTEGER, " +
+ SORT_BY_COLUMN_NAME + " INTEGER, " +
+ SHOULD_THREAD_COLUMN_NAME + " BOOLEAN, " +
+ THREADING_COLUMN_NAME + " INTEGER, " +
+ SHOULD_PAGE_COLUMN_NAME + " BOOLEAN, " +
+ PAGING_COLUMN_NAME + " INTEGER, " +
+ MANUAL_APPROVAL_COLUMN_NAME + " BOOLEAN, " +
+ IDENTITY_REQUIRED_COLUMN_NAME + " BOOLEAN, " +
+ USER_ACCOUNT_REQUIRED_COLUMN_NAME + " BOOLEAN, " +
+ WHITELIST_COLUMN_NAME + " BOOLEAN, " +
+ MODERATION_KEYS_COLUMN_NAME + " TEXT, " +
+ BLACKLIST_KEYS_COLUMN_NAME + " TEXT" +
+ ");";
+
+ public boolean isInLocalTable;
+ public boolean hasVerifiedCredentials;
+ public long localTableId;
+ public String address;
+ public String username;
+ public String password;
+ public String title;
+ public String tagline;
+ public String language;
+ public int languageId;
+ public int privacy;
+ public boolean location;
+ public int defaultCategory;
+ public CategoryModel[] categories;
+ public String defaultPostFormat;
+ public Map postFormats;
+ public String[] postFormatKeys;
+ public boolean showRelatedPosts;
+ public boolean showRelatedPostHeader;
+ public boolean showRelatedPostImages;
+ public boolean allowComments;
+ public boolean sendPingbacks;
+ public boolean receivePingbacks;
+ public boolean shouldCloseAfter;
+ public int closeCommentAfter;
+ public int sortCommentsBy;
+ public boolean shouldThreadComments;
+ public int threadingLevels;
+ public boolean shouldPageComments;
+ public int commentsPerPage;
+ public boolean commentApprovalRequired;
+ public boolean commentsRequireIdentity;
+ public boolean commentsRequireUserAccount;
+ public boolean commentAutoApprovalKnownUsers;
+ public int maxLinks;
+ public List holdForModeration;
+ public List blacklist;
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof SiteSettingsModel)) return false;
+ SiteSettingsModel otherModel = (SiteSettingsModel) other;
+
+ return localTableId == otherModel.localTableId &&
+ address.equals(otherModel.address) &&
+ username.equals(otherModel.username) &&
+ password.equals(otherModel.password) &&
+ title.equals(otherModel.title) &&
+ tagline.equals(otherModel.tagline) &&
+ languageId == otherModel.languageId &&
+ privacy == otherModel.privacy &&
+ location == otherModel.location &&
+ defaultPostFormat.equals(otherModel.defaultPostFormat) &&
+ defaultCategory == otherModel.defaultCategory &&
+ showRelatedPosts == otherModel.showRelatedPosts &&
+ showRelatedPostHeader == otherModel.showRelatedPostHeader &&
+ showRelatedPostImages == otherModel.showRelatedPostImages &&
+ allowComments == otherModel.allowComments &&
+ sendPingbacks == otherModel.sendPingbacks &&
+ receivePingbacks == otherModel.receivePingbacks &&
+ closeCommentAfter == otherModel.closeCommentAfter &&
+ sortCommentsBy == otherModel.sortCommentsBy &&
+ threadingLevels == otherModel.threadingLevels &&
+ commentsPerPage == otherModel.commentsPerPage &&
+ commentApprovalRequired == otherModel.commentApprovalRequired &&
+ commentsRequireIdentity == otherModel.commentsRequireIdentity &&
+ commentsRequireUserAccount == otherModel.commentsRequireUserAccount &&
+ commentAutoApprovalKnownUsers == otherModel.commentAutoApprovalKnownUsers &&
+ maxLinks == otherModel.maxLinks &&
+ holdForModeration != null && holdForModeration.equals(otherModel.holdForModeration) &&
+ blacklist != null && blacklist.equals(otherModel.blacklist);
+ }
+
+ /**
+ * Copies data from another {@link SiteSettingsModel}.
+ */
+ public void copyFrom(SiteSettingsModel other) {
+ if (other == null) return;
+
+ isInLocalTable = other.isInLocalTable;
+ hasVerifiedCredentials = other.hasVerifiedCredentials;
+ localTableId = other.localTableId;
+ address = other.address;
+ username = other.username;
+ password = other.password;
+ title = other.title;
+ tagline = other.tagline;
+ language = other.language;
+ languageId = other.languageId;
+ privacy = other.privacy;
+ location = other.location;
+ defaultCategory = other.defaultCategory;
+ categories = other.categories;
+ defaultPostFormat = other.defaultPostFormat;
+ postFormats = other.postFormats;
+ showRelatedPosts = other.showRelatedPosts;
+ showRelatedPostHeader = other.showRelatedPostHeader;
+ showRelatedPostImages = other.showRelatedPostImages;
+ allowComments = other.allowComments;
+ sendPingbacks = other.sendPingbacks;
+ receivePingbacks = other.receivePingbacks;
+ shouldCloseAfter = other.shouldCloseAfter;
+ closeCommentAfter = other.closeCommentAfter;
+ sortCommentsBy = other.sortCommentsBy;
+ shouldThreadComments = other.shouldThreadComments;
+ threadingLevels = other.threadingLevels;
+ shouldPageComments = other.shouldPageComments;
+ commentsPerPage = other.commentsPerPage;
+ commentApprovalRequired = other.commentApprovalRequired;
+ commentsRequireIdentity = other.commentsRequireIdentity;
+ commentsRequireUserAccount = other.commentsRequireUserAccount;
+ commentAutoApprovalKnownUsers = other.commentAutoApprovalKnownUsers;
+ maxLinks = other.maxLinks;
+ holdForModeration = new ArrayList<>(other.holdForModeration);
+ blacklist = new ArrayList<>(other.blacklist);
+ }
+
+ /**
+ * Sets values from a local database {@link Cursor}.
+ */
+ public void deserializeOptionsDatabaseCursor(Cursor cursor, Map models) {
+ if (cursor == null || !cursor.moveToFirst() || cursor.getCount() == 0) return;
+
+ localTableId = getIntFromCursor(cursor, ID_COLUMN_NAME);
+ address = getStringFromCursor(cursor, ADDRESS_COLUMN_NAME);
+ username = getStringFromCursor(cursor, USERNAME_COLUMN_NAME);
+ password = getStringFromCursor(cursor, PASSWORD_COLUMN_NAME);
+ title = getStringFromCursor(cursor, TITLE_COLUMN_NAME);
+ tagline = getStringFromCursor(cursor, TAGLINE_COLUMN_NAME);
+ languageId = getIntFromCursor(cursor, LANGUAGE_COLUMN_NAME);
+ privacy = getIntFromCursor(cursor, PRIVACY_COLUMN_NAME);
+ defaultCategory = getIntFromCursor(cursor, DEF_CATEGORY_COLUMN_NAME);
+ defaultPostFormat = getStringFromCursor(cursor, DEF_POST_FORMAT_COLUMN_NAME);
+ location = getBooleanFromCursor(cursor, LOCATION_COLUMN_NAME);
+ hasVerifiedCredentials = getBooleanFromCursor(cursor, CREDS_VERIFIED_COLUMN_NAME);
+ allowComments = getBooleanFromCursor(cursor, ALLOW_COMMENTS_COLUMN_NAME);
+ sendPingbacks = getBooleanFromCursor(cursor, SEND_PINGBACKS_COLUMN_NAME);
+ receivePingbacks = getBooleanFromCursor(cursor, RECEIVE_PINGBACKS_COLUMN_NAME);
+ shouldCloseAfter = getBooleanFromCursor(cursor, SHOULD_CLOSE_AFTER_COLUMN_NAME);
+ closeCommentAfter = getIntFromCursor(cursor, CLOSE_AFTER_COLUMN_NAME);
+ sortCommentsBy = getIntFromCursor(cursor, SORT_BY_COLUMN_NAME);
+ shouldThreadComments = getBooleanFromCursor(cursor, SHOULD_THREAD_COLUMN_NAME);
+ threadingLevels = getIntFromCursor(cursor, THREADING_COLUMN_NAME);
+ shouldPageComments = getBooleanFromCursor(cursor, SHOULD_PAGE_COLUMN_NAME);
+ commentsPerPage = getIntFromCursor(cursor, PAGING_COLUMN_NAME);
+ commentApprovalRequired = getBooleanFromCursor(cursor, MANUAL_APPROVAL_COLUMN_NAME);
+ commentsRequireIdentity = getBooleanFromCursor(cursor, IDENTITY_REQUIRED_COLUMN_NAME);
+ commentsRequireUserAccount = getBooleanFromCursor(cursor, USER_ACCOUNT_REQUIRED_COLUMN_NAME);
+ commentAutoApprovalKnownUsers = getBooleanFromCursor(cursor, WHITELIST_COLUMN_NAME);
+
+ String moderationKeys = getStringFromCursor(cursor, MODERATION_KEYS_COLUMN_NAME);
+ String blacklistKeys = getStringFromCursor(cursor, BLACKLIST_KEYS_COLUMN_NAME);
+ holdForModeration = new ArrayList<>();
+ blacklist = new ArrayList<>();
+ Collections.addAll(holdForModeration, moderationKeys.split("\n"));
+ Collections.addAll(blacklist, blacklistKeys.split("\n"));
+
+ setRelatedPostsFlags(Math.max(0, getIntFromCursor(cursor, RELATED_POSTS_COLUMN_NAME)));
+
+ String cachedCategories = getStringFromCursor(cursor, CATEGORIES_COLUMN_NAME);
+ String cachedFormats = getStringFromCursor(cursor, POST_FORMATS_COLUMN_NAME);
+ if (models != null && !TextUtils.isEmpty(cachedCategories)) {
+ String[] split = cachedCategories.split(",");
+ categories = new CategoryModel[split.length];
+ for (int i = 0; i < split.length; ++i) {
+ int catId = Integer.parseInt(split[i]);
+ categories[i] = models.get(catId);
+ }
+ }
+ if (!TextUtils.isEmpty(cachedFormats)) {
+ String[] split = cachedFormats.split(";");
+ postFormats = new HashMap<>();
+ for (String format : split) {
+ String[] kvp = format.split(",");
+ postFormats.put(kvp[0], kvp[1]);
+ }
+ }
+
+ int cachedRelatedPosts = getIntFromCursor(cursor, RELATED_POSTS_COLUMN_NAME);
+ if (cachedRelatedPosts != -1) {
+ setRelatedPostsFlags(cachedRelatedPosts);
+ }
+
+ isInLocalTable = true;
+ }
+
+ /**
+ * Creates the {@link ContentValues} object to store this category data in a local database.
+ */
+ public ContentValues serializeToDatabase() {
+ ContentValues values = new ContentValues();
+ values.put(ID_COLUMN_NAME, localTableId);
+ values.put(ADDRESS_COLUMN_NAME, address);
+ values.put(USERNAME_COLUMN_NAME, username);
+ values.put(PASSWORD_COLUMN_NAME, password);
+ values.put(TITLE_COLUMN_NAME, title);
+ values.put(TAGLINE_COLUMN_NAME, tagline);
+ values.put(PRIVACY_COLUMN_NAME, privacy);
+ values.put(LANGUAGE_COLUMN_NAME, languageId);
+ values.put(LOCATION_COLUMN_NAME, location);
+ values.put(DEF_CATEGORY_COLUMN_NAME, defaultCategory);
+ values.put(CATEGORIES_COLUMN_NAME, categoryIdList(categories));
+ values.put(DEF_POST_FORMAT_COLUMN_NAME, defaultPostFormat);
+ values.put(POST_FORMATS_COLUMN_NAME, postFormatList(postFormats));
+ values.put(CREDS_VERIFIED_COLUMN_NAME, hasVerifiedCredentials);
+ values.put(RELATED_POSTS_COLUMN_NAME, getRelatedPostsFlags());
+ values.put(ALLOW_COMMENTS_COLUMN_NAME, allowComments);
+ values.put(SEND_PINGBACKS_COLUMN_NAME, sendPingbacks);
+ values.put(RECEIVE_PINGBACKS_COLUMN_NAME, receivePingbacks);
+ values.put(SHOULD_CLOSE_AFTER_COLUMN_NAME, shouldCloseAfter);
+ values.put(CLOSE_AFTER_COLUMN_NAME, closeCommentAfter);
+ values.put(SORT_BY_COLUMN_NAME, sortCommentsBy);
+ values.put(SHOULD_THREAD_COLUMN_NAME, shouldThreadComments);
+ values.put(THREADING_COLUMN_NAME, threadingLevels);
+ values.put(SHOULD_PAGE_COLUMN_NAME, shouldPageComments);
+ values.put(PAGING_COLUMN_NAME, commentsPerPage);
+ values.put(MANUAL_APPROVAL_COLUMN_NAME, commentApprovalRequired);
+ values.put(IDENTITY_REQUIRED_COLUMN_NAME, commentsRequireIdentity);
+ values.put(USER_ACCOUNT_REQUIRED_COLUMN_NAME, commentsRequireUserAccount);
+ values.put(WHITELIST_COLUMN_NAME, commentAutoApprovalKnownUsers);
+
+ String moderationKeys = "";
+ if (holdForModeration != null) {
+ for (String key : holdForModeration) {
+ moderationKeys += key + "\n";
+ }
+ }
+ String blacklistKeys = "";
+ if (blacklist != null) {
+ for (String key : blacklist) {
+ blacklistKeys += key + "\n";
+ }
+ }
+ values.put(MODERATION_KEYS_COLUMN_NAME, moderationKeys);
+ values.put(BLACKLIST_KEYS_COLUMN_NAME, blacklistKeys);
+
+ return values;
+ }
+
+ public int getRelatedPostsFlags() {
+ int flags = 0;
+
+ if (showRelatedPosts) flags |= RELATED_POSTS_ENABLED_FLAG;
+ if (showRelatedPostHeader) flags |= RELATED_POST_HEADER_FLAG;
+ if (showRelatedPostImages) flags |= RELATED_POST_IMAGE_FLAG;
+
+ return flags;
+ }
+
+ public void setRelatedPostsFlags(int flags) {
+ showRelatedPosts = (flags & RELATED_POSTS_ENABLED_FLAG) > 0;
+ showRelatedPostHeader = (flags & RELATED_POST_HEADER_FLAG) > 0;
+ showRelatedPostImages = (flags & RELATED_POST_IMAGE_FLAG) > 0;
+ }
+
+ /**
+ * Used to serialize post formats to store in a local database.
+ *
+ * @param formats
+ * map of post formats where the key is the format ID and the value is the format name
+ * @return
+ * a String of semi-colon separated KVP's of Post Formats; Post Format ID -> Post Format Name
+ */
+ private static String postFormatList(Map formats) {
+ if (formats == null || formats.size() == 0) return "";
+
+ StringBuilder builder = new StringBuilder();
+ for (String key : formats.keySet()) {
+ builder.append(key).append(",").append(formats.get(key)).append(";");
+ }
+ builder.setLength(builder.length() - 1);
+
+ return builder.toString();
+ }
+
+ /**
+ * Used to serialize categories to store in a local database.
+ *
+ * @param elements
+ * {@link CategoryModel} array to create String ID list from
+ * @return
+ * a String of comma-separated integer Category ID's
+ */
+ private static String categoryIdList(CategoryModel[] elements) {
+ if (elements == null || elements.length == 0) return "";
+
+ StringBuilder builder = new StringBuilder();
+ for (CategoryModel element : elements) {
+ builder.append(String.valueOf(element.id)).append(",");
+ }
+ builder.setLength(builder.length() - 1);
+
+ return builder.toString();
+ }
+
+ /**
+ * Helper method to get an integer value from a given column in a Cursor.
+ */
+ private int getIntFromCursor(Cursor cursor, String columnName) {
+ int columnIndex = cursor.getColumnIndex(columnName);
+ return columnIndex != -1 ? cursor.getInt(columnIndex) : -1;
+ }
+
+ /**
+ * Helper method to get a String value from a given column in a Cursor.
+ */
+ private String getStringFromCursor(Cursor cursor, String columnName) {
+ int columnIndex = cursor.getColumnIndex(columnName);
+ return columnIndex != -1 ? cursor.getString(columnIndex) : "";
+ }
+
+ /**
+ * Helper method to get a boolean value (stored as an int) from a given column in a Cursor.
+ */
+ private boolean getBooleanFromCursor(Cursor cursor, String columnName) {
+ int columnIndex = cursor.getColumnIndex(columnName);
+ return columnIndex != -1 && cursor.getInt(columnIndex) != 0;
+ }
+}
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java
index aa59a625250c..09a0cf0c3b94 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/ActivityLauncher.java
@@ -28,6 +28,7 @@
import org.wordpress.android.ui.posts.PostsListActivity;
import org.wordpress.android.ui.prefs.BlogPreferencesActivity;
import org.wordpress.android.ui.prefs.SettingsActivity;
+import org.wordpress.android.ui.prefs.SiteSettingsInterface;
import org.wordpress.android.ui.prefs.notifications.NotificationsSettingsActivity;
import org.wordpress.android.ui.stats.StatsActivity;
import org.wordpress.android.ui.stats.StatsConstants;
@@ -139,8 +140,10 @@ public static void viewPostPreviewForResult(Activity activity, Post post, boolea
public static void addNewBlogPostOrPageForResult(Activity context, Blog blog, boolean isPage) {
if (blog == null) return;
- // Create a new post object
+ // Create a new post object and assign default settings
Post newPost = new Post(blog.getLocalTableBlogId(), isPage);
+ newPost.setCategories("[" + SiteSettingsInterface.getDefaultCategory(context) +"]");
+ newPost.setPostFormat(SiteSettingsInterface.getDefaultFormat(context));
WordPress.wpDB.savePost(newPost);
Intent intent = new Intent(context, EditPostActivity.class);
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/WPNumberPicker.java b/WordPress/src/main/java/org/wordpress/android/ui/WPNumberPicker.java
new file mode 100644
index 000000000000..404c4aa67255
--- /dev/null
+++ b/WordPress/src/main/java/org/wordpress/android/ui/WPNumberPicker.java
@@ -0,0 +1,262 @@
+package org.wordpress.android.ui;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.NumberPicker;
+import android.widget.TextView;
+
+import org.wordpress.android.R;
+import org.wordpress.android.util.WPPrefUtils;
+
+import java.lang.reflect.Field;
+
+public class WPNumberPicker extends NumberPicker {
+ private static final String DIVIDER_FIELD = "mSelectionDivider";
+ private static final String INPUT_FIELD = "mInputText";
+ private static final String INDICES_FIELD = "mSelectorIndices";
+ private static final String CUR_OFFSET_FIELD = "mCurrentScrollOffset";
+ private static final String SELECTOR_HEIGHT_FIELD = "mSelectorElementHeight";
+ private static final String INITIAL_OFFSET_FIELD = "mInitialScrollOffset";
+ private static final String CURRENT_OFFSET_FIELD = "mCurrentScrollOffset";
+ private static final String PAINT_FIELD = "mSelectorWheelPaint";
+
+ private static final int DISPLAY_COUNT = 5;
+ private static final int MIDDLE_INDEX = 2;
+
+ private Field mOffsetField;
+ private Field mSelectorHeight;
+ private Field mSelectorIndices;
+ private Field mInitialOffset;
+ private Field mCurrentOffset;
+
+ private EditText mInputView;
+ private Formatter mFormatter;
+ private Paint mPaint;
+ private int[] mDisplayValues;
+
+ public WPNumberPicker(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mDisplayValues = new int[DISPLAY_COUNT];
+ getFieldsViaReflection();
+ }
+
+ @Override
+ public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
+ super.addView(child, index, params);
+ if (child instanceof TextView) {
+ WPPrefUtils.layoutAsNumberPickerPeek((TextView) child);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ updateIntitialOffset();
+ setVerticalFadingEdgeEnabled(false);
+ setHorizontalFadingEdgeEnabled(false);
+ mInputView.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void setValue(int value) {
+ if (value < getMinValue()) value = getMinValue();
+ if (value > getMaxValue()) value = getMaxValue();
+ super.setValue(value);
+ EditText view = (EditText) getChildAt(0);
+ WPPrefUtils.layoutAsNumberPickerSelected(view);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int[] selectorIndices = getIndices();
+ setIndices(new int[0]);
+ setIndices(selectorIndices);
+
+ // Draw the middle number with a different font
+ setDisplayValues();
+ float elementHeight = getSelectorElementHeight();
+ float x = ((getRight() - getLeft()) / 2.0f);
+ float y = getScrollOffset();
+ Paint paint = mInputView.getPaint();
+ paint.setTextAlign(Paint.Align.CENTER);
+ //noinspection deprecation
+ paint.setColor(getResources().getColor(R.color.blue_medium));
+ int alpha = isEnabled() ? 255 : 96;
+ paint.setAlpha(alpha);
+ mPaint.setAlpha(alpha);
+
+ int offset = getResources().getDimensionPixelSize(R.dimen.margin_medium);
+ // Draw the visible values
+ for (int i = 0; i < DISPLAY_COUNT; ++i) {
+ String scrollSelectorValue;
+ if (mFormatter != null) {
+ scrollSelectorValue = mFormatter.format(mDisplayValues[i]);
+ } else {
+ scrollSelectorValue = String.valueOf(mDisplayValues[i]);
+ }
+ if (i == MIDDLE_INDEX) {
+ canvas.drawText(scrollSelectorValue, x, y - ((paint.descent() + paint.ascent()) / 2) - offset, paint);
+ } else {
+ canvas.drawText(scrollSelectorValue, x, y - ((mPaint.descent() + mPaint.ascent()) / 2) - offset, mPaint);
+ }
+ y += elementHeight;
+ }
+ }
+
+ @Override
+ public void setFormatter(Formatter formatter) {
+ super.setFormatter(formatter);
+ mFormatter = formatter;
+ }
+
+ private void setDisplayValues() {
+ int value = getValue();
+ for (int i = 0; i < DISPLAY_COUNT; ++i) {
+ mDisplayValues[i] = value - MIDDLE_INDEX + i;
+ if (mDisplayValues[i] < getMinValue()) {
+ mDisplayValues[i] = getMaxValue() + (mDisplayValues[i] + 1 - getMinValue());
+ } else if (mDisplayValues[i] > getMaxValue()) {
+ mDisplayValues[i] = getMinValue() + (mDisplayValues[i] - getMaxValue() - 1);
+ }
+ }
+ }
+
+ private void setIndices(int[] indices) {
+ if (mSelectorIndices != null) {
+ try {
+ mSelectorIndices.set(this, indices);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private int[] getIndices() {
+ if (mSelectorIndices != null) {
+ try {
+ return (int[]) mSelectorIndices.get(this);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return null;
+ }
+
+ private int getScrollOffset() {
+ if (mOffsetField != null) {
+ try {
+ return (Integer) mOffsetField.get(this);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return 0;
+ }
+
+ private int getSelectorElementHeight() {
+ if (mSelectorHeight != null) {
+ try {
+ return (Integer) mSelectorHeight.get(this);
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return 0;
+ }
+
+ private void updateIntitialOffset() {
+ if (mInitialOffset != null) {
+ try {
+ int offset = (Integer) mInitialOffset.get(this) - getSelectorElementHeight();
+ mInitialOffset.set(this, offset);
+ // Only do this once
+ mInitialOffset = null;
+
+ if (mCurrentOffset != null) {
+ mCurrentOffset.set(this, offset);
+ }
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * From https://www.snip2code.com/Snippet/67740/NumberPicker-with-transparent-selection-
+ */
+ private void removeDividers(Class> clazz) {
+ Field selectionDivider = getFieldAndSetAccessible(clazz, DIVIDER_FIELD);
+ if (selectionDivider != null) {
+ try {
+ selectionDivider.set(this, null);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void getTextPaint(Class> clazz) {
+ Field paint = getFieldAndSetAccessible(clazz, PAINT_FIELD);
+ if (paint != null) {
+ try {
+ mPaint = (Paint) paint.get(this);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void getInputField(Class> clazz) {
+ Field inputField = getFieldAndSetAccessible(clazz, INPUT_FIELD);
+ if (inputField != null) {
+ try {
+ mInputView = ((EditText) inputField.get(this));
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Gets a class field using reflection and makes it accessible.
+ */
+ private Field getFieldAndSetAccessible(Class> clazz, String fieldName) {
+ Field field = null;
+ try {
+ field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ }
+
+ return field;
+ }
+
+ private void getFieldsViaReflection() {
+ Class> numberPickerClass = null;
+ try {
+ numberPickerClass = Class.forName(NumberPicker.class.getName());
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ if (numberPickerClass == null) return;
+
+ mSelectorHeight = getFieldAndSetAccessible(numberPickerClass, SELECTOR_HEIGHT_FIELD);
+ mOffsetField = getFieldAndSetAccessible(numberPickerClass, CUR_OFFSET_FIELD);
+ mSelectorIndices = getFieldAndSetAccessible(numberPickerClass, INDICES_FIELD);
+ mInitialOffset = getFieldAndSetAccessible(numberPickerClass, INITIAL_OFFSET_FIELD);
+ mCurrentOffset = getFieldAndSetAccessible(numberPickerClass, CURRENT_OFFSET_FIELD);
+
+ getTextPaint(numberPickerClass);
+ getInputField(numberPickerClass);
+ removeDividers(numberPickerClass);
+ setIndices(new int[DISPLAY_COUNT]);
+ }
+}
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/AbstractFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/AbstractFragment.java
index 2fe69bb94c59..a1ffdca60af8 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/AbstractFragment.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/AbstractFragment.java
@@ -10,7 +10,6 @@
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageView;
@@ -25,6 +24,7 @@
import org.wordpress.android.networking.RestClientUtils;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.AppLog.T;
+import org.wordpress.android.util.WPActivityUtils;
/**
* A fragment representing a single step in a wizard. The fragment shows a dummy title indicating
@@ -75,12 +75,8 @@ protected boolean onDoneEvent(int actionId, KeyEvent event) {
}
// hide keyboard before calling the done action
- InputMethodManager inputManager = (InputMethodManager) getActivity().getSystemService(
- Context.INPUT_METHOD_SERVICE);
View view = getActivity().getCurrentFocus();
- if (view != null) {
- inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
- }
+ if (view != null) WPActivityUtils.hideKeyboard(view);
// call child action
onDoneAction();
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/main/MySiteFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/main/MySiteFragment.java
index 03fc2ffd80d6..a8d65a84d0d3 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/main/MySiteFragment.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/main/MySiteFragment.java
@@ -48,6 +48,8 @@ public class MySiteFragment extends Fragment
private WPTextView mBlogSubtitleTextView;
private LinearLayout mLookAndFeelHeader;
private RelativeLayout mThemesContainer;
+ private View mConfigurationHeader;
+ private View mSettingsView;
private View mFabView;
private LinearLayout mNoSiteView;
private ScrollView mScrollView;
@@ -116,6 +118,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
mBlogSubtitleTextView = (WPTextView) rootView.findViewById(R.id.my_site_subtitle_label);
mLookAndFeelHeader = (LinearLayout) rootView.findViewById(R.id.my_site_look_and_feel_header);
mThemesContainer = (RelativeLayout) rootView.findViewById(R.id.row_themes);
+ mConfigurationHeader = rootView.findViewById(R.id.row_configuration);
+ mSettingsView = rootView.findViewById(R.id.row_settings);
mScrollView = (ScrollView) rootView.findViewById(R.id.scroll_view);
mNoSiteView = (LinearLayout) rootView.findViewById(R.id.no_site_view);
mNoSiteDrakeImageView = (ImageView) rootView.findViewById(R.id.my_site_no_site_view_drake);
@@ -186,7 +190,7 @@ public void onClick(View v) {
}
});
- rootView.findViewById(R.id.row_settings).setOnClickListener(new View.OnClickListener() {
+ mSettingsView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ActivityLauncher.viewBlogSettingsForResult(getActivity(), mBlog);
@@ -304,6 +308,11 @@ private void refreshBlogDetails() {
mLookAndFeelHeader.setVisibility(themesVisibility);
mThemesContainer.setVisibility(themesVisibility);
+ // show settings for all self-hosted to expose Delete Site
+ int settingsVisibility = mBlog.isAdmin() || !mBlog.isDotcomFlag() ? View.VISIBLE : View.GONE;
+ mConfigurationHeader.setVisibility(settingsVisibility);
+ mSettingsView.setVisibility(settingsVisibility);
+
mBlavatarImageView.setImageUrl(GravatarUtils.blavatarFromUrl(mBlog.getUrl(), mBlavatarSz), WPNetworkImageView.ImageType.BLAVATAR);
String blogName = StringUtils.unescapeHTML(mBlog.getBlogName());
@@ -346,4 +355,14 @@ public void onStart() {
public void onEventMainThread(CoreEvents.MainViewPagerScrolled event) {
mFabView.setTranslationY(mFabTargetYTranslation * event.mXOffset);
}
+
+ @SuppressWarnings("unused")
+ public void onEventMainThread(CoreEvents.BlogListChanged event) {
+ if (!isAdded() || (mBlog = WordPress.getBlog(mBlog.getLocalTableBlogId())) == null) return;
+
+ // Update view if blog has a new name
+ if (!mBlogTitleTextView.getText().equals(mBlog.getBlogName())) {
+ mBlogTitleTextView.setText(mBlog.getBlogName());
+ }
+ }
}
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/main/SitePickerActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/main/SitePickerActivity.java
index b7f76ae5416e..c40ab4356230 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/main/SitePickerActivity.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/main/SitePickerActivity.java
@@ -35,6 +35,7 @@
import org.wordpress.android.ui.stats.datasets.StatsTable;
import org.wordpress.android.util.CoreEvents;
import org.wordpress.android.util.ToastUtils;
+import org.wordpress.android.util.WPActivityUtils;
import org.xmlrpc.android.ApiHelper;
import de.greenrobot.event.EventBus;
@@ -318,8 +319,7 @@ private void disableSearchMode() {
private void hideSoftKeyboard() {
if (!hasHardwareKeyboard()) {
- InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- inputMethodManager.hideSoftInputFromWindow(mSearchView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+ WPActivityUtils.hideKeyboard(mSearchView);
}
}
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java
index e79628baa9cb..9fd6f4c3274c 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java
@@ -33,8 +33,8 @@
import org.wordpress.android.ui.notifications.utils.NotificationsUtils;
import org.wordpress.android.ui.notifications.utils.SimperiumUtils;
import org.wordpress.android.ui.prefs.AppPrefs;
-import org.wordpress.android.ui.prefs.BlogPreferencesActivity;
import org.wordpress.android.ui.prefs.SettingsFragment;
+import org.wordpress.android.ui.prefs.SiteSettingsFragment;
import org.wordpress.android.ui.reader.ReaderPostListFragment;
import org.wordpress.android.util.AnalyticsUtils;
import org.wordpress.android.util.AniUtils;
@@ -385,7 +385,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
break;
case RequestCodes.BLOG_SETTINGS:
- if (resultCode == BlogPreferencesActivity.RESULT_BLOG_REMOVED) {
+ if (resultCode == SiteSettingsFragment.RESULT_BLOG_REMOVED) {
// user removed the current (self-hosted) blog from blog settings
if (!AccountHelper.isSignedIn()) {
ActivityLauncher.showSignInForResult(this);
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java
index 06e456ab6828..d3a3487f80dc 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.java
@@ -60,6 +60,7 @@
import org.wordpress.android.ui.media.services.MediaEvents;
import org.wordpress.android.ui.media.services.MediaUploadService;
import org.wordpress.android.ui.posts.services.PostUploadService;
+import org.wordpress.android.ui.prefs.SiteSettingsInterface;
import org.wordpress.android.ui.suggestion.adapters.TagSuggestionAdapter;
import org.wordpress.android.ui.suggestion.util.SuggestionServiceConnectionManager;
import org.wordpress.android.ui.suggestion.util.SuggestionUtils;
@@ -210,6 +211,8 @@ protected void onCreate(Bundle savedInstanceState) {
// Create a new post for share intents and QuickPress
mPost = new Post(WordPress.getCurrentLocalTableBlogId(), false);
+ mPost.setCategories("[" + SiteSettingsInterface.getDefaultCategory(this) +"]");
+ mPost.setPostFormat(SiteSettingsInterface.getDefaultFormat(this));
WordPress.wpDB.savePost(mPost);
mIsNewPost = true;
} else if (extras != null) {
@@ -691,6 +694,10 @@ public void onBackPressed() {
}
}
+ public boolean isNewPost() {
+ return mIsNewPost;
+ }
+
private boolean hasEmptyContentFields() {
return TextUtils.isEmpty(mEditorFragment.getTitle()) && TextUtils.isEmpty(mEditorFragment.getContent());
}
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostSettingsFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostSettingsFragment.java
index e2c0908a5b86..463e4dd16a29 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostSettingsFragment.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostSettingsFragment.java
@@ -2,6 +2,7 @@
import android.app.AlertDialog;
import android.app.Fragment;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Address;
@@ -45,6 +46,7 @@
import org.wordpress.android.models.PostLocation;
import org.wordpress.android.models.PostStatus;
import org.wordpress.android.ui.RequestCodes;
+import org.wordpress.android.ui.prefs.SiteSettingsInterface;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.AppLog.T;
import org.wordpress.android.util.EditTextUtils;
@@ -188,7 +190,7 @@ public boolean onTouch(View view, MotionEvent motionEvent) {
initSettingsFields();
populateSelectedCategories();
- initLocation();
+ initLocation(mRootView);
return mRootView;
}
@@ -612,12 +614,11 @@ public void afterTextChanged(Editable s) {
* called when activity is created to initialize the location provider, show views related
* to location if enabled for this blog, and retrieve the current location if necessary
*/
- public void initLocation() {
- if (!mPost.supportsLocation()) {
- return;
- }
+ private void initLocation(ViewGroup rootView) {
+ if (!mPost.supportsLocation()) return;
+
// show the location views if a provider was found and this is a post on a blog that has location enabled
- View locationRootView = ((ViewStub) mRootView.findViewById(R.id.stub_post_location_settings)).inflate();
+ View locationRootView = ((ViewStub) rootView.findViewById(R.id.stub_post_location_settings)).inflate();
TextView locationLabel = ((TextView) locationRootView.findViewById(R.id.locationLabel));
locationLabel.setText(getResources().getString(R.string.location).toUpperCase());
@@ -644,13 +645,21 @@ public void initLocation() {
updateLocation.setOnClickListener(this);
removeLocation.setOnClickListener(this);
+ if (!checkForLocationPermission()) return;
+
// if this post has location attached to it, look up the location address
if (mPost.hasLocation()) {
showLocationView();
PostLocation location = mPost.getLocation();
setLocation(location.getLatitude(), location.getLongitude());
} else {
- showLocationAdd();
+ // Search for current location to geotag post if preferences allow
+ EditPostActivity activity = (EditPostActivity) getActivity();
+ if (SiteSettingsInterface.getGeotagging(activity) && activity.isNewPost()) {
+ searchLocation();
+ } else {
+ showLocationAdd();
+ }
}
}
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 9726f5a00cc5..46a57ba697a5 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,5 +1,7 @@
package org.wordpress.android.ui.prefs;
+import android.app.Fragment;
+import android.app.FragmentManager;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
@@ -28,6 +30,7 @@
import org.wordpress.android.util.CoreEvents.UserSignedOutCompletely;
import org.wordpress.android.util.StringUtils;
import org.wordpress.android.util.ToastUtils;
+import org.wordpress.android.networking.ConnectionChangeReceiver;
import de.greenrobot.event.EventBus;
@@ -35,9 +38,11 @@
* Activity for configuring blog specific settings.
*/
public class BlogPreferencesActivity extends AppCompatActivity {
- public static final String ARG_LOCAL_BLOG_ID = "local_blog_id";
+ public static final String ARG_LOCAL_BLOG_ID = SiteSettingsFragment.ARG_LOCAL_BLOG_ID;
public static final int RESULT_BLOG_REMOVED = RESULT_FIRST_USER;
+ private static final String KEY_SETTINGS_FRAGMENT = "settings-fragment";
+
// The blog this activity is managing settings for.
private Blog blog;
private boolean mBlogDeleted;
@@ -53,49 +58,69 @@ public class BlogPreferencesActivity extends AppCompatActivity {
@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);
-
- if (blog == null) {
+ if (WordPress.getBlog(id) == null) {
Toast.makeText(this, getString(R.string.blog_not_found), Toast.LENGTH_SHORT).show();
finish();
return;
}
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- 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);
-
- // 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);
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setCustomView(R.layout.site_settings_actionbar);
+ }
+
+ FragmentManager fragmentManager = getFragmentManager();
+ Fragment siteSettingsFragment = fragmentManager.findFragmentByTag(KEY_SETTINGS_FRAGMENT);
+
+ if (siteSettingsFragment == null) {
+ siteSettingsFragment = new SiteSettingsFragment();
+ siteSettingsFragment.setArguments(getIntent().getExtras());
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, siteSettingsFragment, KEY_SETTINGS_FRAGMENT)
+ .commit();
+ }
} else {
- removeBlogButton.setVisibility(View.VISIBLE);
- removeBlogButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- removeBlogWithConfirmation();
- }
- });
- }
+ setContentView(R.layout.blog_preferences);
+
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setTitle(StringUtils.unescapeHTML(blog.getNameOrHostUrl()));
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
- loadSettingsForBlog();
+ 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);
+
+ // 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();
+ }
+ });
+ }
+
+ loadSettingsForBlog();
+ }
}
@Override
@@ -108,7 +133,7 @@ public void finish() {
protected void onPause() {
super.onPause();
- if (mBlogDeleted) {
+ if (blog.isDotcomFlag() || mBlogDeleted) {
return;
}
@@ -159,6 +184,18 @@ public void onClick(DialogInterface dialog, int whichButton) {
}
}
+ @Override
+ protected void onStart() {
+ super.onStart();
+ EventBus.getDefault().register(this);
+ }
+
+ @Override
+ protected void onStop() {
+ EventBus.getDefault().unregister(this);
+ super.onStop();
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemID = item.getItemId();
@@ -170,6 +207,24 @@ public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
+ @SuppressWarnings("unused")
+ public void onEventMainThread(ConnectionChangeReceiver.ConnectionChangeEvent event) {
+ FragmentManager fragmentManager = getFragmentManager();
+ SiteSettingsFragment siteSettingsFragment =
+ (SiteSettingsFragment) fragmentManager.findFragmentByTag(KEY_SETTINGS_FRAGMENT);
+
+ if (siteSettingsFragment != null) {
+ if (!event.isConnected()) {
+ ToastUtils.showToast(this, getString(R.string.site_settings_disconnected_toast));
+ }
+
+ // TODO: add this back when delete blog is back
+ //https://github.com/wordpress-mobile/WordPress-Android/commit/6a90e3fe46e24ee40abdc4a7f8f0db06f157900c
+ // Checks for stats widgets that were synched with a blog that could be gone now.
+// StatsWidgetProvider.updateWidgetsOnLogout(this);
+ }
+ }
+
private void loadSettingsForBlog() {
ArrayAdapter