added a choose country activity

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java          |  12 
src/main/res/values/strings.xml                                         |   1 
src/main/res/values/styles.xml                                          |   8 
src/quick/AndroidManifest.xml                                           |   5 
src/quick/java/eu/siacs/conversations/ui/ChooseCountryActivity.java     | 129 
src/quick/java/eu/siacs/conversations/ui/EnterPhoneNumberActivity.java  |  45 
src/quick/java/eu/siacs/conversations/ui/adapter/CountryAdapter.java    |  70 
src/quick/java/eu/siacs/conversations/utils/PhoneNumberUtilWrapper.java |  40 
src/quick/res/layout/activity_choose_country.xml                        |  24 
src/quick/res/layout/country_item.xml                                   |  25 
src/quick/res/menu/choose_country.xml                                   |  11 
11 files changed, 365 insertions(+), 5 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java 🔗

@@ -2,6 +2,8 @@ package eu.siacs.conversations.ui;
 
 import android.support.v7.app.ActionBar;
 import android.support.v7.app.AppCompatActivity;
+import android.view.MenuItem;
+
 
 public abstract class ActionBarActivity extends AppCompatActivity {
     public static void configureActionBar(ActionBar actionBar) {
@@ -14,4 +16,14 @@ public abstract class ActionBarActivity extends AppCompatActivity {
             actionBar.setDisplayHomeAsUpEnabled(upNavigation);
         }
     }
+
+    @Override
+    public boolean onOptionsItemSelected(final MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                finish();
+                break;
+        }
+        return super.onOptionsItemSelected(item);
+    }
 }

src/main/res/values/strings.xml 🔗

@@ -758,4 +758,5 @@
     <string name="we_will_be_verifying"><![CDATA[We will be verifying the phone number<br/><br/><b>%s</b><br/><br/>Is this OK, or would you like to edit the number?]]></string>
     <string name="not_a_valid_phone_number">%s is not a valid phone number.</string>
     <string name="please_enter_your_phone_number">Please enter your phone number.</string>
+    <string name="search_countries">Search countries</string>
 </resources>

src/main/res/values/styles.xml 🔗

@@ -14,6 +14,14 @@
         <item name="android:textSize">?TextSizeSubhead</item>
     </style>
 
+    <style name="TextAppearance.Conversations.Subhead.Bold" parent="TextAppearance.Conversations.Subhead">
+        <item name="android:textStyle">bold</item>
+    </style>
+
+    <style name="TextAppearance.Conversations.Subhead.Bold.Secondary" parent="TextAppearance.Conversations.Subhead.Bold">
+        <item name="android:textColor">?android:textColorSecondary</item>
+    </style>
+
     <style name="TextAppearance.Conversations.Body2" parent="TextAppearance.AppCompat.Body2">
         <item name="android:textSize">?TextSizeBody2</item>
     </style>

src/quick/AndroidManifest.xml 🔗

@@ -9,5 +9,10 @@
             android:label="@string/verify_your_phone_number"
             android:launchMode="singleTask" />
 
+        <activity
+            android:name=".ui.ChooseCountryActivity"
+            android:label="@string/choose_a_country"
+            android:launchMode="singleTask" />
+
     </application>
 </manifest>

src/quick/java/eu/siacs/conversations/ui/ChooseCountryActivity.java 🔗

