diff --git a/.github/issue_label_bot.yaml b/.github/issue_label_bot.yaml
new file mode 100644
index 000000000..a72fe81f8
--- /dev/null
+++ b/.github/issue_label_bot.yaml
@@ -0,0 +1,4 @@
+label-alias:
+ bug: 'bug'
+ feature_request: 'feature'
+ question: 'question'
diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
index 81936495f..448e54bfd 100644
--- a/.github/release-drafter.yml
+++ b/.github/release-drafter.yml
@@ -1,5 +1,5 @@
-name-template: v$NEXT_PATCH_VERSION 🌈
-tag-template: v$NEXT_PATCH_VERSION
+name-template: Release v$NEXT_MINOR_VERSION 🌈
+tag-template: v$NEXT_MINOR_VERSION
categories:
- title: 🚀 Features and Enhancements
label: feature
diff --git a/.travis.yml b/.travis.yml
index fa8464126..3b5c69163 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,5 @@
language: android
+dist: trusty
sudo: false
jdk:
- oraclejdk8
diff --git a/README.md b/README.md
index 6f7c6ede8..3d7c6dc68 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
[![Codacy Grade](https://img.shields.io/codacy/grade/d6ae120356c94c0d94d6449ec540f520.svg)](https://www.codacy.com/app/mb/open-event-organizer-android)
[![Codecov Coverage](https://img.shields.io/codecov/c/github/fossasia/open-event-organizer-android/development.svg)](https://codecov.io/gh/fossasia/open-event-organizer-android)
[![Appetize Preview](https://img.shields.io/badge/Preview-appetize.io-673AB7.svg)](https://appetize.io/app/w8v8z7pc9aewargb2uuyf108f0)
-[![Gitter](https://img.shields.io/badge/chat-on%20gitter-ff006f.svg)](https://gitter.im/fossasia/open-event-orga-app)
+[![Gitter](https://img.shields.io/badge/chat-on%20gitter-ff006f.svg)](https://gitter.im/fossasia/open-event-organizer-android)
[![Twitter Follow](https://img.shields.io/twitter/follow/eventyay.svg?style=social&label=Follow&maxAge=2592000?style=flat-square)](https://twitter.com/eventyay)
Event management app for organizers using Open Event Platform
@@ -25,7 +25,7 @@ Currently, the application is released in alpha phase and available here:
[Google Play](https://play.google.com/store/apps/details?id=com.eventyay.organizer) and [F-Droid](https://f-droid.org/en/packages/com.eventyay.organizer/).
-
+
## Roadmap
@@ -44,19 +44,19 @@ Our chat channel is on gitter here: https://gitter.im/fossasia/open-event-orga-a
- |
- |
- |
+ |
+ |
+ |
|
- |
- |
+ |
+ |
- |
- |
- |
+ |
+ |
+ |
diff --git a/app/build.gradle b/app/build.gradle
index f389bf1b4..7998a779c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,6 +8,7 @@ apply plugin: "com.github.b3er.local.properties"
def app_name = System.getenv('app_name') ?: "Eventyay Organizer"
def GOOGLE_PLACES_API_KEY = System.getenv('GOOGLE_PLACES_API_KEY') ?: "YOUR_API_KEY"
+def MAPBOX_ACCESS_TOKEN = System.getenv('MAPBOX_ACCESS_TOKEN') ?: "YOUR_ACCESS_TOKEN"
def LOCAL_KEY_PRESENT = project.hasProperty('SIGNING_KEY_FILE') && rootProject.file(SIGNING_KEY_FILE).exists()
@@ -27,13 +28,14 @@ android {
applicationId "com.eventyay.organizer"
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
- versionCode 14
- versionName "1.4.0"
+ versionCode 15
+ versionName "1.5.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
manifestPlaceholders = [
appName: app_name,
- GOOGLE_PLACES_API_KEY: GOOGLE_PLACES_API_KEY
+ GOOGLE_PLACES_API_KEY: GOOGLE_PLACES_API_KEY,
+ MAPBOX_ACCESS_TOKEN: MAPBOX_ACCESS_TOKEN
]
}
@@ -63,6 +65,7 @@ android {
buildConfigField "String", "DEFAULT_BASE_URL", '"https://api.eventyay.com/v1/"'
resValue "string", "default_base_url", '"https://api.eventyay.com/v1/"'
+ resValue "string", "FRONTEND_HOST", "eventyay.com"
if (LOCAL_KEY_PRESENT || TRAVIS_BUILD)
signingConfig signingConfigs.release
@@ -71,6 +74,7 @@ android {
testCoverageEnabled = true
buildConfigField "String", "DEFAULT_BASE_URL", '"https://open-event-api-dev.herokuapp.com/v1/"'
resValue "string", "default_base_url", '"https://open-event-api-dev.herokuapp.com/v1/"'
+ resValue "string", "FRONTEND_HOST", "open-event-fe.netlify.com"
}
}
@@ -144,7 +148,7 @@ dependencies {
implementation "androidx.appcompat:appcompat:1.1.0-rc01"
implementation "androidx.cardview:cardview:1.0.0"
implementation "androidx.recyclerview:recyclerview:1.1.0-beta01"
- implementation "com.google.android.material:material:1.1.0-alpha07"
+ implementation "com.google.android.material:material:1.1.0-alpha08"
implementation "androidx.browser:browser:1.0.0"
implementation "androidx.palette:palette:1.0.0"
implementation "com.takisoft.fix:preference-v7:${versions.support_lib}.0"
@@ -190,7 +194,7 @@ dependencies {
implementation "com.squareup.retrofit2:retrofit:${versions.retrofit}"
implementation "com.squareup.retrofit2:converter-jackson:${versions.retrofit}"
implementation "com.squareup.retrofit2:adapter-rxjava2:${versions.retrofit}"
- implementation 'com.squareup.okhttp3:logging-interceptor:4.0.0'
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.0.1'
implementation 'com.github.jasminb:jsonapi-converter:0.9'
// RxJava
@@ -255,6 +259,9 @@ dependencies {
// QR Code Scanner
fdroidImplementation 'com.github.blikoon:QRCodeScanner:0.1.2'
+ // Mapbox
+ fdroidImplementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-places-v8:0.9.0'
+
//Testing
androidTestImplementation('androidx.test.espresso:espresso-core:3.2.0', {
exclude group: 'com.android.support', module: 'support-annotations'
@@ -265,7 +272,7 @@ dependencies {
exclude group: 'com.android.support', module: 'support-core-utils'
})
testImplementation 'junit:junit:4.12'
- testImplementation 'org.mockito:mockito-inline:2.28.2'
+ testImplementation 'org.mockito:mockito-inline:3.0.0'
testImplementation 'org.json:json:20180130'
testImplementation "org.robolectric:robolectric:${versions.roboelectric}"
testImplementation "org.robolectric:shadows-multidex:${versions.roboelectric}"
diff --git a/app/src/fdroid/java/com/eventyay/organizer/core/event/create/EventDetailsStepOne.java b/app/src/fdroid/java/com/eventyay/organizer/core/event/create/EventDetailsStepOne.java
index c578b25dd..9213598b1 100644
--- a/app/src/fdroid/java/com/eventyay/organizer/core/event/create/EventDetailsStepOne.java
+++ b/app/src/fdroid/java/com/eventyay/organizer/core/event/create/EventDetailsStepOne.java
@@ -1,24 +1,30 @@
package com.eventyay.organizer.core.event.create;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.lifecycle.ViewModelProviders;
-import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import androidx.databinding.DataBindingUtil;
+import android.graphics.Color;
import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.databinding.DataBindingUtil;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.lifecycle.ViewModelProviders;
+
import com.eventyay.organizer.R;
import com.eventyay.organizer.common.mvp.view.BaseBottomSheetFragment;
import com.eventyay.organizer.data.event.Event;
import com.eventyay.organizer.databinding.EventDetailsStepOneBinding;
+import com.eventyay.organizer.ui.ViewUtils;
+import com.mapbox.api.geocoding.v5.models.CarmenFeature;
+import com.mapbox.mapboxsdk.plugins.places.autocomplete.model.PlaceOptions;
+import com.mapbox.mapboxsdk.plugins.places.autocomplete.ui.PlaceAutocompleteFragment;
+import com.mapbox.mapboxsdk.plugins.places.autocomplete.ui.PlaceSelectionListener;
import java.util.Arrays;
import java.util.List;
@@ -27,8 +33,6 @@
import timber.log.Timber;
-import static android.app.Activity.RESULT_OK;
-
public class EventDetailsStepOne extends BaseBottomSheetFragment implements EventDetailsStepOneView {
@Inject
@@ -36,8 +40,6 @@ public class EventDetailsStepOne extends BaseBottomSheetFragment implements Even
private CreateEventViewModel createEventViewModel;
private EventDetailsStepOneBinding binding;
- private static final int PLACE_PICKER_REQUEST = 1;
- private final LocationPicker locationPicker = new LocationPicker();
public static EventDetailsStepOne newInstance() {
return new EventDetailsStepOne();
@@ -58,7 +60,7 @@ public void onStart() {
int timezoneIndex = createEventViewModel.setTimeZoneList(getTimeZoneList());
setupSpinner();
setDefaultTimeZone(timezoneIndex);
- setupPlacePicker();
+ setupPlacesAutocomplete();
}
private void setupSpinner() {
@@ -82,50 +84,52 @@ public void onNothingSelected(AdapterView> parent) {
});
}
- private void setupPlacePicker() {
- //check if there's a google places API key
+ private void setupPlacesAutocomplete() {
+
+ ApplicationInfo applicationInfo = null;
try {
- ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
- Bundle bundle = ai.metaData;
- String placesApiKey = bundle.getString("com.google.android.geo.API_KEY");
- if ("YOUR_API_KEY".equals(placesApiKey)) {
- Timber.d("Add Google Places API key in AndroidManifest.xml file to use Place Picker.");
- binding.buttonPlacePicker.setVisibility(View.GONE);
- showLocationLayouts();
- }
+ applicationInfo = getContext().getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
- Timber.e(e, "Package name not found");
+ Timber.e(e);
}
+ Bundle bundle = applicationInfo.metaData;
- binding.buttonPlacePicker.setOnClickListener(view -> {
- boolean success = locationPicker.launchPicker(getActivity());
- if (locationPicker.shouldShowLocationLayout() || !success)
- showLocationLayouts();
- });
- }
+ String mapboxAccessToken = bundle.getString(getString(R.string.mapbox_access_token));
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == PLACE_PICKER_REQUEST && resultCode == RESULT_OK) {
- //once place is picked from map, make location fields visible for confirmation by user
- showLocationLayouts();
- //set event attributes
- Location location = locationPicker.getPlace(getActivity(), data);
- Event event = binding.getEvent();
- event.latitude = location.getLatitude();
- event.longitude = location.getLongitude();
-
- //auto-complete location fields for confirmation by user
- binding.locationName.setText(location.getAddress());
- binding.searchableLocationName.setText(
- createEventViewModel.getSearchableLocationName(location.getAddress().toString()));
- }
- }
+ binding.selectLocationButton.setOnClickListener(view -> {
- private void showLocationLayouts() {
- binding.layoutSearchableLocation.setVisibility(View.VISIBLE);
- binding.layoutLocationName.setVisibility(View.VISIBLE);
+ if (mapboxAccessToken.equals("YOUR_ACCESS_TOKEN")) {
+ ViewUtils.showSnackbar(binding.getRoot(), R.string.access_token_required);
+ return;
+ }
+
+ PlaceAutocompleteFragment autocompleteFragment = PlaceAutocompleteFragment.newInstance(
+ mapboxAccessToken, PlaceOptions.builder().backgroundColor(Color.WHITE).build());
+
+ getFragmentManager().beginTransaction()
+ .replace(R.id.fragment, autocompleteFragment)
+ .addToBackStack(null)
+ .commit();
+
+ autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
+ @Override
+ public void onPlaceSelected(CarmenFeature carmenFeature) {
+ Event event = binding.getEvent();
+ event.setLatitude(carmenFeature.center().latitude());
+ event.setLongitude(carmenFeature.center().longitude());
+ event.setLocationName(carmenFeature.placeName());
+ event.setSearchableLocationName(carmenFeature.text());
+ binding.layoutLocationName.setVisibility(View.VISIBLE);
+ binding.locationName.setText(event.getLocationName());
+ getFragmentManager().popBackStack();
+ }
+
+ @Override
+ public void onCancel() {
+ getFragmentManager().popBackStack();
+ }
+ });
+ });
}
@Override
diff --git a/app/src/fdroid/java/com/eventyay/organizer/core/event/create/LocationPicker.java b/app/src/fdroid/java/com/eventyay/organizer/core/event/create/LocationPicker.java
deleted file mode 100644
index 632e33a21..000000000
--- a/app/src/fdroid/java/com/eventyay/organizer/core/event/create/LocationPicker.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.eventyay.organizer.core.event.create;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.Intent;
-
-public class LocationPicker {
-
- private final double DEMO_VALUE = 1;
-
- public boolean launchPicker(Activity activity) {
- //do nothing
- return false;
- }
-
- @SuppressLint("RestrictedApi")
- public Location getPlace(Activity activity, Intent data) {
- return new Location(DEMO_VALUE, DEMO_VALUE, null);
- }
-
- public boolean shouldShowLocationLayout() {
- return true;
- }
-}
diff --git a/app/src/fdroid/java/com/eventyay/organizer/core/event/create/UpdateEventFragment.java b/app/src/fdroid/java/com/eventyay/organizer/core/event/create/UpdateEventFragment.java
index 51554420b..9d202db2f 100644
--- a/app/src/fdroid/java/com/eventyay/organizer/core/event/create/UpdateEventFragment.java
+++ b/app/src/fdroid/java/com/eventyay/organizer/core/event/create/UpdateEventFragment.java
@@ -43,6 +43,10 @@
import com.eventyay.organizer.ui.editor.RichEditorActivity;
import com.eventyay.organizer.utils.Utils;
import com.eventyay.organizer.utils.ValidateUtils;
+import com.mapbox.api.geocoding.v5.models.CarmenFeature;
+import com.mapbox.mapboxsdk.plugins.places.autocomplete.model.PlaceOptions;
+import com.mapbox.mapboxsdk.plugins.places.autocomplete.ui.PlaceAutocompleteFragment;
+import com.mapbox.mapboxsdk.plugins.places.autocomplete.ui.PlaceSelectionListener;
import java.io.FileNotFoundException;
import java.io.InputStream;
@@ -70,11 +74,9 @@ public class UpdateEventFragment extends BaseFragment implements CreateEventView
private ArrayAdapter timezoneAdapter;
private long eventId = -1;
private int countryIndex = -1;
- private final LocationPicker locationPicker = new LocationPicker();
- private static final int PLACE_PICKER_REQUEST = 1;
- private static final int RICH_TEXT_REQUEST = 2;
- private static final int IMAGE_CHOOSER_REQUEST_CODE = 3;
+ private static final int RICH_TEXT_REQUEST = 1;
+ private static final int IMAGE_CHOOSER_REQUEST_CODE = 2;
private CreateEventViewModel createEventViewModel;
public static UpdateEventFragment newInstance() {
@@ -135,7 +137,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
attachCountryList(createEventViewModel.getCountryList());
attachCurrencyCodesList(createEventViewModel.getCurrencyCodesList());
- setupPlacePicker();
+ setupPlacesAutocomplete();
return binding.getRoot();
}
@@ -301,48 +303,58 @@ public List getTimeZoneList() {
return Arrays.asList(getResources().getStringArray(R.array.timezones));
}
- private void setupPlacePicker() {
- //check if there's an google places API key
+ private void setupPlacesAutocomplete() {
+
+ ApplicationInfo applicationInfo = null;
try {
- ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
- Bundle bundle = ai.metaData;
- String placesApiKey = bundle.getString("com.google.android.geo.API_KEY");
- if ("YOUR_API_KEY".equals(placesApiKey)) {
- Timber.d("Add Google Places API key in AndroidManifest.xml file to use Place Picker.");
- binding.form.buttonPlacePicker.setVisibility(View.GONE);
- showLocationLayouts();
- }
+ applicationInfo = getContext().getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
- Timber.e(e, "Package name not found");
+ Timber.e(e);
}
+ Bundle bundle = applicationInfo.metaData;
+
+ String mapboxAccessToken = bundle.getString(getString(R.string.mapbox_access_token));
+
+ binding.form.selectLocationButton.setOnClickListener(view -> {
+
+ if (mapboxAccessToken.equals("YOUR_ACCESS_TOKEN")) {
+ ViewUtils.showSnackbar(binding.getRoot(), R.string.access_token_required);
+ return;
+ }
+
+ PlaceAutocompleteFragment autocompleteFragment = PlaceAutocompleteFragment.newInstance(
+ mapboxAccessToken, PlaceOptions.builder().backgroundColor(Color.WHITE).build());
+
+ getFragmentManager().beginTransaction()
+ .replace(R.id.fragment, autocompleteFragment)
+ .addToBackStack(null)
+ .commit();
+
+ autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
+ @Override
+ public void onPlaceSelected(CarmenFeature carmenFeature) {
+ Event event = binding.getEvent();
+ event.setLatitude(carmenFeature.center().latitude());
+ event.setLongitude(carmenFeature.center().longitude());
+ event.setLocationName(carmenFeature.placeName());
+ event.setSearchableLocationName(carmenFeature.text());
+ binding.form.layoutLocationName.setVisibility(View.VISIBLE);
+ binding.form.locationName.setText(event.getLocationName());
+ getFragmentManager().popBackStack();
+ }
- binding.form.buttonPlacePicker.setOnClickListener(view -> {
- boolean success = locationPicker.launchPicker(getActivity());
- if (locationPicker.shouldShowLocationLayout() || !success)
- showLocationLayouts();
+ @Override
+ public void onCancel() {
+ getFragmentManager().popBackStack();
+ }
+ });
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == PLACE_PICKER_REQUEST && resultCode == RESULT_OK) {
- //once place is picked from map, make location fields visible for confirmation by user
- showLocationLayouts();
- //set event attributes
-
- Location location = locationPicker.getPlace(getActivity(), data);
-
- Event event = binding.getEvent();
- event.latitude = location.getLatitude();
- event.longitude = location.getLongitude();
- //auto-complete location fields for confirmation by user
-
- binding.form.locationName.setText(location.getAddress());
- binding.form.searchableLocationName.setText(
- createEventViewModel.getSearchableLocationName(location.getAddress().toString())
- );
- } else if (requestCode == RICH_TEXT_REQUEST && resultCode == RESULT_OK) {
+ if (requestCode == RICH_TEXT_REQUEST && resultCode == RESULT_OK) {
String description = data.getStringExtra(TAG_RICH_TEXT);
if (!TextUtils.isEmpty(description)) {
createEventViewModel.getEvent().setDescription(description);
@@ -365,11 +377,6 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
}
- private void showLocationLayouts() {
- binding.form.layoutSearchableLocation.setVisibility(View.VISIBLE);
- binding.form.layoutLocationName.setVisibility(View.VISIBLE);
- }
-
@Override
public void setEvent(Event event) {
binding.setEvent(event);
diff --git a/app/src/fdroid/res/layout/event_create_form.xml b/app/src/fdroid/res/layout/event_create_form.xml
index 9eef94f38..2df09edb0 100644
--- a/app/src/fdroid/res/layout/event_create_form.xml
+++ b/app/src/fdroid/res/layout/event_create_form.xml
@@ -236,51 +236,21 @@
android:textStyle="bold" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="wrap_content" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:padding="@dimen/spacing_extra_small" />
-
+ android:exported="false" />
+
+
+
+
+
+
+
+
+ android:theme="@style/AppTheme.Main.Light" />
+ android:theme="@style/AppTheme.Main.Light" />
+ android:theme="@style/AppTheme.Main.Light" />
-
+
+
+
+
+
+
+
+
+
+
+
-
+
+ android:theme="@style/AppTheme.Main.Light" />
+ android:value="${GOOGLE_PLACES_API_KEY}" />
+
+
diff --git a/app/src/main/java/com/eventyay/organizer/common/Constants.java b/app/src/main/java/com/eventyay/organizer/common/Constants.java
index 4331fbe19..7adaa2dd1 100644
--- a/app/src/main/java/com/eventyay/organizer/common/Constants.java
+++ b/app/src/main/java/com/eventyay/organizer/common/Constants.java
@@ -26,6 +26,7 @@ public final class Constants {
public static final String PREF_SCAN_WILL_CHECK_OUT = "check_out";
public static final String PREF_SCAN_WILL_VALIDATE = "validate";
public static final String PREF_USER_EMAIL = "user_email";
+ public static final String PREF_PLAY_SOUNDS = "play_sounds";
private Constants() {
// Never Called
diff --git a/app/src/main/java/com/eventyay/organizer/core/attendee/list/AttendeesFragment.java b/app/src/main/java/com/eventyay/organizer/core/attendee/list/AttendeesFragment.java
index 20faf60bf..a2625882e 100644
--- a/app/src/main/java/com/eventyay/organizer/core/attendee/list/AttendeesFragment.java
+++ b/app/src/main/java/com/eventyay/organizer/core/attendee/list/AttendeesFragment.java
@@ -1,33 +1,28 @@
package com.eventyay.organizer.core.attendee.list;
import android.content.Context;
-
-import androidx.databinding.DataBindingUtil;
-
import android.graphics.PorterDuff;
import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
-import com.eventyay.organizer.BR;
-import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
-
+import androidx.appcompat.widget.SearchView;
+import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import androidx.appcompat.widget.SearchView;
-import androidx.recyclerview.widget.ItemTouchHelper;
-
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+import com.eventyay.organizer.BR;
import com.eventyay.organizer.R;
import com.eventyay.organizer.common.mvp.view.BaseFragment;
import com.eventyay.organizer.core.attendee.ScanningDecider;
@@ -39,6 +34,7 @@
import com.eventyay.organizer.databinding.FragmentAttendeesBinding;
import com.eventyay.organizer.ui.ViewUtils;
import com.eventyay.organizer.utils.SearchUtils;
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.mikepenz.fastadapter.FastAdapter;
import com.mikepenz.fastadapter.adapters.ItemAdapter;
import com.mikepenz.fastadapter.utils.ComparableItemListImpl;
@@ -58,6 +54,10 @@
@SuppressWarnings("PMD.TooManyMethods")
public class AttendeesFragment extends BaseFragment implements AttendeesView {
+ private static final int SORTBYTICKET = 1;
+ private static final int SORTBYNAME = 0;
+ private static final long ITEMS_PER_PAGE = 20;
+
private Context context;
private long eventId;
@@ -68,9 +68,6 @@ public class AttendeesFragment extends BaseFragment implements AttendeesView {
@Inject
ViewModelProvider.Factory viewModelFactory;
- private static final int SORTBYTICKET = 1;
- private static final int SORTBYNAME = 0;
-
private FastAdapter fastAdapter;
private final ScanningDecider scanningDecider = new ScanningDecider();
@@ -261,8 +258,13 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
binding.fabScanQr.hide();
if (!recyclerView.canScrollVertically(1)) {
+
+ if (recyclerView.getAdapter().getItemCount() > currentPage * ITEMS_PER_PAGE) {
+ currentPage++;
+ } else {
currentPage++;
attendeesViewModel.loadAttendeesPageWise(currentPage, true);
+ }
}
}
@@ -297,16 +299,10 @@ private void setupRefreshListener() {
refreshLayout.setRefreshing(false);
attendeeList.clear();
attendeesViewModel.loadAttendeesPageWise(FIRST_PAGE, true);
+ currentPage = FIRST_PAGE;
});
}
- @Override
- public void onResume() {
- super.onResume();
- attendeeList.clear();
- attendeesViewModel.loadAttendeesPageWise(FIRST_PAGE, false);
- }
-
// View Implementation
@Override
diff --git a/app/src/main/java/com/eventyay/organizer/core/attendee/list/AttendeesViewModel.java b/app/src/main/java/com/eventyay/organizer/core/attendee/list/AttendeesViewModel.java
index 9cc770985..c2d59b4c4 100644
--- a/app/src/main/java/com/eventyay/organizer/core/attendee/list/AttendeesViewModel.java
+++ b/app/src/main/java/com/eventyay/organizer/core/attendee/list/AttendeesViewModel.java
@@ -9,6 +9,7 @@
import com.eventyay.organizer.common.ContextManager;
import com.eventyay.organizer.common.livedata.SingleEventLiveData;
import com.eventyay.organizer.common.rx.Logger;
+import com.eventyay.organizer.data.Preferences;
import com.eventyay.organizer.data.attendee.Attendee;
import com.eventyay.organizer.data.attendee.AttendeeRepository;
import com.eventyay.organizer.data.db.DatabaseChangeListener;
@@ -30,6 +31,7 @@ public class AttendeesViewModel extends ViewModel {
private final AttendeeRepository attendeeRepository;
private final DatabaseChangeListener attendeeListener;
+ private final Preferences preferences;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
private final List attendeeList = new ArrayList<>();
@@ -40,14 +42,14 @@ public class AttendeesViewModel extends ViewModel {
private final SingleEventLiveData showScanButtonLiveData = new SingleEventLiveData<>();
private final SingleEventLiveData updateAttendeeLiveData = new SingleEventLiveData<>();
- private final long FIRST_PAGE = 1;
-
private long eventId;
@Inject
- public AttendeesViewModel(AttendeeRepository attendeeRepository, DatabaseChangeListener attendeeListener) {
+ public AttendeesViewModel(AttendeeRepository attendeeRepository, DatabaseChangeListener attendeeListener,
+ Preferences preferences) {
this.attendeeRepository = attendeeRepository;
this.attendeeListener = attendeeListener;
+ this.preferences = preferences;
eventId = ContextManager.getSelectedEvent().getId();
}
@@ -76,6 +78,10 @@ public List getAttendees() {
return attendeeList;
}
+ public Preferences getPreferences() {
+ return preferences;
+ }
+
public void loadAttendees(boolean forceReload) {
showScanButtonLiveData.setValue(false);
@@ -137,7 +143,6 @@ public void listenChanges() {
.map(DbFlowDatabaseChangeListener.ModelChange::getModel)
.flatMap(filterAttendee -> attendeeRepository.getAttendee(filterAttendee.getId(), false))
.subscribe(attendee -> {
- loadAttendeesPageWise(FIRST_PAGE, false);
updateAttendeeLiveData.setValue(attendee);
updateLocal(attendee);
}, Logger::logError);
diff --git a/app/src/main/java/com/eventyay/organizer/core/attendee/list/SwipeController.java b/app/src/main/java/com/eventyay/organizer/core/attendee/list/SwipeController.java
index 31f1ffb3f..62751919e 100644
--- a/app/src/main/java/com/eventyay/organizer/core/attendee/list/SwipeController.java
+++ b/app/src/main/java/com/eventyay/organizer/core/attendee/list/SwipeController.java
@@ -8,9 +8,12 @@
import android.graphics.RectF;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper;
+
+import android.media.MediaPlayer;
import android.view.View;
import com.eventyay.organizer.R;
+import com.eventyay.organizer.common.Constants;
import com.eventyay.organizer.data.attendee.Attendee;
import java.util.List;
@@ -19,21 +22,26 @@ public class SwipeController extends ItemTouchHelper.SimpleCallback {
private final AttendeesViewModel attendeesViewModel;
private List attendeeList;
+ private final Context context;
private final Paint paintGreen = new Paint();
private final Paint paintRed = new Paint();
private final Bitmap closeIcon;
private final Bitmap doneIcon;
+ private final boolean playSound;
public SwipeController(AttendeesViewModel attendeesViewModel, List attendeeList, Context context) {
super(0, ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT);
this.attendeesViewModel = attendeesViewModel;
this.attendeeList = attendeeList;
+ this.context = context;
closeIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.close);
doneIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.done);
paintGreen.setColor(context.getResources().getColor(R.color.light_green_500));
paintRed.setColor(context.getResources().getColor(R.color.red_500));
+
+ playSound = attendeesViewModel.getPreferences().getBoolean(Constants.PREF_PLAY_SOUNDS, false);
}
@Override
@@ -57,6 +65,11 @@ public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder v
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int swipedPosition = viewHolder.getAdapterPosition();
attendeesViewModel.toggleCheckInState(attendeeList, swipedPosition);
+
+ if (playSound) {
+ MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.check_in_sound);
+ mediaPlayer.start();
+ }
}
@Override
diff --git a/app/src/main/java/com/eventyay/organizer/core/auth/AuthActivity.java b/app/src/main/java/com/eventyay/organizer/core/auth/AuthActivity.java
index 2d16d3198..db59e9b73 100644
--- a/app/src/main/java/com/eventyay/organizer/core/auth/AuthActivity.java
+++ b/app/src/main/java/com/eventyay/organizer/core/auth/AuthActivity.java
@@ -1,5 +1,7 @@
package com.eventyay.organizer.core.auth;
+import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
@@ -7,7 +9,9 @@
import androidx.appcompat.widget.Toolbar;
import com.eventyay.organizer.R;
+import com.eventyay.organizer.core.auth.reset.ResetPasswordFragment;
import com.eventyay.organizer.core.auth.start.StartFragment;
+import com.eventyay.organizer.utils.LinkHandler;
import javax.inject.Inject;
@@ -41,6 +45,30 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
.replace(R.id.fragment_container, new StartFragment())
.commit();
}
+
+ handleIntent(getIntent());
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ handleIntent(intent);
+ }
+
+ private void handleIntent(Intent intent) {
+ String appLinkAction = intent.getAction();
+ Uri appLinkData = intent.getData();
+
+ if (Intent.ACTION_VIEW.equals(appLinkAction) && appLinkData != null){
+ LinkHandler.Destination destination = LinkHandler.getDestinationAndToken(appLinkData.toString()).getDestination();
+ String token = LinkHandler.getDestinationAndToken(appLinkData.toString()).getToken();
+
+ if (destination.equals(LinkHandler.Destination.RESET_PASSWORD)) {
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.fragment_container, ResetPasswordFragment.newInstance(token))
+ .commit();
+ }
+ }
}
@Override
diff --git a/app/src/main/java/com/eventyay/organizer/core/auth/reset/ResetPasswordFragment.java b/app/src/main/java/com/eventyay/organizer/core/auth/reset/ResetPasswordFragment.java
index fc9dee1e4..c4a5a5b38 100644
--- a/app/src/main/java/com/eventyay/organizer/core/auth/reset/ResetPasswordFragment.java
+++ b/app/src/main/java/com/eventyay/organizer/core/auth/reset/ResetPasswordFragment.java
@@ -1,14 +1,16 @@
package com.eventyay.organizer.core.auth.reset;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.lifecycle.ViewModelProviders;
-import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
+import androidx.annotation.Nullable;
+import androidx.databinding.DataBindingUtil;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.lifecycle.ViewModelProviders;
+
import com.eventyay.organizer.R;
import com.eventyay.organizer.common.mvp.view.BaseFragment;
import com.eventyay.organizer.core.auth.SharedViewModel;
@@ -23,6 +25,8 @@
public class ResetPasswordFragment extends BaseFragment implements ResetPasswordView {
+ private static final String TOKEN_KEY = "token";
+
@Inject
ViewModelProvider.Factory viewModelFactory;
@@ -30,10 +34,28 @@ public class ResetPasswordFragment extends BaseFragment implements ResetPassword
private ResetPasswordByTokenFragmentBinding binding;
private Validator validator;
+ private String token;
+
public static ResetPasswordFragment newInstance() {
return new ResetPasswordFragment();
}
+ public static ResetPasswordFragment newInstance(String token) {
+ ResetPasswordFragment fragment = new ResetPasswordFragment();
+ Bundle args = new Bundle();
+ args.putString(TOKEN_KEY, token);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (getArguments() != null)
+ token = getArguments().getString(TOKEN_KEY);
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@@ -57,6 +79,9 @@ public void onStart() {
resetPasswordViewModel.setBaseUrl();
+ if (token != null)
+ resetPasswordViewModel.setToken(token);
+
binding.btnResetPassword.setOnClickListener(view -> {
if (!validator.validate())
return;
diff --git a/app/src/main/java/com/eventyay/organizer/core/auth/reset/ResetPasswordViewModel.java b/app/src/main/java/com/eventyay/organizer/core/auth/reset/ResetPasswordViewModel.java
index a3a377bc5..28458c44e 100644
--- a/app/src/main/java/com/eventyay/organizer/core/auth/reset/ResetPasswordViewModel.java
+++ b/app/src/main/java/com/eventyay/organizer/core/auth/reset/ResetPasswordViewModel.java
@@ -75,6 +75,10 @@ public void requestToken(String email) {
throwable -> error.setValue(ErrorUtils.getMessage(throwable).toString())));
}
+ public void setToken(String token) {
+ submitToken.setToken(token);
+ }
+
public LiveData getError() {
return error;
}
diff --git a/app/src/main/java/com/eventyay/organizer/core/event/list/EventListFragment.java b/app/src/main/java/com/eventyay/organizer/core/event/list/EventListFragment.java
index 588799757..39c3581fb 100644
--- a/app/src/main/java/com/eventyay/organizer/core/event/list/EventListFragment.java
+++ b/app/src/main/java/com/eventyay/organizer/core/event/list/EventListFragment.java
@@ -25,6 +25,7 @@
import com.eventyay.organizer.data.ContextUtils;
import com.eventyay.organizer.databinding.EventListFragmentBinding;
import com.eventyay.organizer.ui.ViewUtils;
+import com.google.android.material.appbar.AppBarLayout;
import javax.inject.Inject;
@@ -36,6 +37,9 @@
*
*/
public class EventListFragment extends BaseFragment implements EventsView {
+
+ private static final int ACTION_BAR_ELEVATION = 4;
+
@Inject
ContextUtils utilModel;
@@ -46,6 +50,7 @@ public class EventListFragment extends BaseFragment implements EventsView {
private EventListFragmentBinding binding;
private SwipeRefreshLayout refreshLayout;
+ private AppBarLayout appBarLayout;
public static final String[] EVENT_TYPE = {"live", "past", "draft"};
public static final String POSITION = "position";
@@ -60,6 +65,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
// Inflate the layout for this fragment
binding = DataBindingUtil.inflate(inflater, R.layout.event_list_fragment, container, false);
+ appBarLayout = getActivity().findViewById(R.id.main_app_bar);
+
eventsViewModel = ViewModelProviders.of(getActivity(), viewModelFactory).get(EventsViewModel.class);
eventsViewModel.getSuccess().observe(this, this::onRefreshComplete);
eventsViewModel.getError().observe(this, this::showError);
@@ -110,6 +117,8 @@ public CharSequence getPageTitle(int position) {
public void onStart() {
super.onStart();
setupRefreshListener();
+ appBarLayout.setElevation(0);
+ appBarLayout.setStateListAnimator(null);
}
@Override
@@ -135,6 +144,7 @@ public void openNotificationsFragment() {
public void onStop() {
super.onStop();
refreshLayout.setOnRefreshListener(null);
+ appBarLayout.setElevation(ViewUtils.dpToPx(getContext(), ACTION_BAR_ELEVATION));
}
private void setupRefreshListener() {
diff --git a/app/src/main/java/com/eventyay/organizer/core/main/DrawerNavigator.java b/app/src/main/java/com/eventyay/organizer/core/main/DrawerNavigator.java
index 807b7f329..5ad323652 100644
--- a/app/src/main/java/com/eventyay/organizer/core/main/DrawerNavigator.java
+++ b/app/src/main/java/com/eventyay/organizer/core/main/DrawerNavigator.java
@@ -53,9 +53,9 @@ void selectItem(MenuItem item) {
Intent intent = new Intent(context, AboutEventActivity.class);
intent.putExtra(AboutEventActivity.EVENT_ID, fragmentNavigator.getEventId());
context.startActivity(intent);
- } else if (id == R.id.nav_suggestion) {
+ } /*else if (id == R.id.nav_suggestion) {
BrowserUtils.launchUrl(context, GOOGLE_FORM_LINK);
- } else
+ }*/ else
fragmentNavigator.loadFragment(id);
}
diff --git a/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailActivity.java b/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailActivity.java
index 235ceb170..47842edff 100644
--- a/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailActivity.java
+++ b/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailActivity.java
@@ -1,5 +1,7 @@
package com.eventyay.organizer.core.organizer.detail;
+import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@@ -8,6 +10,7 @@
import com.eventyay.organizer.R;
import com.eventyay.organizer.core.organizer.update.UpdateOrganizerInfoFragment;
+import com.eventyay.organizer.utils.LinkHandler;
import javax.inject.Inject;
@@ -34,6 +37,30 @@ protected void onCreate(Bundle savedInstanceState) {
.replace(R.id.fragment, new OrganizerDetailFragment())
.commit();
}
+
+ handleIntent(getIntent());
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ handleIntent(intent);
+ }
+
+ private void handleIntent(Intent intent) {
+ String appLinkAction = intent.getAction();
+ Uri appLinkData = intent.getData();
+
+ if (Intent.ACTION_VIEW.equals(appLinkAction) && appLinkData != null) {
+ LinkHandler.Destination destination = LinkHandler.getDestinationAndToken(appLinkData.toString()).getDestination();
+ String token = LinkHandler.getDestinationAndToken(appLinkData.toString()).getToken();
+
+ if (destination.equals(LinkHandler.Destination.VERIFY_EMAIL)) {
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.fragment, OrganizerDetailFragment.newInstance(token))
+ .commit();
+ }
+ }
}
@Override
diff --git a/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailFragment.java b/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailFragment.java
index 69cacd55c..fba70df41 100644
--- a/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailFragment.java
+++ b/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailFragment.java
@@ -1,5 +1,6 @@
package com.eventyay.organizer.core.organizer.detail;
+import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import android.content.Intent;
@@ -47,9 +48,13 @@
public class OrganizerDetailFragment extends BaseFragment implements OrganizerDetailView {
+ private static final String TOKEN_KEY = "token";
+
private OrganizerDetailFragmentBinding binding;
private SwipeRefreshLayout refreshLayout;
+ private String token;
+
@Inject
ContextUtils utilModel;
@@ -62,6 +67,22 @@ public class OrganizerDetailFragment extends BaseFragment implements OrganizerDe
private static final int IMAGE_CHOOSER_REQUEST_CODE = 3;
+ public static OrganizerDetailFragment newInstance(String token) {
+ OrganizerDetailFragment fragment = new OrganizerDetailFragment();
+ Bundle args = new Bundle();
+ args.putString(TOKEN_KEY, token);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (getArguments() != null)
+ token = getArguments().getString(TOKEN_KEY);
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.organizer_detail_fragment, container, false);
@@ -152,6 +173,11 @@ public void onStart() {
organizerDetailViewModel.getError().observe(this, this::showError);
organizerDetailViewModel.getUserLiveData().observe(this, this::setUser);
binding.setUser(organizerDetailViewModel.getUser());
+
+ if (token != null) {
+ organizerDetailViewModel.setToken(token);
+ organizerDetailViewModel.verifyMail();
+ }
}
@Override
diff --git a/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailViewModel.java b/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailViewModel.java
index 13951bde8..68ab1f059 100644
--- a/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailViewModel.java
+++ b/app/src/main/java/com/eventyay/organizer/core/organizer/detail/OrganizerDetailViewModel.java
@@ -6,6 +6,7 @@
import com.eventyay.organizer.common.livedata.SingleEventLiveData;
import com.eventyay.organizer.data.auth.AuthService;
import com.eventyay.organizer.data.auth.model.ResendVerificationMail;
+import com.eventyay.organizer.data.auth.model.SubmitEmailVerificationToken;
import com.eventyay.organizer.data.image.ImageData;
import com.eventyay.organizer.data.user.User;
import com.eventyay.organizer.data.user.UserRepository;
@@ -22,6 +23,7 @@ public class OrganizerDetailViewModel extends ViewModel {
private final UserRepository userRepository;
private final AuthService authService;
private final ResendVerificationMail resendVerificationMail = new ResendVerificationMail();
+ private final SubmitEmailVerificationToken submitEmailVerificationToken = new SubmitEmailVerificationToken();
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
@@ -58,6 +60,10 @@ public LiveData getUserLiveData() {
return userLiveData;
}
+ public void setToken(String token) {
+ submitEmailVerificationToken.setToken(token);
+ }
+
public void loadOrganizer(boolean forceReload) {
compositeDisposable.add(
getOrganizerSource(forceReload)
@@ -83,6 +89,18 @@ public void resendVerificationMail() {
}));
}
+ public void verifyMail() {
+ compositeDisposable.add(
+ authService.verifyMail(submitEmailVerificationToken)
+ .doOnSubscribe(disposable -> progress.setValue(true))
+ .doFinally(() -> progress.setValue(false))
+ .subscribe(() -> success.setValue("Mail Verified"),
+ throwable -> {
+ error.setValue(ErrorUtils.getErrorDetails(throwable).toString());
+ Timber.e(throwable, "An exception occurred : %s", throwable.getMessage());
+ }));
+ }
+
//Method for storing user uploaded image in temporary location
public void uploadImage(ImageData imageData) {
compositeDisposable.add(
diff --git a/app/src/main/java/com/eventyay/organizer/core/organizer/update/UpdateOrganizerInfoFragment.java b/app/src/main/java/com/eventyay/organizer/core/organizer/update/UpdateOrganizerInfoFragment.java
index bf9e134cc..2beae0e8a 100644
--- a/app/src/main/java/com/eventyay/organizer/core/organizer/update/UpdateOrganizerInfoFragment.java
+++ b/app/src/main/java/com/eventyay/organizer/core/organizer/update/UpdateOrganizerInfoFragment.java
@@ -79,13 +79,6 @@ public void onStart() {
updateOrganizerInfoViewModel.getError().observe(this, this::showError);
updateOrganizerInfoViewModel.getUserLiveData().observe(this, this::setUser);
updateOrganizerInfoViewModel.loadUser();
- validate(binding.form.holderAvatarUrl, ValidateUtils::validateUrl, getResources().getString(R.string.url_validation_error));
- validate(binding.form.holderTwitterUrl, ValidateUtils::validateUrl, getResources().getString(R.string.url_validation_error));
- validate(binding.form.holderFacebookUrl, ValidateUtils::validateUrl, getResources().getString(R.string.url_validation_error));
- validate(binding.form.holderInstragramUrl, ValidateUtils::validateUrl, getResources().getString(R.string.url_validation_error));
- validate(binding.form.holderThumbnailImageUrl, ValidateUtils::validateUrl, getResources().getString(R.string.url_validation_error));
- validate(binding.form.holderGooglePlusUrl, ValidateUtils::validateUrl, getResources().getString(R.string.url_validation_error));
- validate(binding.form.holderIconImageUrl, ValidateUtils::validateUrl, getResources().getString(R.string.url_validation_error));
}
@Override
diff --git a/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListAdapter.java b/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListAdapter.java
index 932d55444..0ed059fbd 100644
--- a/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListAdapter.java
+++ b/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListAdapter.java
@@ -30,6 +30,8 @@ public RoleViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int posit
DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()),
R.layout.role_item, viewGroup, false), roleListViewModel);
+ roleViewHolder.setLongClickAction(roleListViewModel::onLongSelect);
+
return roleViewHolder;
}
diff --git a/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListFragment.java b/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListFragment.java
index 65b98cd92..92698ff7b 100644
--- a/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListFragment.java
+++ b/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListFragment.java
@@ -1,8 +1,10 @@
package com.eventyay.organizer.core.role.list;
import android.content.Context;
+import android.os.Build;
import android.os.Bundle;
+import androidx.appcompat.app.AlertDialog;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
@@ -11,7 +13,11 @@
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+import android.view.ActionMode;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -42,6 +48,9 @@ public class RoleListFragment extends BaseFragment implements RoleListView {
private RoleListAdapter rolesAdapter;
private RolesFragmentBinding binding;
private SwipeRefreshLayout refreshLayout;
+ private ActionMode actionMode;
+ private int statusBarColor;
+ private AlertDialog deleteDialog;
private RoleListViewModel roleListViewModel;
@@ -69,7 +78,10 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
binding = DataBindingUtil.inflate(inflater, R.layout.roles_fragment, container, false);
roleListViewModel = ViewModelProviders.of(this, viewModelFactory).get(RoleListViewModel.class);
- binding.createRoleFab.setOnClickListener(v -> openRoleInviteFragment());
+ binding.createRoleFab.setOnClickListener(v -> {
+ roleListViewModel.resetToDefaultState();
+ openRoleInviteFragment();
+ });
return binding.getRoot();
}
@@ -83,6 +95,8 @@ public void onStart() {
roleListViewModel.getSuccess().observe(this, this::showMessage);
roleListViewModel.getError().observe(this, this::showError);
roleListViewModel.getRolesLiveData().observe(this, this::showResults);
+ roleListViewModel.getExitContextualMenuModeLiveData().observe(this, (exitContextualMenuMode) -> exitContextualMenuMode());
+ roleListViewModel.getEnterContextualMenuModeLiveData().observe(this, (enterContextualMenuMode) -> enterContextualMenuMode());
roleListViewModel.loadRoles(false);
roleListViewModel.listenChanges();
}
@@ -121,6 +135,78 @@ public void openRoleInviteFragment() {
.commit();
}
+ public ActionMode.Callback actionCallback = new ActionMode.Callback() {
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ MenuInflater inflater = mode.getMenuInflater();
+ inflater.inflate(R.menu.menu_roles, menu);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ // Hold current color of status bar
+ statusBarColor = getActivity().getWindow().getStatusBarColor();
+ // Set the default color
+ getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.color_top_surface));
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ return true;
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.delete:
+ showDeleteDialog();
+ break;
+ default:
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ actionMode.finish();
+ roleListViewModel.resetToDefaultState();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ // Return to old color of status bar
+ getActivity().getWindow().setStatusBarColor(statusBarColor);
+ }
+ }
+ };
+
+ public void showDeleteDialog() {
+ if (deleteDialog == null)
+ deleteDialog = new AlertDialog.Builder(context)
+ .setTitle(R.string.delete)
+ .setMessage(String.format(getString(R.string.delete_confirmation_message),
+ getString(R.string.roles)))
+ .setPositiveButton(R.string.ok, (dialog, which) -> {
+ roleListViewModel.deleteSelectedRole();
+ roleListViewModel.resetToDefaultState();
+ exitContextualMenuMode();
+ })
+ .setNegativeButton(R.string.cancel, (dialog, which) -> {
+ dialog.dismiss();
+ })
+ .create();
+
+ deleteDialog.show();
+ }
+
+ @Override
+ public void enterContextualMenuMode() {
+ actionMode = getActivity().startActionMode(actionCallback);
+ }
+
+ @Override
+ public void exitContextualMenuMode() {
+ if (actionMode != null)
+ actionMode.finish();
+ }
+
@Override
protected int getTitle() {
return R.string.roles;
diff --git a/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListView.java b/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListView.java
index 4d7b35b74..1e1d688db 100644
--- a/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListView.java
+++ b/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListView.java
@@ -15,4 +15,8 @@ public interface RoleListView {
void showResults(List items);
void showEmptyView(boolean show);
+
+ void exitContextualMenuMode();
+
+ void enterContextualMenuMode();
}
diff --git a/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListViewModel.java b/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListViewModel.java
index 2cd6e1c0e..c277b415b 100644
--- a/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListViewModel.java
+++ b/app/src/main/java/com/eventyay/organizer/core/role/list/RoleListViewModel.java
@@ -1,5 +1,6 @@
package com.eventyay.organizer.core.role.list;
+import androidx.databinding.ObservableBoolean;
import androidx.lifecycle.LiveData;
import com.eventyay.organizer.common.livedata.SingleEventLiveData;
import androidx.lifecycle.ViewModel;
@@ -15,6 +16,8 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
@@ -27,12 +30,17 @@ public class RoleListViewModel extends ViewModel {
private final List roles = new ArrayList<>();
private final RoleRepository roleRepository;
private final DatabaseChangeListener roleListChangeListener;
+ private final Map selectedMap = new ConcurrentHashMap<>();
+ private RoleInvite previousRole = new RoleInvite();
+ private boolean isContextualModeActive;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
private final SingleEventLiveData progress = new SingleEventLiveData<>();
private final SingleEventLiveData error = new SingleEventLiveData<>();
private final SingleEventLiveData success = new SingleEventLiveData<>();
private final SingleEventLiveData> rolesLiveData = new SingleEventLiveData<>();
+ private final SingleEventLiveData exitContextualMenuMode = new SingleEventLiveData<>();
+ private final SingleEventLiveData enterContextualMenuMode = new SingleEventLiveData<>();
private long eventId;
@@ -58,6 +66,18 @@ public LiveData> getRolesLiveData() {
return rolesLiveData;
}
+ public LiveData getExitContextualMenuModeLiveData() {
+ return exitContextualMenuMode;
+ }
+
+ public LiveData getEnterContextualMenuModeLiveData() {
+ return enterContextualMenuMode;
+ }
+
+ public Map getSelectedMap() {
+ return selectedMap;
+ }
+
public DatabaseChangeListener getRoleListChangeListener() {
return roleListChangeListener;
}
@@ -91,7 +111,7 @@ public void listenChanges() {
roleListChangeListener.startListening();
roleListChangeListener.getNotifier()
.map(DbFlowDatabaseChangeListener.ModelChange::getAction)
- .filter(action -> action.equals(BaseModel.Action.INSERT))
+ .filter(action -> action.equals(BaseModel.Action.INSERT) || action.equals(BaseModel.Action.DELETE))
.subscribeOn(Schedulers.io())
.subscribe(roleModelChange -> loadRoles(false), Logger::logError);
}
@@ -99,4 +119,69 @@ public void listenChanges() {
public List getRoles() {
return roles;
}
+
+ public void deleteRole(RoleInvite role) {
+ roleRepository
+ .deleteRole(role.getId())
+ .doOnSubscribe(disposable -> progress.setValue(true))
+ .doFinally(() -> progress.setValue(false))
+ .subscribe(() -> {
+ selectedMap.remove(role);
+ loadRoles(true);
+ Logger.logSuccess(role);
+ }, Logger::logError);
+ }
+
+ public void deleteSelectedRole() {
+ Observable.fromIterable(selectedMap.entrySet())
+ .doOnSubscribe(disposable -> progress.setValue(true))
+ .doFinally(() -> progress.setValue(false))
+ .subscribe(entry -> {
+ if (entry.getValue().get()) {
+ deleteRole(entry.getKey());
+ }
+ success.setValue("Deleted Successfully");
+ }, Logger::logError);
+ }
+
+ public void unselectRole(RoleInvite role) {
+ if (role != null && selectedMap.containsKey(role))
+ selectedMap.get(role).set(false);
+ }
+
+ public void resetToDefaultState() {
+ isContextualModeActive = false;
+ unSelectRoleList();
+ exitContextualMenuMode.call();
+ }
+
+ public void onLongSelect(RoleInvite currentRole) {
+ getRoleSelected(currentRole);
+ if (!isContextualModeActive) {
+ enterContextualMenuMode.call();
+ }
+ if (!previousRole.equals(currentRole)) {
+ unselectRole(previousRole);
+ }
+ selectedMap.get(currentRole).set(true);
+ previousRole = currentRole;
+ isContextualModeActive = true;
+ }
+
+ public ObservableBoolean getRoleSelected(RoleInvite role) {
+ if (!selectedMap.containsKey(role)) {
+ selectedMap.put(role, new ObservableBoolean(false));
+ }
+ return selectedMap.get(role);
+ }
+
+ public Map getIsSelected() {
+ return selectedMap;
+ }
+
+ public void unSelectRoleList() {
+ for (RoleInvite role : selectedMap.keySet()) {
+ unselectRole(role);
+ }
+ }
}
diff --git a/app/src/main/java/com/eventyay/organizer/core/role/list/viewholder/RoleViewHolder.java b/app/src/main/java/com/eventyay/organizer/core/role/list/viewholder/RoleViewHolder.java
index af12d085d..8c1fc5451 100644
--- a/app/src/main/java/com/eventyay/organizer/core/role/list/viewholder/RoleViewHolder.java
+++ b/app/src/main/java/com/eventyay/organizer/core/role/list/viewholder/RoleViewHolder.java
@@ -2,6 +2,7 @@
import androidx.recyclerview.widget.RecyclerView;
+import com.eventyay.organizer.common.Pipe;
import com.eventyay.organizer.core.role.list.RoleListViewModel;
import com.eventyay.organizer.data.role.RoleInvite;
import com.eventyay.organizer.databinding.RoleItemBinding;
@@ -10,14 +11,29 @@ public class RoleViewHolder extends RecyclerView.ViewHolder {
private final RoleItemBinding binding;
private final RoleListViewModel roleListViewModel;
+ private RoleInvite role;
+
+ private Pipe longClickAction;
public RoleViewHolder(RoleItemBinding binding, RoleListViewModel roleListViewModel) {
super(binding.getRoot());
this.binding = binding;
this.roleListViewModel = roleListViewModel;
+
+ binding.getRoot().setOnLongClickListener(view -> {
+ if (longClickAction != null) {
+ longClickAction.push(role);
+ }
+ return true;
+ });
+ }
+
+ public void setLongClickAction(Pipe longClickAction) {
+ this.longClickAction = longClickAction;
}
public void bind(RoleInvite role) {
+ this.role = role;
binding.setRole(role);
binding.setRoleListViewModel(roleListViewModel);
binding.executePendingBindings();
diff --git a/app/src/main/java/com/eventyay/organizer/core/settings/SettingsFragment.java b/app/src/main/java/com/eventyay/organizer/core/settings/SettingsFragment.java
index e9eb04b4b..29395ebed 100644
--- a/app/src/main/java/com/eventyay/organizer/core/settings/SettingsFragment.java
+++ b/app/src/main/java/com/eventyay/organizer/core/settings/SettingsFragment.java
@@ -9,6 +9,8 @@
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentTransaction;
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import android.view.LayoutInflater;
@@ -50,6 +52,15 @@ public void onCreatePreferencesFix(@Nullable Bundle bundle, String rootKey) {
setPreferencesFromResource(R.xml.preferences, rootKey);
+ CheckBoxPreference playSound = (CheckBoxPreference) findPreference(Constants.PREF_PLAY_SOUNDS);
+
+ Preference.OnPreferenceChangeListener listener = (preference, newValue) -> {
+ playSound.setChecked(!playSound.isChecked());
+ return (Boolean) newValue;
+ };
+
+ playSound.setOnPreferenceChangeListener(listener);
+
findPreference(getString(R.string.sales_data_display_key)).setOnPreferenceClickListener(preference -> {
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, SalesDataSettings.newInstance())
diff --git a/app/src/main/java/com/eventyay/organizer/core/ticket/list/TicketsFragment.java b/app/src/main/java/com/eventyay/organizer/core/ticket/list/TicketsFragment.java
index dccb9705b..395708b79 100644
--- a/app/src/main/java/com/eventyay/organizer/core/ticket/list/TicketsFragment.java
+++ b/app/src/main/java/com/eventyay/organizer/core/ticket/list/TicketsFragment.java
@@ -1,20 +1,18 @@
package com.eventyay.organizer.core.ticket.list;
import android.content.Context;
-import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
import androidx.annotation.Nullable;
-import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersDecoration;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.eventyay.organizer.R;
import com.eventyay.organizer.common.mvp.view.BaseFragment;
@@ -25,6 +23,8 @@
import com.eventyay.organizer.data.ticket.Ticket;
import com.eventyay.organizer.databinding.TicketsFragmentBinding;
import com.eventyay.organizer.ui.ViewUtils;
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
+import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersDecoration;
import java.util.List;
@@ -34,15 +34,12 @@
public class TicketsFragment extends BaseFragment implements TicketsView {
- private Context context;
- private long eventId;
-
@Inject
ContextUtils utilModel;
-
@Inject
Lazy ticketsPresenter;
-
+ private Context context;
+ private long eventId;
private TicketsAdapter ticketsAdapter;
private RecyclerView.AdapterDataObserver adapterDataObserver;
private TicketsFragmentBinding binding;
@@ -69,9 +66,13 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.tickets_fragment, container, false);
+
+ ticketsAdapter = null;
+
binding.createTicketFab.setOnClickListener(view -> {
openCreateTicketFragment();
- });
+ });
+
return binding.getRoot();
}
diff --git a/app/src/main/java/com/eventyay/organizer/data/auth/AuthApi.java b/app/src/main/java/com/eventyay/organizer/data/auth/AuthApi.java
index d3e5e2d69..2feb46b7c 100644
--- a/app/src/main/java/com/eventyay/organizer/data/auth/AuthApi.java
+++ b/app/src/main/java/com/eventyay/organizer/data/auth/AuthApi.java
@@ -6,10 +6,12 @@
import com.eventyay.organizer.data.auth.model.EmailValidationResponse;
import com.eventyay.organizer.data.auth.model.Login;
import com.eventyay.organizer.data.auth.model.LoginResponse;
+import com.eventyay.organizer.data.auth.model.EmailVerificationResponse;
import com.eventyay.organizer.data.auth.model.RequestToken;
import com.eventyay.organizer.data.auth.model.RequestTokenResponse;
import com.eventyay.organizer.data.auth.model.ResendVerificationMail;
import com.eventyay.organizer.data.auth.model.ResendVerificationMailResponse;
+import com.eventyay.organizer.data.auth.model.SubmitEmailVerificationToken;
import com.eventyay.organizer.data.auth.model.SubmitToken;
import com.eventyay.organizer.data.auth.model.SubmitTokenResponse;
import com.eventyay.organizer.data.user.User;
@@ -43,4 +45,7 @@ public interface AuthApi {
@POST("auth/resend-verification-email")
Observable resendMail(@Body ResendVerificationMail resendVerificationMail);
+
+ @POST("auth/verify-email")
+ Observable verifyMail(@Body Map submitMailVerificationToken);
}
diff --git a/app/src/main/java/com/eventyay/organizer/data/auth/AuthService.java b/app/src/main/java/com/eventyay/organizer/data/auth/AuthService.java
index e08fe8e78..03d81a34c 100644
--- a/app/src/main/java/com/eventyay/organizer/data/auth/AuthService.java
+++ b/app/src/main/java/com/eventyay/organizer/data/auth/AuthService.java
@@ -7,6 +7,7 @@
import com.eventyay.organizer.data.auth.model.RequestToken;
import com.eventyay.organizer.data.auth.model.ResendVerificationMail;
import com.eventyay.organizer.data.auth.model.ResendVerificationMailResponse;
+import com.eventyay.organizer.data.auth.model.SubmitEmailVerificationToken;
import com.eventyay.organizer.data.auth.model.SubmitToken;
import com.eventyay.organizer.data.user.User;
@@ -32,4 +33,6 @@ public interface AuthService {
Observable checkEmailRegistered(EmailRequest emailRequest);
Observable resendVerificationMail(ResendVerificationMail resendVerificationMail);
+
+ Completable verifyMail(SubmitEmailVerificationToken submitEmailVerificationToken);
}
diff --git a/app/src/main/java/com/eventyay/organizer/data/auth/AuthServiceImpl.java b/app/src/main/java/com/eventyay/organizer/data/auth/AuthServiceImpl.java
index aedce491e..8dd8c7d87 100644
--- a/app/src/main/java/com/eventyay/organizer/data/auth/AuthServiceImpl.java
+++ b/app/src/main/java/com/eventyay/organizer/data/auth/AuthServiceImpl.java
@@ -8,6 +8,7 @@
import com.eventyay.organizer.data.auth.model.RequestToken;
import com.eventyay.organizer.data.auth.model.ResendVerificationMail;
import com.eventyay.organizer.data.auth.model.ResendVerificationMailResponse;
+import com.eventyay.organizer.data.auth.model.SubmitEmailVerificationToken;
import com.eventyay.organizer.data.auth.model.SubmitToken;
import com.eventyay.organizer.data.user.User;
import com.eventyay.organizer.common.Constants;
@@ -154,4 +155,17 @@ public Observable resendVerificationMail(ResendV
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
+
+ @Override
+ public Completable verifyMail(SubmitEmailVerificationToken token) {
+ if (!repository.isConnected())
+ return Completable.error(new Throwable(Constants.NO_NETWORK));
+
+ return authApi
+ .verifyMail(CustomObjectWrapper.withLabel("data", token))
+ .flatMapCompletable(
+ var -> Completable.complete())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
}
diff --git a/app/src/main/java/com/eventyay/organizer/data/auth/model/EmailVerificationResponse.java b/app/src/main/java/com/eventyay/organizer/data/auth/model/EmailVerificationResponse.java
new file mode 100644
index 000000000..2b12af59a
--- /dev/null
+++ b/app/src/main/java/com/eventyay/organizer/data/auth/model/EmailVerificationResponse.java
@@ -0,0 +1,9 @@
+package com.eventyay.organizer.data.auth.model;
+
+import lombok.Data;
+
+@Data
+public class EmailVerificationResponse {
+
+ public String message;
+}
diff --git a/app/src/main/java/com/eventyay/organizer/data/auth/model/SubmitEmailVerificationToken.java b/app/src/main/java/com/eventyay/organizer/data/auth/model/SubmitEmailVerificationToken.java
new file mode 100644
index 000000000..706e05b87
--- /dev/null
+++ b/app/src/main/java/com/eventyay/organizer/data/auth/model/SubmitEmailVerificationToken.java
@@ -0,0 +1,13 @@
+package com.eventyay.organizer.data.auth.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class SubmitEmailVerificationToken {
+
+ public String token;
+}
diff --git a/app/src/main/java/com/eventyay/organizer/data/role/RoleApi.java b/app/src/main/java/com/eventyay/organizer/data/role/RoleApi.java
index 7366b0eed..ec56dc19b 100644
--- a/app/src/main/java/com/eventyay/organizer/data/role/RoleApi.java
+++ b/app/src/main/java/com/eventyay/organizer/data/role/RoleApi.java
@@ -2,8 +2,10 @@
import java.util.List;
+import io.reactivex.Completable;
import io.reactivex.Observable;
import retrofit2.http.Body;
+import retrofit2.http.DELETE;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
@@ -15,4 +17,7 @@ public interface RoleApi {
@GET("events/{id}/role-invites")
Observable> getRoles(@Path("id") long id);
+
+ @DELETE("role-invites/{role_invite_id}")
+ Completable deleteRole(@Path("role_invite_id") long roleInviteId);
}
diff --git a/app/src/main/java/com/eventyay/organizer/data/role/RoleRepository.java b/app/src/main/java/com/eventyay/organizer/data/role/RoleRepository.java
index d9768ade0..381521445 100644
--- a/app/src/main/java/com/eventyay/organizer/data/role/RoleRepository.java
+++ b/app/src/main/java/com/eventyay/organizer/data/role/RoleRepository.java
@@ -1,5 +1,6 @@
package com.eventyay.organizer.data.role;
+import io.reactivex.Completable;
import io.reactivex.Observable;
public interface RoleRepository {
@@ -7,4 +8,6 @@ public interface RoleRepository {
Observable sendRoleInvite(RoleInvite roleInvite);
Observable getRoles(long eventId, boolean forceReload);
+
+ Completable deleteRole(long roleInviteId);
}
diff --git a/app/src/main/java/com/eventyay/organizer/data/role/RoleRepositoryImpl.java b/app/src/main/java/com/eventyay/organizer/data/role/RoleRepositoryImpl.java
index 1aaf139c9..b5269e78c 100644
--- a/app/src/main/java/com/eventyay/organizer/data/role/RoleRepositoryImpl.java
+++ b/app/src/main/java/com/eventyay/organizer/data/role/RoleRepositoryImpl.java
@@ -1,5 +1,7 @@
package com.eventyay.organizer.data.role;
+import androidx.annotation.NonNull;
+
import com.eventyay.organizer.common.Constants;
import com.eventyay.organizer.data.RateLimiter;
import com.eventyay.organizer.data.Repository;
@@ -8,6 +10,7 @@
import javax.inject.Inject;
+import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@@ -58,4 +61,19 @@ public Observable getRoles(long eventId, boolean reload) {
.withNetworkObservable(networkObservable)
.build();
}
+
+ @NonNull
+ @Override
+ public Completable deleteRole(long roleInviteId) {
+ if (!repository.isConnected()) {
+ return Completable.error(new Throwable(Constants.NO_NETWORK));
+ }
+
+ return roleApi.deleteRole(roleInviteId)
+ .doOnComplete(() -> repository
+ .delete(Role.class, RoleInvite_Table.id.eq(roleInviteId))
+ .subscribe())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
}
diff --git a/app/src/main/java/com/eventyay/organizer/ui/ViewUtils.java b/app/src/main/java/com/eventyay/organizer/ui/ViewUtils.java
index 254e8f8c1..7340f4910 100644
--- a/app/src/main/java/com/eventyay/organizer/ui/ViewUtils.java
+++ b/app/src/main/java/com/eventyay/organizer/ui/ViewUtils.java
@@ -13,6 +13,8 @@
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.recyclerview.widget.RecyclerView;
+
+import android.util.TypedValue;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
@@ -117,4 +119,12 @@ public static void showDialog(Fragment fragment, String title, String message, S
Timber.e("Fragment %s is not attached to any Activity", fragment);
}
}
+
+ public static float dpToPx(Context context, int dp) {
+ return TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ dp,
+ context.getResources().getDisplayMetrics()
+ );
+ }
}
diff --git a/app/src/main/java/com/eventyay/organizer/utils/ErrorUtils.java b/app/src/main/java/com/eventyay/organizer/utils/ErrorUtils.java
index f495079fe..78973e77b 100644
--- a/app/src/main/java/com/eventyay/organizer/utils/ErrorUtils.java
+++ b/app/src/main/java/com/eventyay/organizer/utils/ErrorUtils.java
@@ -23,6 +23,7 @@ public final class ErrorUtils {
public static final int NOT_FOUND = 404;
public static final int METHOD_NOT_ALLOWED = 405;
public static final int REQUEST_TIMEOUT = 408;
+ public static final int CONFLICT = 409;
public static final int UNPROCESSABLE_ENTITY = 422;
private ErrorUtils() {
@@ -37,7 +38,7 @@ public static Error getMessage(Throwable throwable) {
if (errorCode == BAD_REQUEST || errorCode == UNAUTHORIZED || errorCode == FORBIDDEN || errorCode == NOT_FOUND ||
errorCode == METHOD_NOT_ALLOWED || errorCode == REQUEST_TIMEOUT) {
error = getErrorTitleAndDetails(throwable);
- } else if (errorCode == UNPROCESSABLE_ENTITY) {
+ } else if (errorCode == UNPROCESSABLE_ENTITY || errorCode == CONFLICT) {
error = getErrorDetails(throwable);
} else {
error.setDetail(throwable.getMessage());
diff --git a/app/src/main/java/com/eventyay/organizer/utils/LinkHandler.java b/app/src/main/java/com/eventyay/organizer/utils/LinkHandler.java
new file mode 100644
index 000000000..743e79d29
--- /dev/null
+++ b/app/src/main/java/com/eventyay/organizer/utils/LinkHandler.java
@@ -0,0 +1,47 @@
+package com.eventyay.organizer.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+import timber.log.Timber;
+
+public class LinkHandler {
+
+ public Destination destination;
+ public String token;
+
+ public LinkHandler(Destination destination, String token) {
+ this.destination = destination;
+ this.token = token;
+ }
+
+ public static LinkHandler getDestinationAndToken(String url) {
+ try {
+ url = URLDecoder.decode(url, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ Timber.e(e);
+ }
+
+ if (url.contains("reset-password")) {
+ String token = url.substring(url.indexOf('=') + 1);
+ return new LinkHandler(Destination.RESET_PASSWORD, token);
+ } else if (url.contains("verify")) {
+ String token = url.substring(url.indexOf('=') + 1);
+ return new LinkHandler(Destination.VERIFY_EMAIL, token);
+ } else
+ return null;
+ }
+
+ public Destination getDestination() {
+ return destination;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public enum Destination {
+ VERIFY_EMAIL,
+ RESET_PASSWORD
+ }
+}
diff --git a/app/src/main/res/layout/main_app_bar.xml b/app/src/main/res/layout/main_app_bar.xml
index 700525d86..cd94effaf 100644
--- a/app/src/main/res/layout/main_app_bar.xml
+++ b/app/src/main/res/layout/main_app_bar.xml
@@ -8,6 +8,7 @@
tools:context="com.eventyay.organizer.core.main.MainActivity">
diff --git a/app/src/main/res/layout/role_item.xml b/app/src/main/res/layout/role_item.xml
index 57c79c29f..c7b9272ae 100644
--- a/app/src/main/res/layout/role_item.xml
+++ b/app/src/main/res/layout/role_item.xml
@@ -20,7 +20,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/spacing_small"
- android:padding="@dimen/spacing_normal">
+ android:padding="@dimen/spacing_normal"
+ android:backgroundTint="@{ roleListViewModel.getRoleSelected(role) ? @color/blue_200 : 0 }">
-
-
@@ -77,7 +66,7 @@
android:id="@+id/organizer_lastname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:hint="@string/last_name"
+ android:hint="@string/family_name"
android:text="@={ user.lastName }" />
@@ -135,216 +124,12 @@
android:id="@+id/contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:hint="@string/contact"
+ android:hint="@string/phone"
android:text="@={user.contact}"
android:inputType="number" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/update_organizer_layout.xml b/app/src/main/res/layout/update_organizer_layout.xml
index 4ebaf56ec..f52bcaf7d 100644
--- a/app/src/main/res/layout/update_organizer_layout.xml
+++ b/app/src/main/res/layout/update_organizer_layout.xml
@@ -33,7 +33,7 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
- app:title="@string/copyright" />
+ app:title="@string/edit_profile" />
diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml
index 86b21c186..7505e95fe 100644
--- a/app/src/main/res/menu/activity_main_drawer.xml
+++ b/app/src/main/res/menu/activity_main_drawer.xml
@@ -118,10 +118,10 @@
android:title="@string/device_settings"
android:checkable="true"/>
-
+ android:title="@string/nav_suggestions"/>-->
-
+
diff --git a/app/src/main/res/raw/check_in_sound.wav b/app/src/main/res/raw/check_in_sound.wav
new file mode 100644
index 000000000..a36b3e6fb
Binary files /dev/null and b/app/src/main/res/raw/check_in_sound.wav differ
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d0bb7c648..12ef61daa 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -402,6 +402,14 @@
No
My Account
Start scanning again
+ Play sounds
+ play_sounds
+ Play sound on check-in and check-out
+ Select Location
+ Mapbox Access Token
+ A valid access token is required
+ Family Name
+ Phone
- Africa/Abidjan
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 995274705..0779cbe47 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -2,22 +2,22 @@
+ android:key="@string/play_sounds_key"
+ android:title="@string/play_sounds"
+ android:summary="@string/play_sound_on_check_in_out"
+ android:defaultValue="false" />
+ android:defaultValue="false" />
+ android:summary="@string/device_name_summary" />