From 6acde92507b161862c46d7083d69cd1e209a79da Mon Sep 17 00:00:00 2001 From: krishnarb3 Date: Thu, 10 Mar 2016 03:35:22 +0530 Subject: [PATCH 1/5] Added Edit User Profile --- api/src/main/AndroidManifest.xml | 2 +- .../api/controllers/DhisController.java | 9 + .../api/controllers/UserController.java | 38 ++- .../dashboard/api/network/DhisApi.java | 4 + .../preferences/DateTimeManager.java | 6 +- app/src/main/AndroidManifest.xml | 3 + .../dhis/android/dashboard/DhisService.java | 14 +- .../activities/EditUserProfileActivity.java | 213 +++++++++++++ .../ui/adapters/AccountEditFieldAdapter.java | 280 ++++++++++++++++++ .../ui/fragments/AccountFragment.java | 14 +- .../dashboard/ui/views/FontSpinner.java | 78 +++++ .../res/layout/activity_edit_user_profile.xml | 50 ++++ app/src/main/res/layout/fragment_account.xml | 7 + ...cycler_view_edit_profile_item_edittext.xml | 26 ++ ...ecycler_view_edit_profile_item_spinner.xml | 26 ++ ...cycler_view_edit_profile_item_textview.xml | 28 ++ app/src/main/res/values/dimens.xml | 2 +- app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 4 + 19 files changed, 797 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/org/hisp/dhis/android/dashboard/ui/activities/EditUserProfileActivity.java create mode 100644 app/src/main/java/org/hisp/dhis/android/dashboard/ui/adapters/AccountEditFieldAdapter.java create mode 100644 app/src/main/java/org/hisp/dhis/android/dashboard/ui/views/FontSpinner.java create mode 100644 app/src/main/res/layout/activity_edit_user_profile.xml create mode 100644 app/src/main/res/layout/recycler_view_edit_profile_item_edittext.xml create mode 100644 app/src/main/res/layout/recycler_view_edit_profile_item_spinner.xml create mode 100644 app/src/main/res/layout/recycler_view_edit_profile_item_textview.xml diff --git a/api/src/main/AndroidManifest.xml b/api/src/main/AndroidManifest.xml index 2dbf51c3..b31c16ec 100755 --- a/api/src/main/AndroidManifest.xml +++ b/api/src/main/AndroidManifest.xml @@ -3,7 +3,7 @@ package="org.hisp.dhis.android.dashboard.api"> - + \ No newline at end of file diff --git a/api/src/main/java/org/hisp/dhis/android/dashboard/api/controllers/DhisController.java b/api/src/main/java/org/hisp/dhis/android/dashboard/api/controllers/DhisController.java index b0fcd96e..3505c3e9 100755 --- a/api/src/main/java/org/hisp/dhis/android/dashboard/api/controllers/DhisController.java +++ b/api/src/main/java/org/hisp/dhis/android/dashboard/api/controllers/DhisController.java @@ -42,6 +42,8 @@ import org.hisp.dhis.android.dashboard.api.persistence.preferences.DateTimeManager; import org.hisp.dhis.android.dashboard.api.persistence.preferences.LastUpdatedManager; +import retrofit.client.Response; + import static org.hisp.dhis.android.dashboard.api.utils.Preconditions.isNull; public class DhisController { @@ -99,6 +101,13 @@ private UserAccount signInUser(HttpUrl serverUrl, Credentials credentials) throw return user; } + public Response setUserProfileDetails(HttpUrl serverUrl + , Credentials credentials, UserAccount userAccount) throws APIException { + DhisApi dhisApi = RepoManager + .createService(serverUrl, credentials); + return new UserController(dhisApi) + .updateProfileDetails(userAccount,credentials); + } public void invalidateSession() { LastUpdatedManager.getInstance().invalidate(); diff --git a/api/src/main/java/org/hisp/dhis/android/dashboard/api/controllers/UserController.java b/api/src/main/java/org/hisp/dhis/android/dashboard/api/controllers/UserController.java index 00a1c2ef..b903f976 100755 --- a/api/src/main/java/org/hisp/dhis/android/dashboard/api/controllers/UserController.java +++ b/api/src/main/java/org/hisp/dhis/android/dashboard/api/controllers/UserController.java @@ -26,6 +26,8 @@ package org.hisp.dhis.android.dashboard.api.controllers; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.raizlabs.android.dbflow.sql.language.Delete; import com.squareup.okhttp.HttpUrl; @@ -49,12 +51,14 @@ import java.util.HashMap; import java.util.Map; +import retrofit.client.Response; + /** * @author Araz Abishov . */ final class UserController { private final DhisApi mDhisApi; - + public String TAG="JSONTAG"; public UserController(DhisApi dhisApi) { mDhisApi = dhisApi; } @@ -112,4 +116,36 @@ public UserAccount updateUserAccount() throws APIException { userAccount.save(); return userAccount; } + public Response updateProfileDetails(UserAccount userAccount + , Credentials credentials) throws APIException { + final JsonNodeFactory profileDetailsNodeFactory = JsonNodeFactory.instance; + ObjectNode profileDetailsNode = profileDetailsNodeFactory.objectNode(); + profileDetailsNode.put("username", credentials.getUsername()); + profileDetailsNode.put("firstName", userAccount.getFirstName()); + profileDetailsNode.put("surname", userAccount.getSurname()); + profileDetailsNode.put("email", userAccount.getEmail()); + profileDetailsNode.put("introduction", userAccount.getIntroduction()); + profileDetailsNode.put("jobTitle", userAccount.getJobTitle()); + profileDetailsNode.put("gender", userAccount.getGender()); + profileDetailsNode.put("birthday", userAccount.getBirthday()); + profileDetailsNode.put("employer", userAccount.getEmployer()); + profileDetailsNode.put("education", userAccount.getEducation()); + profileDetailsNode.put("interests", userAccount.getInterests()); + profileDetailsNode.put("languages", userAccount.getLanguages()); + profileDetailsNode.put("phoneNumber", userAccount.getPhoneNumber()); + + //TODO get Settings using api + ObjectNode settingsNode = profileDetailsNodeFactory.objectNode(); + settingsNode.put("keyDBLocale", "null"); + settingsNode.put("keyMessageSmsNotification","true"); + settingsNode.put("keyUiLocale","en"); + settingsNode.put("keyAnalysisDisplayProperty","name"); + settingsNode.put("keyMessageEmailNotification","true"); + profileDetailsNode.set("settings", settingsNode); + + Response response = mDhisApi.postUserAccount(profileDetailsNode); + if(response.getStatus()==200) + userAccount.save(); + return mDhisApi.postUserAccount(profileDetailsNode); + } } diff --git a/api/src/main/java/org/hisp/dhis/android/dashboard/api/network/DhisApi.java b/api/src/main/java/org/hisp/dhis/android/dashboard/api/network/DhisApi.java index 1dd70b7c..8e55b5ec 100755 --- a/api/src/main/java/org/hisp/dhis/android/dashboard/api/network/DhisApi.java +++ b/api/src/main/java/org/hisp/dhis/android/dashboard/api/network/DhisApi.java @@ -28,6 +28,8 @@ package org.hisp.dhis.android.dashboard.api.network; +import com.fasterxml.jackson.databind.JsonNode; + import org.hisp.dhis.android.dashboard.api.models.Dashboard; import org.hisp.dhis.android.dashboard.api.models.DashboardItem; import org.hisp.dhis.android.dashboard.api.models.DashboardItemContent; @@ -63,6 +65,8 @@ public interface DhisApi { @GET("/me/") UserAccount getCurrentUserAccount(@QueryMap Map queryParams); + @POST("/me/user-account/") + Response postUserAccount(@Body JsonNode accountJSON); ///////////////////////////////////////////////////////////////////////// // Methods for getting Dashboard and DashboardItems diff --git a/api/src/main/java/org/hisp/dhis/android/dashboard/api/persistence/preferences/DateTimeManager.java b/api/src/main/java/org/hisp/dhis/android/dashboard/api/persistence/preferences/DateTimeManager.java index 9e1b3f7f..fc911612 100755 --- a/api/src/main/java/org/hisp/dhis/android/dashboard/api/persistence/preferences/DateTimeManager.java +++ b/api/src/main/java/org/hisp/dhis/android/dashboard/api/persistence/preferences/DateTimeManager.java @@ -51,7 +51,7 @@ public DateTime getLastUpdated(ResourceType type) { * Removes all key-value pairs. */ public void delete() { - mPrefs.edit().clear().commit(); + mPrefs.edit().clear().apply(); } public void deleteLastUpdated(ResourceType type) { @@ -63,7 +63,7 @@ public boolean isLastUpdatedSet(ResourceType type) { } private void putString(String key, String value) { - mPrefs.edit().putString(key, value).commit(); + mPrefs.edit().putString(key, value).apply(); } private String getString(String key) { @@ -71,7 +71,7 @@ private String getString(String key) { } private void deleteString(String key) { - mPrefs.edit().remove(key).commit(); + mPrefs.edit().remove(key).apply(); } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a2200501..a61f15a3 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,6 +38,9 @@ + diff --git a/app/src/main/java/org/hisp/dhis/android/dashboard/DhisService.java b/app/src/main/java/org/hisp/dhis/android/dashboard/DhisService.java index 60e6bb55..c551aa74 100755 --- a/app/src/main/java/org/hisp/dhis/android/dashboard/DhisService.java +++ b/app/src/main/java/org/hisp/dhis/android/dashboard/DhisService.java @@ -44,6 +44,8 @@ import org.hisp.dhis.android.dashboard.api.utils.EventBusProvider; import org.hisp.dhis.android.dashboard.ui.events.UiEvent; +import retrofit.client.Response; + /** * @author Araz Abishov . */ @@ -51,6 +53,7 @@ public final class DhisService extends Service { public static final int LOG_IN = 1; public static final int CONFIRM_USER = 2; public static final int LOG_OUT = 3; + public static final int EDIT_PROFILE = 4; public static final int SYNC_DASHBOARDS = 5; public static final int SYNC_DASHBOARD_CONTENT = 6; public static final int SYNC_INTERPRETATIONS = 7; @@ -105,7 +108,16 @@ public void onFinish(UiEvent result) { } }); } - + public void editProfileDetails(final HttpUrl serverUrl, final Credentials credentials + ,final UserAccount userAccount) { + JobExecutor.enqueueJob(new NetworkJob(EDIT_PROFILE, + ResourceType.USERS) { + @Override + public Response execute() throws APIException { + return mDhisController.setUserProfileDetails(serverUrl, credentials, userAccount); + } + }); + } public void confirmUser(final Credentials credentials) { JobExecutor.enqueueJob(new NetworkJob(CONFIRM_USER, ResourceType.USERS) { diff --git a/app/src/main/java/org/hisp/dhis/android/dashboard/ui/activities/EditUserProfileActivity.java b/app/src/main/java/org/hisp/dhis/android/dashboard/ui/activities/EditUserProfileActivity.java new file mode 100644 index 00000000..ab63383b --- /dev/null +++ b/app/src/main/java/org/hisp/dhis/android/dashboard/ui/activities/EditUserProfileActivity.java @@ -0,0 +1,213 @@ +package org.hisp.dhis.android.dashboard.ui.activities; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.app.LoaderManager; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.Loader; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.Toast; + +import org.hisp.dhis.android.dashboard.DhisService; +import org.hisp.dhis.android.dashboard.R; +import org.hisp.dhis.android.dashboard.api.models.UserAccount; +import org.hisp.dhis.android.dashboard.api.models.meta.Session; +import org.hisp.dhis.android.dashboard.api.persistence.loaders.DbLoader; +import org.hisp.dhis.android.dashboard.api.persistence.loaders.Query; +import org.hisp.dhis.android.dashboard.api.persistence.preferences.LastUpdatedManager; +import org.hisp.dhis.android.dashboard.ui.adapters.AccountEditFieldAdapter; +import org.hisp.dhis.android.dashboard.ui.models.Field; +import org.hisp.dhis.android.dashboard.ui.views.GridDividerDecoration; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; + +public class EditUserProfileActivity extends BaseActivity implements LoaderCallbacks> { + + private static final int LOADER_ID = 66756123; + private Session mSession; + + @Bind(R.id.recycler_view_edit_profile) + RecyclerView mRecyclerView; + @Bind(R.id.toolbar) + Toolbar toolbar; + @Bind(R.id.fab) + FloatingActionButton fab; + + AccountEditFieldAdapter mAdapter; + private LoaderManager.LoaderCallbacks> mCallbacks; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_edit_user_profile); + ButterKnife.bind(this); + + setSupportActionBar(toolbar); + + mAdapter = new AccountEditFieldAdapter(this, + getLayoutInflater()); + + LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); + + mRecyclerView.setLayoutManager(linearLayoutManager); + mRecyclerView.setItemAnimator(new DefaultItemAnimator()); + mRecyclerView.addItemDecoration(new GridDividerDecoration(this + .getApplicationContext())); + mRecyclerView.setAdapter(mAdapter); + + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Toast.makeText(getApplicationContext(),"Updating...",Toast.LENGTH_SHORT).show(); + if (isDhisServiceBound() && isNetworkAvailable() && + !getDhisService().isJobRunning(DhisService.EDIT_PROFILE)) { + mSession = LastUpdatedManager.getInstance().get(); + sendUserDetails(); + Toast.makeText(getApplicationContext() + , "Successfully Updated", Toast.LENGTH_LONG).show(); + } + else { + Toast.makeText(getApplicationContext(),"Failure",Toast.LENGTH_LONG).show(); + } + } + }); + + mCallbacks=this; + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + mCallbacks = this; + getSupportLoaderManager().initLoader(LOADER_ID,null,mCallbacks); + } + + public void sendUserDetails() { + List fieldList = mAdapter.getData(); + UserAccount userAccount = getUserAccountFromFields(fieldList); + getDhisService().editProfileDetails( + mSession.getServerUrl(), mSession.getCredentials(), userAccount); + } + + public UserAccount getUserAccountFromFields(List fields) { + UserAccount userAccount = new UserAccount(); + userAccount.setFirstName(fields.get(0).getValue()); + userAccount.setSurname(fields.get(1).getValue()); + + String gender,genderFromField; + genderFromField = fields.get(2).getValue(); + switch (genderFromField) { + case "Male": + gender = "gender_male"; + break; + case "Female": + gender = "gender_female"; + break; + default: + gender = "gender_other"; + break; + } + userAccount.setGender(gender); + + userAccount.setBirthday(fields.get(3).getValue()); + userAccount.setIntroduction(fields.get(4).getValue()); + userAccount.setEducation(fields.get(5).getValue()); + userAccount.setEmployer(fields.get(6).getValue()); + userAccount.setInterests(fields.get(7).getValue()); + userAccount.setJobTitle(fields.get(8).getValue()); + userAccount.setLanguages(fields.get(9).getValue()); + userAccount.setEmail(fields.get(10).getValue()); + userAccount.setPhoneNumber(fields.get(11).getValue()); + return userAccount; + } + @Override + public Loader> onCreateLoader(int id, Bundle args) { + if (LOADER_ID == id) { + List trackedTables = new ArrayList<>(); + trackedTables.add(new DbLoader.TrackedTable(UserAccount.class)); + return new DbLoader<>(this.getApplicationContext(), + trackedTables, new UserAccountQuery()); + } + return null; + } + + @Override + public void onLoadFinished(Loader> loader, List data) { + if (loader != null && loader.getId() == LOADER_ID) { + mAdapter.swapData(data); + } + } + + @Override + public void onLoaderReset(Loader> loader) { + // stub implementation + } + + private static class UserAccountQuery implements Query> { + + @Override + public List query(Context context) { + UserAccount userAccount = UserAccount.getCurrentUserAccountFromDb(); + + String gender = userAccount.getGender(); + if (gender != null) { + switch (gender) { + case "gender_female": { + gender = "Female"; + break; + } + case "gender_male": { + gender = "Male"; + break; + } + case "gender_other": { + gender = "Other"; + break; + } + } + } + return Arrays.asList( + new Field(getString(context, R.string.first_name), userAccount.getFirstName()), + new Field(getString(context, R.string.surname), userAccount.getSurname()), + new Field(getString(context, R.string.gender), gender), + new Field(getString(context, R.string.birthday), userAccount.getBirthday()), + new Field(getString(context, R.string.introduction), userAccount.getIntroduction()), + new Field(getString(context, R.string.education), userAccount.getEducation()), + new Field(getString(context, R.string.employer), userAccount.getEmployer()), + new Field(getString(context, R.string.interests), userAccount.getInterests()), + new Field(getString(context, R.string.job_title), userAccount.getJobTitle()), + new Field(getString(context, R.string.languages), userAccount.getLanguages()), + new Field(getString(context, R.string.email), userAccount.getEmail()), + new Field(getString(context, R.string.phone_number), userAccount.getPhoneNumber()) + ); + } + + private static String getString(Context context, int resource) { + return context.getString(resource); + } + } + + private boolean isNetworkAvailable() { + ConnectivityManager connMgr = (ConnectivityManager) this + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + if (networkInfo != null && networkInfo.isConnected()) { + return true; + } + else { + return false; + } + } +} diff --git a/app/src/main/java/org/hisp/dhis/android/dashboard/ui/adapters/AccountEditFieldAdapter.java b/app/src/main/java/org/hisp/dhis/android/dashboard/ui/adapters/AccountEditFieldAdapter.java new file mode 100644 index 00000000..a9039f5d --- /dev/null +++ b/app/src/main/java/org/hisp/dhis/android/dashboard/ui/adapters/AccountEditFieldAdapter.java @@ -0,0 +1,280 @@ +package org.hisp.dhis.android.dashboard.ui.adapters; + +import android.app.DatePickerDialog; +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.DatePicker; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; + +import org.hisp.dhis.android.dashboard.R; +import org.hisp.dhis.android.dashboard.ui.models.Field; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Created by arazabishov on 7/27/15. + */ +public class AccountEditFieldAdapter extends AbsAdapter { + + private static final int EDITTEXT=0,SPINNER=1,DATEPICKER=2; + private static Context context; + private static final String[] genderList = {"Male", "Female", "Other"}; + + public AccountEditFieldAdapter(Context context, LayoutInflater inflater) { + super(context, inflater); + AccountEditFieldAdapter.context = context; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + + RecyclerView.ViewHolder viewHolder; + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + + if(viewType == EDITTEXT) { + View viewEditText = inflater.inflate(R.layout.recycler_view_edit_profile_item_edittext + , parent, false); + viewHolder = new FieldEditTextViewHolder(viewEditText, new EditTextListener()); + } + else if(viewType == SPINNER){ + View viewSpinner = inflater.inflate(R.layout.recycler_view_edit_profile_item_spinner + , parent, false); + viewHolder = new FieldSpinnerViewHolder(viewSpinner); + } + else{ + View viewDatePicker = inflater.inflate(R.layout.recycler_view_edit_profile_item_textview + , parent, false); + viewHolder = new FieldDatePickerViewHolder(viewDatePicker, new DatePickerListener()); + } + return viewHolder; + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { + final Field field; + switch (holder.getItemViewType()) { + case EDITTEXT: + field = getData().get(position); + final FieldEditTextViewHolder fieldEditTextViewHolder + = (FieldEditTextViewHolder) holder; + fieldEditTextViewHolder.mEditTextListener.updatePosition(position); + fieldEditTextViewHolder.labelTextView.setText(field.getLabel()); + fieldEditTextViewHolder.valueEditText.setText(field.getValue()); + + if(field.getLabel().equals("Email")) { + fieldEditTextViewHolder.mEditTextListener.setEditText( + fieldEditTextViewHolder.valueEditText); + if(!isValidEmail(field.getValue())) { + fieldEditTextViewHolder.valueEditText.setError("Invalid Email"); + } + } + else + fieldEditTextViewHolder.valueEditText.setError(null); + break; + case SPINNER: + field = getData().get(position); + FieldSpinnerViewHolder fieldSpinnerViewHolder = (FieldSpinnerViewHolder) holder; + fieldSpinnerViewHolder.labelTextView.setText(field.getLabel()); + + if (field.getLabel().equals("Gender")) { + int pos=0; + String gender = field.getValue(); + if(gender.equals(genderList[0])) + pos = 0; + else if(gender.equals(genderList[1])) + pos = 1; + else if(gender.equals(genderList[2])) + pos = 2; + + fieldSpinnerViewHolder.valueSpinner.setSelection(pos); + fieldSpinnerViewHolder.valueSpinner.setOnItemSelectedListener( + new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent + , View view, int itemPosition, long id) { + List fieldList = getData(); + fieldList.set(position + , new Field(getData().get(position).getLabel() + , genderList[itemPosition])); + swapData(fieldList); + AccountEditFieldAdapter.this.notifyDataSetChanged(); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + } + break; + case DATEPICKER: + field = getData().get(position); + final FieldDatePickerViewHolder fieldDatePickerViewHolder + = (FieldDatePickerViewHolder) holder; + fieldDatePickerViewHolder.labelTextView.setText(field.getLabel()); + fieldDatePickerViewHolder.valueTextView.setText(field.getValue()); + + String birthday = field.getValue(); + String[] date = birthday.split("-"); + final int year = Integer.parseInt(date[0]); + final int month = Integer.parseInt(date[1]); + final int day = Integer.parseInt(date[2]); + + fieldDatePickerViewHolder.valueTextView.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + fieldDatePickerViewHolder + .mDatePickerListener.updatePosition(position); + new DatePickerDialog(context + , fieldDatePickerViewHolder.mDatePickerListener + , year, month-1, day).show(); + } + }); + break; + + } + } + + public static class FieldEditTextViewHolder extends RecyclerView.ViewHolder { + + public EditTextListener mEditTextListener; + + @Bind(R.id.field_label_text_view) + public TextView labelTextView; + + @Bind(R.id.field_edit_text) + public EditText valueEditText; + + public FieldEditTextViewHolder(View itemView, EditTextListener mEditTextListener) { + super(itemView); + ButterKnife.bind(this, itemView); + this.mEditTextListener = mEditTextListener; + this.valueEditText.addTextChangedListener(mEditTextListener); + } + } + + public static class FieldSpinnerViewHolder extends RecyclerView.ViewHolder { + + @Bind(R.id.field_label_text_view) + public TextView labelTextView; + + @Bind(R.id.field_spinner) + public Spinner valueSpinner; + + public FieldSpinnerViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + this.valueSpinner.setAdapter(new ArrayAdapter<>( //For Better Scrolling Performance + context, + android.R.layout.simple_spinner_dropdown_item, + genderList + )); + + } + } + + public static class FieldDatePickerViewHolder extends RecyclerView.ViewHolder { + + public DatePickerListener mDatePickerListener; + + @Bind(R.id.field_label_text_view) + public TextView labelTextView; + + @Bind(R.id.field_value_text_view) + public TextView valueTextView; + + public FieldDatePickerViewHolder(View itemView,DatePickerListener mDatePickerListener) { + super(itemView); + ButterKnife.bind(this, itemView); + this.mDatePickerListener = mDatePickerListener; + } + } + + public class EditTextListener implements TextWatcher { + + EditText mEditText; + private int position; + public void updatePosition(int position) { + this.position = position; + } + public void setEditText(EditText mEditText) { //For setting error without calling onBind + this.mEditText = mEditText; + } + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + List fieldList = getData(); + fieldList.set(position, new Field( + getData().get(position).getLabel(), charSequence.toString())); + swapData(fieldList); + if(!isValidEmail(charSequence)&&mEditText!=null) { + mEditText.setError("Invalid Email"); + } + else if(mEditText!=null){ + mEditText.setError(null); + } + } + + @Override + public void afterTextChanged(Editable editable) { + } + } + + public class DatePickerListener implements DatePickerDialog.OnDateSetListener { + + private int position; + public void updatePosition(int position) { + this.position = position; + } + @Override + public void onDateSet(DatePicker view, int year, int monthOfYear, + int dayOfMonth) { + String dateSet; + + Calendar calendar = Calendar.getInstance(); + calendar.set(year, monthOfYear, dayOfMonth); + SimpleDateFormat dateformat = new SimpleDateFormat( + "yyyy-MM-dd", Locale.ENGLISH); + dateSet = dateformat.format(calendar.getTime()); + List fieldList = getData(); + fieldList.set(position + , new Field(getData().get(position).getLabel(), dateSet)); + swapData(fieldList); + AccountEditFieldAdapter.this.notifyDataSetChanged(); + } + } + @Override + public int getItemViewType(int position) { + if(getData().get(position).getLabel().equals("Gender")) + return SPINNER; + else if(getData().get(position).getLabel().equals("Birthday")) + return DATEPICKER; + else + return EDITTEXT; + } + + public static boolean isValidEmail(CharSequence target) { + return !TextUtils.isEmpty(target) && android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches(); + } +} diff --git a/app/src/main/java/org/hisp/dhis/android/dashboard/ui/fragments/AccountFragment.java b/app/src/main/java/org/hisp/dhis/android/dashboard/ui/fragments/AccountFragment.java index 784b9476..0faa022a 100755 --- a/app/src/main/java/org/hisp/dhis/android/dashboard/ui/fragments/AccountFragment.java +++ b/app/src/main/java/org/hisp/dhis/android/dashboard/ui/fragments/AccountFragment.java @@ -27,8 +27,10 @@ package org.hisp.dhis.android.dashboard.ui.fragments; import android.content.Context; +import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.design.widget.FloatingActionButton; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; import android.support.v7.widget.DefaultItemAnimator; @@ -43,6 +45,7 @@ import org.hisp.dhis.android.dashboard.api.models.UserAccount; import org.hisp.dhis.android.dashboard.api.persistence.loaders.DbLoader; import org.hisp.dhis.android.dashboard.api.persistence.loaders.Query; +import org.hisp.dhis.android.dashboard.ui.activities.EditUserProfileActivity; import org.hisp.dhis.android.dashboard.ui.adapters.AccountFieldAdapter; import org.hisp.dhis.android.dashboard.ui.models.Field; import org.hisp.dhis.android.dashboard.ui.views.GridDividerDecoration; @@ -62,7 +65,8 @@ public final class AccountFragment extends BaseFragment implements LoaderCallbac @Bind(R.id.toolbar) Toolbar mToolbar; - + @Bind(R.id.fab) + FloatingActionButton floatingActionButton; @Bind(R.id.recycler_view) RecyclerView mRecyclerView; @@ -97,6 +101,14 @@ public void onClick(View v) { mRecyclerView.addItemDecoration(new GridDividerDecoration(getActivity() .getApplicationContext())); mRecyclerView.setAdapter(mAdapter); + + floatingActionButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(),EditUserProfileActivity.class); + startActivity(intent); + } + }); } @Override diff --git a/app/src/main/java/org/hisp/dhis/android/dashboard/ui/views/FontSpinner.java b/app/src/main/java/org/hisp/dhis/android/dashboard/ui/views/FontSpinner.java new file mode 100644 index 00000000..81454790 --- /dev/null +++ b/app/src/main/java/org/hisp/dhis/android/dashboard/ui/views/FontSpinner.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.dashboard.ui.views; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.widget.Spinner; + +import org.hisp.dhis.android.dashboard.R; +import org.hisp.dhis.android.dashboard.utils.TypefaceManager; + +public class FontSpinner extends Spinner { + + public FontSpinner(Context context) { + super(context); + } + + public FontSpinner(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public FontSpinner(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs); + } + + private void init(Context context, AttributeSet attributeSet) { + if (!isInEditMode()) { + TypedArray attrs = context.obtainStyledAttributes( + attributeSet, R.styleable.ViewFont); + setFont(attrs.getString(R.styleable.ViewFont_font)); + attrs.recycle(); + } + } + + public void setFont(int resId) { + String name = getResources().getString(resId); + setFont(name); + } + + private void setFont(final String fontName) { + if (getContext() != null && + getContext().getAssets() != null && fontName != null) { + Typeface typeface = TypefaceManager.getTypeface( + getContext().getAssets(), fontName); + } + } +} diff --git a/app/src/main/res/layout/activity_edit_user_profile.xml b/app/src/main/res/layout/activity_edit_user_profile.xml new file mode 100644 index 00000000..d63f80cd --- /dev/null +++ b/app/src/main/res/layout/activity_edit_user_profile.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_account.xml b/app/src/main/res/layout/fragment_account.xml index 0caa5593..49e01afe 100755 --- a/app/src/main/res/layout/fragment_account.xml +++ b/app/src/main/res/layout/fragment_account.xml @@ -44,4 +44,11 @@ + \ No newline at end of file diff --git a/app/src/main/res/layout/recycler_view_edit_profile_item_edittext.xml b/app/src/main/res/layout/recycler_view_edit_profile_item_edittext.xml new file mode 100644 index 00000000..9a6ade5e --- /dev/null +++ b/app/src/main/res/layout/recycler_view_edit_profile_item_edittext.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/recycler_view_edit_profile_item_spinner.xml b/app/src/main/res/layout/recycler_view_edit_profile_item_spinner.xml new file mode 100644 index 00000000..7ba74d97 --- /dev/null +++ b/app/src/main/res/layout/recycler_view_edit_profile_item_spinner.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/recycler_view_edit_profile_item_textview.xml b/app/src/main/res/layout/recycler_view_edit_profile_item_textview.xml new file mode 100644 index 00000000..4f15b0ab --- /dev/null +++ b/app/src/main/res/layout/recycler_view_edit_profile_item_textview.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 75fac8f9..4b2d6323 100755 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -4,6 +4,6 @@ 16dp 250dp 3dp - + 16dp 1 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9df4d090..4b17ea8e 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -106,5 +106,6 @@ Languages Email Phone number + Edit User Profile diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index b0c9e397..ef928014 100755 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -56,4 +56,8 @@ @color/light_grey +