@@ -0,0 +1,129 @@
+package eu.siacs.conversations.ui;
+
+import android.content.Context;
+import android.content.Intent;
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.Toolbar;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.ActivityChooseCountryBinding;
+import eu.siacs.conversations.ui.adapter.CountryAdapter;
+import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
+
+public class ChooseCountryActivity extends ActionBarActivity implements CountryAdapter.OnCountryClicked {
+
+    private ActivityChooseCountryBinding binding;
+
+    private List<PhoneNumberUtilWrapper.Country> countries = new ArrayList<>();
+    private CountryAdapter countryAdapter = new CountryAdapter(countries);
+    private final TextWatcher mSearchTextWatcher = new TextWatcher() {
+
+        @Override
+        public void afterTextChanged(final Editable editable) {
+            filterCountries(editable.toString());
+        }
+
+        @Override
+        public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
+        }
+
+        @Override
+        public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
+        }
+    };
+    private EditText mSearchEditText;
+    private final MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
+
+        @Override
+        public boolean onMenuItemActionExpand(final MenuItem item) {
+            mSearchEditText.post(() -> {
+                mSearchEditText.requestFocus();
+                final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+                imm.showSoftInput(mSearchEditText, InputMethodManager.SHOW_IMPLICIT);
+            });
+
+            return true;
+        }
+
+        @Override
+        public boolean onMenuItemActionCollapse(final MenuItem item) {
+            final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+            imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
+            mSearchEditText.setText("");
+            filterCountries(null);
+            return true;
+        }
+    };
+     private TextView.OnEditorActionListener mSearchDone = (v, actionId, event) -> {
+         if (countries.size() == 1) {
+             onCountryClicked(countries.get(0));
+         }
+         return true;
+     };
+
+    @Override
+    protected void onCreate(final Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        this.binding = DataBindingUtil.setContentView(this, R.layout.activity_choose_country);
+        setSupportActionBar((Toolbar) this.binding.toolbar);
+        configureActionBar(getSupportActionBar());
+        this.countries.addAll(PhoneNumberUtilWrapper.getCountries(this));
+        Collections.sort(this.countries);
+        this.binding.countries.setAdapter(countryAdapter);
+        this.binding.countries.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
+        countryAdapter.setOnCountryClicked(this);
+        countryAdapter.notifyDataSetChanged();
+    }
+
+    @Override
+    public void onCountryClicked(PhoneNumberUtilWrapper.Country country) {
+        Intent data = new Intent();
+        data.putExtra("region", country.getRegion());
+        setResult(RESULT_OK, data);
+        finish();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(final Menu menu) {
+        getMenuInflater().inflate(R.menu.choose_country, menu);
+        final MenuItem menuSearchView = menu.findItem(R.id.action_search);
+        final View mSearchView = menuSearchView.getActionView();
+        mSearchEditText = mSearchView.findViewById(R.id.search_field);
+        mSearchEditText.addTextChangedListener(mSearchTextWatcher);
+        mSearchEditText.setHint(R.string.search_countries);
+        mSearchEditText.setOnEditorActionListener(mSearchDone);
+        menuSearchView.setOnActionExpandListener(mOnActionExpandListener);
+        return true;
+    }
+
+    private void filterCountries(String needle) {
+        List<PhoneNumberUtilWrapper.Country> countries = PhoneNumberUtilWrapper.getCountries(this);
+        Iterator<PhoneNumberUtilWrapper.Country> iterator = countries.iterator();
+        while(iterator.hasNext()) {
+            final PhoneNumberUtilWrapper.Country country = iterator.next();
+            if(needle != null && !country.getName().toLowerCase(Locale.getDefault()).contains(needle.toLowerCase(Locale.getDefault()))) {
+                iterator.remove();
+            }
+        }
+        this.countries.clear();
+        this.countries.addAll(countries);
+        this.countryAdapter.notifyDataSetChanged();
+    }
+
+}

src/quick/java/eu/siacs/conversations/ui/EnterPhoneNumberActivity.java 🔗

@@ -1,6 +1,7 @@
 package eu.siacs.conversations.ui;
 
 import android.app.AlertDialog;
+import android.content.Intent;
 import android.databinding.DataBindingUtil;
 import android.os.Bundle;
 import android.support.v7.app.AppCompatActivity;
@@ -10,7 +11,9 @@ import android.text.Html;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.util.Log;
+import android.view.KeyEvent;
 import android.view.View;
