Commit 9d3d3e10 authored by Roger Barton's avatar Roger Barton
Browse files

Merge branch 'localisation'

parents 0bee4005 053cddb4
Pipeline #4497 failed with stages
in 1 minute and 57 seconds
......@@ -7,7 +7,7 @@ android {
minSdkVersion 23
targetSdkVersion 27
versionCode 1
versionName "1.0"
versionName "0.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
......
......@@ -17,11 +17,12 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:screenOrientation="portrait"
android:supportsRtl="true"
android:name=".MyApplication"
android:theme="@style/AppThemeLight">
<activity
android:name=".SettingsActivity"
android:label=""
android:configChanges="layoutDirection|locale"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
......@@ -29,7 +30,7 @@
</activity>
<activity
android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:configChanges="keyboardHidden|orientation|layoutDirection|screenSize|locale"
android:label="@string/app_name"
android:theme="@style/AppThemeLight"
android:windowSoftInputMode="adjustNothing">
......@@ -42,7 +43,7 @@
</activity>
<activity
android:name=".LoginActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:configChanges="keyboardHidden|orientation|layoutDirection|screenSize|locale"
android:label=""
android:windowSoftInputMode="stateVisible">
<meta-data
......@@ -51,6 +52,7 @@
</activity>
<activity
android:name=".EventDetailActivity"
android:configChanges="orientation|layoutDirection|locale"
android:theme="@style/AppThemeLight">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
......@@ -58,6 +60,7 @@
</activity>
<activity android:name=".BarcodeIdActivity"
android:screenOrientation="portrait"
android:configChanges="layoutDirection|locale"
android:parentActivityName=".MainActivity">
</activity>
......
package ch.amiv.android_app;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
......@@ -71,8 +72,11 @@ public class BarcodeIdActivity extends AppCompatActivity {
* Will generate a barcode bitmap and apply it to the barcodeImageview. Note: barcode will not fill whole constraint as the width of the bars is determined in pixels, to prevent distortion
*/
public void GenerateBarcode(){
if(UserInfo.current == null || (UserInfo.current.nethz.isEmpty() && UserInfo.current.email.isEmpty()))
if(UserInfo.current == null || (UserInfo.current.nethz.isEmpty() && UserInfo.current.email.isEmpty())){
Snackbar.make(swipeRefreshLayout, R.string.not_logged_in, Snackbar.LENGTH_LONG).show();
swipeRefreshLayout.setRefreshing(false);
return;
}
//prioritise nethz as this is shorter
String encode = UserInfo.current.nethz.isEmpty() ? UserInfo.current.email : UserInfo.current.nethz;
......
......@@ -128,8 +128,8 @@ public class EventDetailActivity extends AppCompatActivity {
}
//Link up variables with UI elements from the layout xml
((TextView) findViewById(R.id.eventTitle)).setText(Events.eventInfos.get(eventIndex).title_en);
((TextView)findViewById(R.id.eventDetail)).setText(Events.eventInfos.get(eventIndex).description_en);
((TextView) findViewById(R.id.eventTitle)).setText(Events.eventInfos.get(eventIndex).GetTitle(getResources()));
((TextView)findViewById(R.id.eventDetail)).setText(Events.eventInfos.get(eventIndex).GetDescription(getResources()));
scrollView = findViewById(R.id.scrollView_event);
posterProgress = findViewById(R.id.progressBar);
posterImage = findViewById(R.id.eventPoster);
......@@ -228,7 +228,7 @@ public class EventDetailActivity extends AppCompatActivity {
}, 0, 0, ImageView.ScaleType.CENTER_INSIDE, Bitmap.Config.ARGB_8888,
new Response.ErrorListener() {
public void onErrorResponse(VolleyError error) {
Snackbar.make(posterImage, "Error loading image", Snackbar.LENGTH_SHORT).show();
Snackbar.make(posterImage, R.string.error_image_load, Snackbar.LENGTH_SHORT).show();
posterProgress.setVisibility(View.GONE);
swipeRefreshLayout.setRefreshing(false);
}
......@@ -252,7 +252,7 @@ public class EventDetailActivity extends AppCompatActivity {
LinearLayout linear = findViewById(R.id.register_details_list);
linear.removeAllViews();
ArrayList<String[]> infos = Events.eventInfos.get(eventIndex).GetInfos();
ArrayList<String[]> infos = Events.eventInfos.get(eventIndex).GetInfos(getResources());
LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
for (int i = 0; i < infos.size(); i++) {
//Create a view from the xml and then add it as a child of the listview
......@@ -271,7 +271,7 @@ public class EventDetailActivity extends AppCompatActivity {
public void RegisterForEvent(View view)
{
if(!Requests.CheckConnection(getApplicationContext())) {
Snackbar.make(view, "Requires Internet", Snackbar.LENGTH_LONG).show();
Snackbar.make(view, R.string.requires_internet, Snackbar.LENGTH_LONG).show();
return;
}
......@@ -307,14 +307,14 @@ public class EventDetailActivity extends AppCompatActivity {
});
//Interpret notification to show from the signup
String notification = "";
int notification = 0;
if(Events.eventInfos.get(eventIndex).accepted) {
if(Events.eventInfos.get(eventIndex).confirmed)
notification = "Successfully Registered";
notification = R.string.register_success;
else
notification = "Registered, please confirm with mail";
notification = R.string.register_success_confirm_required;
} else
notification = "Added to Waiting List";
notification = R.string.added_to_waiting_list;
Snackbar.make(scrollView, notification, Snackbar.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
......@@ -322,7 +322,7 @@ public class EventDetailActivity extends AppCompatActivity {
}
else {
Log.e("request", "Request returned null response.");
Snackbar.make(scrollView, "Error occured, please try again", Snackbar.LENGTH_SHORT).show();
Snackbar.make(scrollView, R.string.snack_error_retry, Snackbar.LENGTH_SHORT).show();
}
return super.parseNetworkResponse(response);
}
......@@ -332,7 +332,7 @@ public class EventDetailActivity extends AppCompatActivity {
if(volleyError != null && volleyError.networkResponse != null) {
Log.e("request", "status code: " + volleyError.networkResponse.statusCode + "\n" + new String(volleyError.networkResponse.data));
if(volleyError.networkResponse.statusCode == 422) {
Snackbar.make(scrollView, "Already Registered", Snackbar.LENGTH_SHORT).show();
Snackbar.make(scrollView, R.string.already_registered, Snackbar.LENGTH_SHORT).show();
}
}
else
......@@ -367,10 +367,10 @@ public class EventDetailActivity extends AppCompatActivity {
private void UpdateRegisterButton() {
if (Events.eventInfos.get(eventIndex).IsSignedUp()) {
registerButton.setEnabled(false);
registerButton.setText("Already Registered");
registerButton.setText(R.string.already_registered);
} else {
registerButton.setEnabled(true);
registerButton.setText("Register");
registerButton.setText(R.string.register_title);
}
}
......
......@@ -66,8 +66,8 @@ public class EventDetailFragment extends Fragment {
TextView content = getView().findViewById(R.id.eventDetail);
final ImageView poster = getView().findViewById(R.id.eventPoster);
title.setText(Events.eventInfos.get(eventIndex).title_en);
content.setText(Events.eventInfos.get(eventIndex).description_en);
title.setText(Events.eventInfos.get(eventIndex).GetTitle(getResources()));
content.setText(Events.eventInfos.get(eventIndex).GetDescription(getResources()));
String posterUrl = "https://www.amiv.ethz.ch/sites/all/themes/amiv15/logo.png";
ImageRequest posterRequest = new ImageRequest(posterUrl,
......
package ch.amiv.android_app;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.Log;
import org.json.JSONException;
......@@ -9,6 +11,7 @@ import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
/**
* This is all the data about one event AND the current users signup data about that event
......@@ -16,12 +19,12 @@ import java.util.Date;
public class EventInfo {
//region - ====Variables====
public String _id;
public String title_de;
public String title_en;
public String catchphrase_de;
public String catchphrase_en;
public String description_de;
public String description_en;
private String title_de;
private String title_en;
private String catchphrase_de;
private String catchphrase_en;
private String description_de;
private String description_en;
public String location;
public String price;
public String priority;
......@@ -156,24 +159,49 @@ public class EventInfo {
* Choose the key value pairs to be displayed in the event info section when viewing the event in detail
* @return
*/
public ArrayList<String[]> GetInfos(){
public ArrayList<String[]> GetInfos(Resources r){
if(infos != null && infos.size() > 0)
return infos;
DateFormat dateFormat = new SimpleDateFormat("yyyy - MMM - dd HH:mm");
if(time_start != null) infos.add(new String[]{"Start", dateFormat.format(time_start)});
if(time_end != null) infos.add(new String[]{"End", dateFormat.format(time_end)});
if(!price.isEmpty()) infos.add(new String[]{"Price", (price.equalsIgnoreCase("0") ? "Free" : price)});
if(!location.isEmpty()) infos.add(new String[]{"Location", location});
if(time_register_start != null) infos.add(new String[]{"Register Start", dateFormat.format(time_register_start)});
if(time_register_end != null) infos.add(new String[]{"Register End", dateFormat.format(time_register_end)});
infos.add(new String[]{"Available Places", (spots == 0 ? "-" : "" + Math.max(0, spots - signup_count))});
DateFormat dateFormat = new SimpleDateFormat("dd - MMM - yyyy HH:mm", r.getConfiguration().locale);
if(time_start != null) infos.add(new String[]{ r.getString(R.string.start_time), dateFormat.format(time_start)});
if(time_end != null) infos.add(new String[]{ r.getString(R.string.end_time), dateFormat.format(time_end)});
if(!price.isEmpty()) infos.add(new String[]{ r.getString(R.string.price), (price.equalsIgnoreCase("0") ? r.getString(R.string.price_free) : price + " CHF")});
if(!location.isEmpty()) infos.add(new String[]{ r.getString(R.string.location), location});
if(time_register_start != null) infos.add(new String[]{ r.getString(R.string.register_start), dateFormat.format(time_register_start)});
if(time_register_end != null) infos.add(new String[]{ r.getString(R.string.register_end), dateFormat.format(time_register_end)});
infos.add(new String[]{ r.getString(R.string.available_places), (spots <= 0 ? "-" : "" + Math.max(0, spots - signup_count))});
if(spots - signup_count < 0)
infos.add(new String[]{"Waiting List Size", "" + (signup_count - spots)});
infos.add(new String[]{ r.getString(R.string.waiting_list_size), "" + (signup_count - spots)});
return infos;
}
public String GetTitle (Resources res)
{
Locale locale = res.getConfiguration().locale;
if(res.getConfiguration().locale.equals(Locale.GERMAN) && !title_de.isEmpty())
return title_de;
else
return title_en;
}
public String GetDescription(Resources res)
{
if(res.getConfiguration().locale.equals(Locale.GERMAN) && !description_de.isEmpty())
return description_de;
else
return description_en;
}
public String GetCatchphrase(Resources res)
{
if(res.getConfiguration().locale.equals(Locale.GERMAN) && !catchphrase_de.isEmpty())
return catchphrase_de;
else
return catchphrase_en;
}
public boolean IsSignedUp ()
{
return !signup_id.isEmpty();
......
package ch.amiv.android_app;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
......@@ -37,6 +39,7 @@ public final class Events {
public static void AddSignupArray(JSONArray json) {
boolean[] hasUpdatedEvent = new boolean[eventInfos.size()];
signupLoop:
for (int i = 0; i < json.length(); i++) {
try {
JSONObject signup = json.getJSONObject(i);
......@@ -46,8 +49,10 @@ public final class Events {
if (!hasUpdatedEvent[j] && event.equals(eventInfos.get(j)._id)) {
Events.eventInfos.get(j).AddSignup(signup);
hasUpdatedEvent[j] = true;
continue signupLoop;
}
}
Log.e("events", "Received signup for event that does not exist locally, event id:" + signup.getString("event"));
}
}
catch (JSONException e){
......
......@@ -53,7 +53,7 @@ public class EventsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
}
public EventsListAdapter(Activity activity_) {
headerList.add("New Events");
headerList.add(activity_.getResources().getString(R.string.new_events_title));
//headerList.add("Attended Events"); //XXX Add sorting of old events, where checkin or confirmed is true
activity = activity_;
}
......@@ -121,8 +121,8 @@ public class EventsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
final EventInfoHolder eventInfoHolder = (EventInfoHolder)holder;
final int eventIndex = holder.getAdapterPosition() - 1;
final EventInfo e = Events.eventInfos.get(eventIndex);
eventInfoHolder.titleField.setText(e.title_en);
eventInfoHolder.catchphraseField.setText(e.catchphrase_en);
eventInfoHolder.titleField.setText(e.GetTitle(activity.getResources()));
eventInfoHolder.catchphraseField.setText(e.GetCatchphrase(activity.getResources()));
eventInfoHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
......@@ -145,7 +145,7 @@ public class EventsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
else {
eventInfoHolder.statusImage.setVisibility(View.GONE);
eventInfoHolder.placesField.setVisibility(View.VISIBLE);
eventInfoHolder.placesField.setText((e.spots == 0 ? "" : "" + (e.spots - e.signup_count)));
eventInfoHolder.placesField.setText("" + Math.max(0, e.spots - e.signup_count));
}
break;
}
......
......@@ -74,7 +74,7 @@ public class LoginActivity extends AppCompatActivity {
final String password = passwordField.getText().toString();
if(username.isEmpty()) {
Snackbar.make(submitButton, "Please fill in all fields", Snackbar.LENGTH_SHORT).show();
Snackbar.make(submitButton, R.string.snack_fill_all_fields, Snackbar.LENGTH_SHORT).show();
return;
}
......@@ -95,7 +95,7 @@ public class LoginActivity extends AppCompatActivity {
ReturnToCallingActivity(true);
}
else{
Snackbar.make(userField, "An error occured, please retry", Snackbar.LENGTH_SHORT).show();
Snackbar.make(userField, R.string.snack_error_retry, Snackbar.LENGTH_SHORT).show();
SetSubmitButtonState(true, false);
}
......@@ -123,12 +123,12 @@ public class LoginActivity extends AppCompatActivity {
protected VolleyError parseNetworkError(final VolleyError volleyError) { //see comments at parseNetworkResponse()
if(volleyError != null && volleyError.networkResponse != null)
{
Snackbar.make(userField, "Invalid Login Details", Snackbar.LENGTH_SHORT).show();
Snackbar.make(userField, R.string.invalid_login, Snackbar.LENGTH_SHORT).show();
Log.e("request", "status code: " + volleyError.networkResponse.statusCode + "\n" + new String(volleyError.networkResponse.data));
}
else
{
Snackbar.make(userField, "No Internet", Snackbar.LENGTH_SHORT).show();
Snackbar.make(userField, R.string.no_internet, Snackbar.LENGTH_SHORT).show();
Log.e("request", "Request returned null response.");
}
......@@ -149,7 +149,7 @@ public class LoginActivity extends AppCompatActivity {
if(wasSent)
SetSubmitButtonState(false, false);
else
Snackbar.make(userField, "No Internet", Snackbar.LENGTH_SHORT).show();
Snackbar.make(userField, R.string.no_internet, Snackbar.LENGTH_SHORT).show();
}
/**
......@@ -162,7 +162,7 @@ public class LoginActivity extends AppCompatActivity {
@Override
public void run() {
submitButton.setEnabled(enable);
submitButton.setText(enable ? "Submit" : (loginSuccess ? "Success" : "Please Wait"));
submitButton.setText(enable ? R.string.login_title : (loginSuccess ? R.string.success : R.string.wait));
}
});
}
......
......@@ -168,7 +168,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
{
if(Settings.IsLoggedIn(getApplicationContext())) {
drawerNavigation.getMenu().findItem(R.id.nav_login)
.setTitle("Logout")
.setTitle(R.string.logout_title)
.setChecked(false);
if(UserInfo.current != null)
{
......@@ -179,9 +179,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
else
{
drawerNavigation.getMenu().findItem(R.id.nav_login)
.setTitle("Login")
.setTitle(R.string.login_title)
.setChecked(false);
drawer_title.setText("Not Logged In");
drawer_title.setText(R.string.not_logged_in);
drawer_subtitle.setText("");
}
}
......
package ch.amiv.android_app;
import android.app.Application;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.preference.PreferenceManager;
import java.util.Locale;
public class MyApplication extends Application
{
private Locale locale = null;
@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
if (locale != null)
{
newConfig.locale = locale;
Locale.setDefault(locale);
getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics());
}
}
@Override
public void onCreate()
{
super.onCreate();
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
Configuration config = getBaseContext().getResources().getConfiguration();
String lang = settings.getString(getString(R.string.pref_lang_key), "");
if (!lang.isEmpty() && !config.locale.getLanguage().equals(lang))
{
locale = new Locale(lang);
Locale.setDefault(locale);
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
}
}
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
......@@ -18,9 +19,11 @@ import android.preference.RingtonePreference;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBar;
import android.text.TextUtils;
import android.transition.ChangeBounds;
import android.view.MenuItem;
import java.util.List;
import java.util.Locale;
/**
* A {@link PreferenceActivity} that presents a set of application settings. On
......@@ -51,10 +54,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
preference.setSummary(index >= 0 ? listPreference.getEntries()[index] : null);
} else if (preference instanceof RingtonePreference) {
// For ringtone preferences, look up the correct display value
......@@ -87,15 +87,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
}
};
/**
* Helper method to determine if the device has an extra-large screen. For
* example, 10" tablets are extra-large.
*/
private static boolean isXLargeTablet(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
......@@ -121,6 +112,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
getFragmentManager().beginTransaction().replace(android.R.id.content, new GeneralPreferenceFragment()).commit();
}
/**
......@@ -146,34 +138,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
return super.onMenuItemSelected(featureId, item);
}
/**
* {@inheritDoc}
*/
@Override
public boolean onIsMultiPane() {
return isXLargeTablet(this);
}
/**
* {@inheritDoc}
*/
@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
/**
* This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here.
*/
protected boolean isValidFragment(String fragmentName) {
return PreferenceFragment.class.getName().equals(fragmentName)
|| GeneralPreferenceFragment.class.getName().equals(fragmentName)
|| DataSyncPreferenceFragment.class.getName().equals(fragmentName)
|| NotificationPreferenceFragment.class.getName().equals(fragmentName);
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
......@@ -183,75 +147,39 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference("lang_list"));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
/**
* This fragment shows notification preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class NotificationPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_notification);
addPreferencesFromResource(R.xml.pref_settings);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));