+import android.widget.TextView;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
@@ -23,6 +26,8 @@ import io.michaelrocks.libphonenumber.android.Phonenumber;
 
 public class EnterPhoneNumberActivity extends AppCompatActivity {
 
+    private static final int REQUEST_CHOOSE_COUNTRY = 0x1234;
+
     private ActivityEnterNumberBinding binding;
     private String region = null;
     private final TextWatcher countryCodeTextWatcher = new TextWatcher() {
@@ -40,8 +45,11 @@ public class EnterPhoneNumberActivity extends AppCompatActivity {
         public void afterTextChanged(Editable editable) {
             final String text = editable.toString();
             try {
+                final int oldCode = region != null ? PhoneNumberUtilWrapper.getInstance(EnterPhoneNumberActivity.this).getCountryCodeForRegion(region) : 0;
                 final int code = Integer.parseInt(text);
-                region = PhoneNumberUtilWrapper.getInstance(EnterPhoneNumberActivity.this).getRegionCodeForCountryCode(code);
+                if (oldCode != code) {
+                    region = PhoneNumberUtilWrapper.getInstance(EnterPhoneNumberActivity.this).getRegionCodeForCountryCode(code);
+                }
                 if ("ZZ".equals(region)) {
                     binding.country.setText(TextUtils.isEmpty(text) ? R.string.choose_a_country : R.string.invalid_country_code);
                 } else {
@@ -57,18 +65,31 @@ public class EnterPhoneNumberActivity extends AppCompatActivity {
     @Override
     protected void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
+        String region = savedInstanceState != null ? savedInstanceState.getString("region") : null;
+        if (region != null) {
+            this.region = region;
+        } else {
+            this.region = PhoneNumberUtilWrapper.getUserCountry(this);
+        }
+
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_enter_number);
         this.binding.countryCode.setCompoundDrawables(new TextDrawable(this.binding.countryCode, "+"), null, null, null);
         this.binding.country.setOnClickListener(this::onSelectCountryClick);
         this.binding.next.setOnClickListener(this::onNextClick);
         setSupportActionBar((Toolbar) this.binding.toolbar);
-
-
         this.binding.countryCode.addTextChangedListener(this.countryCodeTextWatcher);
-        this.region = PhoneNumberUtilWrapper.getUserCountry(this);
         this.binding.countryCode.setText(String.valueOf(PhoneNumberUtilWrapper.getInstance(this).getCountryCodeForRegion(this.region)));
     }
 
+    @Override
+    public void onSaveInstanceState(Bundle savedInstanceState) {
+        if (this.region != null) {
+            savedInstanceState.putString("region", this.region);
+        }
+        super.onSaveInstanceState(savedInstanceState);
+    }
+
     private void onNextClick(View v) {
         final AlertDialog.Builder builder = new AlertDialog.Builder(this);
         try {
@@ -97,11 +118,25 @@ public class EnterPhoneNumberActivity extends AppCompatActivity {
     }
 
     private void onSelectCountryClick(View view) {
-
+        Intent intent = new Intent(this, ChooseCountryActivity.class);
+        startActivityForResult(intent, REQUEST_CHOOSE_COUNTRY);
     }
 
     private void onPhoneNumberEntered(Phonenumber.PhoneNumber phoneNumber) {
 
     }
 
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, final Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (resultCode == RESULT_OK && requestCode == REQUEST_CHOOSE_COUNTRY) {
+            String region = data.getStringExtra("region");
+            if (region != null) {
+                this.region = region;
+                final int countryCode = PhoneNumberUtilWrapper.getInstance(this).getCountryCodeForRegion(region);
+                this.binding.countryCode.setText(String.valueOf(countryCode));
+            }
+        }
+    }
+
 }

src/quick/java/eu/siacs/conversations/ui/adapter/CountryAdapter.java 🔗

@@ -0,0 +1,70 @@
+package eu.siacs.conversations.ui.adapter;
+
+import android.databinding.DataBindingUtil;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import java.util.List;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.CountryItemBinding;
+import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
+
+public class CountryAdapter extends RecyclerView.Adapter<CountryAdapter.CountryViewHolder> {
+
+    private final List<PhoneNumberUtilWrapper.Country> countries;
+
+    private OnCountryClicked onCountryClicked;
+
+    public CountryAdapter(List<PhoneNumberUtilWrapper.Country> countries) {
+        this.countries = countries;
+    }
+
+    @NonNull
+    @Override
+    public CountryViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
+        CountryItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.country_item, parent, false);
+        return new CountryViewHolder(binding);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull CountryViewHolder holder, int position) {
+        final PhoneNumberUtilWrapper.Country county = countries.get(position);
+        holder.binding.country.setText(county.getName());
+        holder.binding.countryCode.setText(county.getCode());
+        holder.itemView.setOnClickListener(v -> {
+            if (onCountryClicked != null) {
+                onCountryClicked.onCountryClicked(county);
+            }
+        });
+    }
+
+    public void setOnCountryClicked(OnCountryClicked listener) {
+        this.onCountryClicked = listener;
+    }
+
+
+    @Override
+    public int getItemCount() {
+        return countries.size();
+    }
+
+
+    class CountryViewHolder extends RecyclerView.ViewHolder {
+
+        private final CountryItemBinding binding;
+
+        CountryViewHolder(CountryItemBinding binding) {
+            super(binding.getRoot());
+            this.binding = binding;
+        }
+    }
+
+    public interface OnCountryClicked {
+        void onCountryClicked(PhoneNumberUtilWrapper.Country country);
+    }
+
+}

src/quick/java/eu/siacs/conversations/utils/PhoneNumberUtilWrapper.java 🔗

@@ -3,6 +3,8 @@ package eu.siacs.conversations.utils;
 import android.content.Context;
 import android.telephony.TelephonyManager;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 
 import io.michaelrocks.libphonenumber.android.PhoneNumberUtil;
@@ -50,4 +52,42 @@ public class PhoneNumberUtilWrapper {
         return localInstance;
     }
 
+    public static List<Country> getCountries(final Context context) {
+        List<Country> countries = new ArrayList<>();
+        for(String region : getInstance(context).getSupportedRegions()) {
+            countries.add(new Country(region, getInstance(context).getCountryCodeForRegion(region)));
+        }
+        return countries;
+
+    }
+
+    public static class Country implements Comparable<Country> {
+        private final String name;
+        private final String region;
+        private final int code;
+
+        Country(String region, int code ) {
+            this.name = getCountryForCode(region);
+            this.region = region;
+            this.code = code;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getRegion() {
+            return region;
+        }
+
+        public String getCode() {
+            return '+'+String.valueOf(code);
+        }
+
+        @Override
+        public int compareTo(Country o) {
+            return name.compareTo(o.name);
+        }
+    }
+
 }

src/quick/res/layout/activity_choose_country.xml 🔗

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="?attr/color_background_primary"
+        android:orientation="vertical">
+
+        <include
+            android:id="@+id/toolbar"
+            layout="@layout/toolbar"/>
+
+        <android.support.v7.widget.RecyclerView
+            android:id="@+id/countries"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:clipToPadding="false"
+            android:padding="2dp"
+            android:scrollbars="vertical"/>
+
+    </LinearLayout>
+</layout>

src/quick/res/layout/country_item.xml 🔗

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="16dp"
+        android:background="?android:selectableItemBackground">
+        <TextView
+            android:id="@+id/country"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentStart="true"
+            android:layout_centerVertical="true"
+            android:textAppearance="@style/TextAppearance.Conversations.Subhead.Bold"
+            android:text="Germany"/>
+        <TextView
+            android:id="@+id/country_code"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true"
+            android:textAppearance="@style/TextAppearance.Conversations.Subhead.Bold.Secondary"
+            android:layout_centerVertical="true"
+            android:text="+49"/>
+    </RelativeLayout>
+</layout>

src/quick/res/menu/choose_country.xml 🔗

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item
+        android:id="@+id/action_search"
+        app:actionLayout="@layout/actionview_search"
+        android:icon="?attr/icon_search"
+        app:showAsAction="collapseActionView|always"
+        android:title="@string/search"/>
+</menu>