diff --git a/AndroidClient/build.gradle b/AndroidClient/build.gradle
index 5d1a434..655d9f9 100644
--- a/AndroidClient/build.gradle
+++ b/AndroidClient/build.gradle
@@ -104,6 +104,8 @@ dependencies {
implementation libs.core
+ implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
+
/*TESTS*/
diff --git a/AndroidClient/src/main/AndroidManifest.xml b/AndroidClient/src/main/AndroidManifest.xml
index bc53dd3..82870dd 100644
--- a/AndroidClient/src/main/AndroidManifest.xml
+++ b/AndroidClient/src/main/AndroidManifest.xml
@@ -58,11 +58,7 @@
-
+ android:label="@string/profile_activity_label">
+
+
onToken, Runnable onCancelledAuth,
- AccountManager am, Activity activity, TokenService tokenService) {
+ Activity activity, TokenService tokenService) {
+ AccountManager am = AccountManager.get(activity);
Account account = getSingleAccount(am);
String token = am.peekAuthToken(account, AUTH_TYPE);
if (token != null) {
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/EventComponent.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/EventComponent.java
index 0c24cf6..a704fb4 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/event/EventComponent.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/EventComponent.java
@@ -7,6 +7,8 @@
import com.tom.meeter.context.event.activity.EventLocationMapActivity;
import com.tom.meeter.context.event.activity.EventOnMapActivity;
import com.tom.meeter.context.event.activity.ProfileEventActivity;
+import com.tom.meeter.context.event.activity.PublishEventActivity;
+import com.tom.meeter.context.event.activity.ScheduleEventActivity;
import com.tom.meeter.context.event.activity.UserEventActivity;
import dagger.BindsInstance;
@@ -29,13 +31,18 @@ interface Builder {
EventComponent build();
}
- void inject(EventDispatcherActivity eventDispatcherActivity);
+ void inject(EventDispatcherActivity activity);
- void inject(ProfileEventActivity profileEventActivity);
+ void inject(ProfileEventActivity activity);
- void inject(UserEventActivity userEventActivity);
+ void inject(UserEventActivity activity);
- void inject(EventOnMapActivity eventOnMapActivity);
+ void inject(EventOnMapActivity activity);
+
+ void inject(EventLocationMapActivity activity);
+
+ void inject(PublishEventActivity activity);
+
+ void inject(ScheduleEventActivity activity);
- void inject(EventLocationMapActivity eventLocationMapActivity);
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventDispatcherActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventDispatcherActivity.java
index 2aea752..da89415 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventDispatcherActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventDispatcherActivity.java
@@ -6,6 +6,7 @@
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import android.accounts.AccountManager;
+import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -30,11 +31,11 @@ public class EventDispatcherActivity extends AppCompatActivity {
public static final String EVENT_ID_KEY = "event_id";
private static final String TAG = EventDispatcherActivity.class.getCanonicalName();
+
@Inject
TokenService tokenService;
@Inject
EventService eventService;
- private AccountManager accountManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -42,29 +43,18 @@ protected void onCreate(Bundle savedInstanceState) {
logMethod(TAG, this);
- Bundle extras = getIntent().getExtras();
- if (extras == null) {
- Log.d(TAG, "Unable to create event activity without extras.");
- finish();
- return;
- }
- String eventId = extras.getString(EVENT_ID_KEY);
- if (eventId == null) {
- Log.d(TAG, "Unable to create event activity without 'event_id' provided.");
- finish();
+ if (EventDispatcherActivity.isIncorrect(this)) {
return;
}
((App) getApplication()).getEventComponent().inject(this);
- accountManager = AccountManager.get(this);
-
//setToken(accountManager, Launcher.EXPIRED);
- checkToken((token) -> onInit(token, eventId), this::finish,
- accountManager, this, tokenService);
+ checkToken(this::onInit, this::finish, this, tokenService);
}
- private void onInit(String token, String eventId) {
+ private void onInit(String token) {
+ String eventId = getEventId(this);
eventService.amICreator(Globals.getAuthHeader(token), eventId)
.enqueue(new BaseOnNotAuthenticatedCallback<>(this, this::recreate) {
@Override
@@ -81,6 +71,28 @@ public void onResponse(Call call, Response resp) {
});
}
+ public static boolean isIncorrect(Activity activity) {
+ Bundle extras = activity.getIntent().getExtras();
+ if (extras == null) {
+ Log.e(TAG, "Unable to create ["
+ + activity.getClass().getCanonicalName()
+ + "] without extras.");
+ activity.finish();
+ return true;
+ }
+ if (extras.getString(EVENT_ID_KEY) == null) {
+ Log.e(TAG, "Unable to create ["
+ + activity.getClass().getCanonicalName()
+ + "] without [" + EVENT_ID_KEY + "] provided.");
+ activity.finish();
+ return true;
+ }
+ return false;
+ }
+
+ public static String getEventId(Activity activity) {
+ return activity.getIntent().getExtras().getString(EVENT_ID_KEY);
+ }
public static void dispatchToEventActivity(Context ctx, String eventId) {
ctx.startActivity(createEventActivityIntent(ctx, eventId));
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventLocationMapActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventLocationMapActivity.java
index f063b5a..3839aa0 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventLocationMapActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventLocationMapActivity.java
@@ -1,9 +1,7 @@
package com.tom.meeter.context.event.activity;
-import static com.tom.meeter.context.auth.infrastructure.AuthHelper.getAuthHeader;
import static com.tom.meeter.context.profile.component.fragment.GoogleMapsFragment.ZOOM_VALUE;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
-import static com.tom.meeter.infrastructure.common.InfrastructureHelper.showMessage;
import android.accounts.AccountManager;
import android.content.ComponentName;
@@ -30,6 +28,7 @@
import com.google.android.gms.maps.model.MarkerOptions;
import com.tom.meeter.App;
import com.tom.meeter.R;
+import com.tom.meeter.context.auth.infrastructure.AuthHelper;
import com.tom.meeter.context.event.service.EventService;
import com.tom.meeter.context.gps.domain.LocationTrackerListener;
import com.tom.meeter.context.gps.service.LocationTrackerService;
@@ -52,40 +51,29 @@ public class EventLocationMapActivity extends AppCompatActivity
public static final String EXTRA_LNG = "extra_lng";
private static final String TAG = EventLocationMapActivity.class.getCanonicalName();
- private Marker eventMarker;
- private GoogleMap gmap;
- private ActivityEventPositionBinding binding;
- private ServiceConnection locationServiceConn;
- private LocationTrackerService locationService;
- private boolean cameraMoved = false;
+ @Inject
+ EventService service;
+ @Inject
+ ImageDownloader imgDownloader;
+ private ActivityEventPositionBinding binding;
+ private LocationTrackerService locationService;
+ private ServiceConnection sConn;
private LocationTrackerListener singleLocationUpdateListener;
- private String eventId;
+ private final Runnable onNotAuthenticated = this::finish;
+ private GoogleMap gmap;
- @Inject
- EventService eventService;
- @Inject
- ImageDownloader imageDownloader;
- private AccountManager accountManager;
+ private Marker eventMarker;
+ private boolean cameraMoved = false;
private LatLng userLocation;
- private final Runnable onNotAuthenticated = this::finish;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Bundle extras = getIntent().getExtras();
- if (extras == null) {
- showMessage(this, "Unable to show map without extras provided.");
- finish();
- return;
- }
- eventId = extras.getString(EventDispatcherActivity.EVENT_ID_KEY);
- if (eventId == null) {
- showMessage(this, "Unable to show map without event_id provided.");
- finish();
+ if (EventDispatcherActivity.isIncorrect(this)) {
return;
}
@@ -94,13 +82,14 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(view);
((App) getApplication()).getEventComponent().inject(this);
- accountManager = AccountManager.get(this);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.eventSelectPosition);
- if (mapFragment != null) {
- mapFragment.getMapAsync(this);
+ if (mapFragment == null) {
+ return;
}
+ mapFragment.getMapAsync(this);
+
binding.btnConfirm.setOnClickListener(v -> {
if (eventMarker != null) {
Intent resultIntent = new Intent();
@@ -127,13 +116,13 @@ public void onLocationChanged(Location location) {
cameraMoved = true;
locationService.removeLocationTrackerListener(this);
singleLocationUpdateListener = null;
- unbindService(locationServiceConn);
+ unbindService(sConn);
locationService = null;
- locationServiceConn = null;
+ sConn = null;
}
}
};
- locationServiceConn = new ServiceConnection() {
+ sConn = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder binder) {
logMethod(TAG, this);
locationService = ((LocationTrackerService.ServiceBinder) binder).getService();
@@ -143,11 +132,12 @@ public void onServiceConnected(ComponentName name, IBinder binder) {
public void onServiceDisconnected(ComponentName name) {
logMethod(TAG, this);
locationService = null;
- locationServiceConn = null;
+ sConn = null;
}
};
- Intent service = new Intent(this, LocationTrackerService.class);
- bindService(service, locationServiceConn, BIND_AUTO_CREATE);
+ bindService(
+ new Intent(this, LocationTrackerService.class),
+ sConn, BIND_AUTO_CREATE);
}
@Override
@@ -156,7 +146,9 @@ public void onMapReady(GoogleMap googleMap) {
UiSettings uiSettings = gmap.getUiSettings();
uiSettings.setZoomControlsEnabled(true);
- eventService.getEvent(getAuthHeader(accountManager), eventId).enqueue(
+ service.getEvent(
+ AuthHelper.getAuthHeader(AccountManager.get(this)),
+ EventDispatcherActivity.getEventId(this)).enqueue(
new BaseOnNotAuthenticatedCallback<>(this, onNotAuthenticated) {
@Override
public void onResponse(Call call, Response resp) {
@@ -199,7 +191,7 @@ private void setupEventMarker(LatLng latLng, EventDTO event) {
if (photoPath == null) {
return;
}
- imageDownloader.downloadEventImage(
+ imgDownloader.downloadEventImage(
photoPath, this, ImagesHelper::circleImage,
(photo) -> eventMarker.setIcon(BitmapDescriptorFactory.fromBitmap(photo)),
onNotAuthenticated);
@@ -212,8 +204,8 @@ protected void onDestroy() {
if (locationService != null && singleLocationUpdateListener != null) {
locationService.removeLocationTrackerListener(singleLocationUpdateListener);
}
- if (locationServiceConn != null) {
- unbindService(locationServiceConn);
+ if (sConn != null) {
+ unbindService(sConn);
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventOnMapActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventOnMapActivity.java
index 1a2f771..a2f5c47 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventOnMapActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventOnMapActivity.java
@@ -1,6 +1,5 @@
package com.tom.meeter.context.event.activity;
-import static com.tom.meeter.context.auth.infrastructure.AuthHelper.getAuthHeader;
import static com.tom.meeter.context.profile.component.fragment.GoogleMapsFragment.ZOOM_VALUE;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.showMessage;
@@ -24,6 +23,7 @@
import com.google.android.gms.maps.model.MarkerOptions;
import com.tom.meeter.App;
import com.tom.meeter.R;
+import com.tom.meeter.context.auth.infrastructure.AuthHelper;
import com.tom.meeter.context.event.service.EventService;
import com.tom.meeter.context.image.ImageDownloader;
import com.tom.meeter.context.network.dto.EventDTO;
@@ -49,25 +49,13 @@ public class EventOnMapActivity extends AppCompatActivity
//TODO remake onNotAuthenticated
private final Runnable onNotAuthenticated = this::finish;
- private GoogleMap gmap;
private ActivityEventOnMapBinding binding;
- private AccountManager accountManager;
- private String eventId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Bundle extras = getIntent().getExtras();
- if (extras == null) {
- showMessage(this, "Unable to show map without extras provided.");
- finish();
- return;
- }
- eventId = extras.getString(EventDispatcherActivity.EVENT_ID_KEY);
- if (eventId == null) {
- showMessage(this, "Unable to show map without event_id provided.");
- finish();
+ if (EventDispatcherActivity.isIncorrect(this)) {
return;
}
@@ -77,22 +65,22 @@ protected void onCreate(Bundle savedInstanceState) {
((App) getApplication()).getEventComponent().inject(this);
- accountManager = AccountManager.get(this);
-
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.eventOnMap);
- if (mapFragment != null) {
- mapFragment.getMapAsync(this);
+ if (mapFragment == null) {
+ return;
}
+ mapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
- gmap = googleMap;
- UiSettings uiSettings = gmap.getUiSettings();
+ UiSettings uiSettings = googleMap.getUiSettings();
uiSettings.setZoomControlsEnabled(true);
- service.getEvent(getAuthHeader(accountManager), eventId).enqueue(
+ service.getEvent(
+ AuthHelper.getAuthHeader(AccountManager.get(this)),
+ EventDispatcherActivity.getEventId(this)).enqueue(
//TODO:
// token is not checked at start,
// in case of invalid token infinity recreation
@@ -113,13 +101,14 @@ public void onResponse(Call call, Response resp) {
LatLng latLng = new LatLng(latitude, longitude);
String photoPath = event.getPhotoPath();
if (photoPath == null) {
- addMarkerMoveCamera(latLng, event.getName(), null);
+ addMarkerMoveCamera(googleMap, latLng, event.getName(), null);
return;
}
imgDownloader.downloadEventImage(
photoPath, EventOnMapActivity.this,
ImagesHelper::circleImage,
(photo) -> addMarkerMoveCamera(
+ googleMap,
latLng,
event.getName(),
BitmapDescriptorFactory.fromBitmap(photo)),
@@ -130,14 +119,14 @@ public void onResponse(Call call, Response resp) {
}
private void addMarkerMoveCamera(
- LatLng latLng, String title, BitmapDescriptor bmd) {
- gmap.addMarker(
+ GoogleMap map, LatLng latLng,
+ String title, BitmapDescriptor bmd) {
+ map.addMarker(
new MarkerOptions()
.position(latLng)
.title(title)
- .icon(bmd)
- );
- gmap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, ZOOM_VALUE));
+ .icon(bmd));
+ map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, ZOOM_VALUE));
}
@Override
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/ProfileEventActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/ProfileEventActivity.java
index f9e07c5..83fdaaf 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/ProfileEventActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/ProfileEventActivity.java
@@ -1,11 +1,15 @@
package com.tom.meeter.context.event.activity;
+import static android.view.View.GONE;
import static com.tom.meeter.context.auth.infrastructure.AuthHelper.checkToken;
import static com.tom.meeter.context.auth.infrastructure.AuthHelper.getAuthHeader;
-import static com.tom.meeter.context.event.activity.EventDispatcherActivity.EVENT_ID_KEY;
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.getUserUuid;
import static com.tom.meeter.context.event.activity.EventLocationMapActivity.EXTRA_LAT;
import static com.tom.meeter.context.event.activity.EventLocationMapActivity.EXTRA_LNG;
import static com.tom.meeter.context.event.activity.EventLocationMapActivity.createEventLocationMapActivityIntent;
+import static com.tom.meeter.context.event.activity.EventOnMapActivity.dispatchToEventOnMapActivity;
+import static com.tom.meeter.context.event.activity.PublishEventActivity.createPublishEventActivityIntent;
+import static com.tom.meeter.context.event.activity.ScheduleEventActivity.createScheduleEventActivityIntent;
import static com.tom.meeter.context.event.utils.Utils.createUpdateEventRequest;
import static com.tom.meeter.context.event.utils.Utils.currentUserIsEventCreator;
import static com.tom.meeter.context.event.utils.Utils.dumpEventDispatcherError;
@@ -13,6 +17,7 @@
import static com.tom.meeter.infrastructure.common.CommonHelper.UI_DATE_TIME_FORMAT;
import static com.tom.meeter.infrastructure.common.CommonHelper.dateOrNull;
import static com.tom.meeter.infrastructure.common.CommonHelper.handleEventStatus;
+import static com.tom.meeter.infrastructure.common.CommonHelper.resolveStatusAction;
import static com.tom.meeter.infrastructure.common.CommonHelper.textOrNull;
import static com.tom.meeter.infrastructure.common.DateHelper.showDateTimePicker;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
@@ -25,15 +30,15 @@
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import com.tom.meeter.App;
@@ -49,6 +54,7 @@
import com.tom.meeter.context.token.service.TokenService;
import com.tom.meeter.databinding.ActivityEventEditableBinding;
import com.tom.meeter.infrastructure.common.ImagesHelper;
+import com.tom.meeter.infrastructure.components.activity.BaseBackToolbarActivity;
import com.tom.meeter.infrastructure.http.BaseOnNotAuthenticatedCallback;
import com.tom.meeter.infrastructure.http.HttpCodes;
import com.tom.meeter.infrastructure.http.HttpErrorLogger;
@@ -60,7 +66,7 @@
import retrofit2.Call;
import retrofit2.Response;
-public class ProfileEventActivity extends AppCompatActivity {
+public class ProfileEventActivity extends BaseBackToolbarActivity {
private static final String TAG = ProfileEventActivity.class.getCanonicalName();
@@ -73,11 +79,10 @@ public class ProfileEventActivity extends AppCompatActivity {
@Inject
ImageDownloader imgDownloader;
- private final Runnable onNotAuthenticated = this::recreate;
+ private final Runnable onAuthFail = this::recreate;
private ActivityEventEditableBinding binding;
private AccountManager accountManager;
private EventViewModel viewModel;
- private ActivityResultLauncher mapResult;
private EventDTO eventCache;
private boolean isEditableModeEnabled = false;
@@ -94,74 +99,102 @@ public class ProfileEventActivity extends AppCompatActivity {
binding.photoPath.setText(photoPath);
});
+ private final ActivityResultLauncher mapResult = registerForActivityResult(
+ new ActivityResultContracts.StartActivityForResult(),
+ result -> {
+ if (result.getResultCode() != RESULT_OK || result.getData() == null) {
+ return;
+ }
+ double lat = result.getData().getDoubleExtra(EXTRA_LAT, 0.0);
+ double lng = result.getData().getDoubleExtra(EXTRA_LNG, 0.0);
+ binding.latitude.setText(String.valueOf(lat));
+ binding.longitude.setText(String.valueOf(lng));
+ });
+
+ private final ActivityResultLauncher publishLauncher =
+ registerForActivityResult(
+ new ActivityResultContracts.StartActivityForResult(),
+ result -> {
+ if (result.getResultCode() == RESULT_OK) {
+ viewModel.init();
+ }
+ }
+ );
+
+ private final ActivityResultLauncher scheduleLauncher =
+ registerForActivityResult(
+ new ActivityResultContracts.StartActivityForResult(),
+ result -> {
+ if (result.getResultCode() == RESULT_OK) {
+ viewModel.init();
+ }
+ }
+ );
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mapResult = registerForActivityResult(
- new ActivityResultContracts.StartActivityForResult(),
- result -> {
- if (result.getResultCode() != RESULT_OK || result.getData() == null) {
- return;
- }
- double lat = result.getData().getDoubleExtra(EXTRA_LAT, 0.0);
- double lng = result.getData().getDoubleExtra(EXTRA_LNG, 0.0);
- binding.latitude.setText(String.valueOf(lat));
- binding.longitude.setText(String.valueOf(lng));
- });
-
logMethod(TAG, this);
- Bundle extras = getIntent().getExtras();
- if (extras == null) {
- Log.d(TAG, "Unable to create event activity without extras.");
- finish();
- return;
- }
- String eventId = extras.getString(EVENT_ID_KEY);
- if (eventId == null) {
- Log.d(TAG, "Unable to create event activity without 'event_id' provided.");
- finish();
+ if (EventDispatcherActivity.isIncorrect(this)) {
return;
}
+ binding = ActivityEventEditableBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
+ setupToolbar(binding.includeToolbar.toolbar, R.string.view_event);
+
((App) getApplication()).getEventComponent().inject(this);
accountManager = AccountManager.get(this);
//setToken(accountManager, Launcher.EXPIRED);
- checkToken((token) -> onInit(eventId), this::finish,
- accountManager, this, tokenService);
+ checkToken((token) -> onInit(), this::finish, this, tokenService);
}
- private void onInit(String eventId) {
+ private void onInit() {
viewModel = new ViewModelProvider(
this,
assistedFactory.factory(
- assistedFactory, eventId, this, onNotAuthenticated))
+ assistedFactory,
+ EventDispatcherActivity.getEventId(this),
+ this, onAuthFail))
.get(EventViewModel.class);
+ binding.swipeRefresh.setOnRefreshListener(() -> viewModel.init());
+
initLayout();
viewModel.getEvent()
.observe(this, event -> {
if (!currentUserIsEventCreator(accountManager, event)) {
- dumpEventDispatcherError(TAG, accountManager, event);
+ dumpEventDispatcherError(TAG, getUserUuid(accountManager), event);
finish();
return;
}
+ binding.swipeRefresh.setRefreshing(false);
eventCache = event;
updateLayout();
viewModel.getEventPhoto()
.observe(this, this::updateLayoutPhoto);
});
+
+ viewModel.getTransitions()
+ .observe(this, transitions -> {
+ if (transitions.isEmpty()) {
+ binding.actionsButtonContainer.setVisibility(GONE);
+ return;
+ }
+ binding.actionsButtonContainer.removeAllViews();
+ for (EventDTO.EventStatus t : transitions) {
+ binding.actionsButtonContainer.addView(createStatusButton(t));
+ }
+ });
}
private void initLayout() {
- binding = ActivityEventEditableBinding.inflate(getLayoutInflater());
- View view = binding.getRoot();
- setContentView(view);
-
binding.selectStartingDateButton.setOnClickListener(
v -> showDateTimePicker(this, binding.starting));
binding.selectEndingDateButton.setOnClickListener(
@@ -169,6 +202,8 @@ private void initLayout() {
binding.locationMapButton.setOnClickListener(
v -> mapResult.launch(
createEventLocationMapActivityIntent(this, eventCache.getId())));
+ binding.showOnMapButton.setOnClickListener(
+ v -> dispatchToEventOnMapActivity(this, eventCache.getId()));
binding.deleteEventButton.setOnClickListener(v -> showAlertDialog());
binding.editSaveButton.setOnClickListener(v -> {
@@ -180,7 +215,7 @@ private void initLayout() {
return;
}
service.updateEvent(getAuthHeader(accountManager), eventCache.getId(), req)
- .enqueue(new BaseOnNotAuthenticatedCallback<>(this, onNotAuthenticated) {
+ .enqueue(new BaseOnNotAuthenticatedCallback<>(this, onAuthFail) {
@Override
public void onResponse(
Call call, Response resp) {
@@ -209,7 +244,7 @@ public void onResponse(
void downloadAndUpdateLayoutPhoto(String photoPath) {
imgDownloader.downloadEventImage(
photoPath, this, ImagesHelper::bigCircleImage,
- this::updateLayoutPhoto, onNotAuthenticated);
+ this::updateLayoutPhoto, onAuthFail);
}
private void updateLayoutPhoto(Bitmap photo) {
@@ -219,10 +254,7 @@ private void updateLayoutPhoto(Bitmap photo) {
private void switchEditMode() {
isEditableModeEnabled = !isEditableModeEnabled;
- binding.selectPhotoButton.setEnabled(isEditableModeEnabled);
- binding.locationMapButton.setEnabled(isEditableModeEnabled);
- binding.selectStartingDateButton.setEnabled(isEditableModeEnabled);
- binding.selectEndingDateButton.setEnabled(isEditableModeEnabled);
+ setButtonsVisibility(isEditableModeEnabled);
binding.name.setEnabled(isEditableModeEnabled);
binding.description.setEnabled(isEditableModeEnabled);
@@ -234,6 +266,18 @@ private void switchEditMode() {
binding.editSaveButton.setText(isEditableModeEnabled ? R.string.save : R.string.edit);
}
+ private void setButtonsVisibility(boolean isEditableModeEnabled) {
+ int onEdit = isEditableModeEnabled ? View.VISIBLE : View.GONE;
+ binding.locationMapButton.setVisibility(onEdit);
+ binding.selectPhotoButton.setVisibility(onEdit);
+ binding.photoPath.setVisibility(onEdit);
+ binding.selectStartingDateButton.setVisibility(onEdit);
+ binding.selectEndingDateButton.setVisibility(onEdit);
+
+ int onRead = isEditableModeEnabled ? View.GONE : View.VISIBLE;
+ binding.showOnMapButton.setVisibility(onRead);
+ }
+
private void showAlertDialog() {
new AlertDialog.Builder(this)
.setTitle(R.string.delete_event)
@@ -298,6 +342,116 @@ protected void onPause() {
super.onPause();
}
+ private Button createStatusButton(EventDTO.EventStatus status) {
+ String auth = getAuthHeader(accountManager);
+ String eventId = eventCache.getId();
+ Button btn = new Button(this);
+ btn.setText(resolveStatusAction(this, status));
+ btn.setLayoutParams(new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+ switch (status) {
+ case PUBLISHED:
+ btn.setOnClickListener(
+ v -> publishLauncher.launch(
+ createPublishEventActivityIntent(
+ this, eventId)));
+ break;
+ case SCHEDULED:
+ btn.setOnClickListener(
+ v -> scheduleLauncher.launch(
+ createScheduleEventActivityIntent(
+ this, eventId)));
+ break;
+ case UNPUBLISHED:
+ btn.setOnClickListener(
+ v -> showConfirmStatusChangeDialog(
+ this,
+ EventDTO.EventStatus.UNPUBLISHED,
+ () -> service.unpublishEvent(auth, eventId)
+ .enqueue(refreshCallback)));
+ break;
+ case STARTED:
+ btn.setOnClickListener(
+ v -> showConfirmStatusChangeDialog(
+ this,
+ EventDTO.EventStatus.STARTED,
+ () -> service.startEvent(auth, eventId)
+ .enqueue(refreshCallback)));
+ break;
+ case PAUSED:
+ btn.setOnClickListener(
+ v -> showConfirmStatusChangeDialog(
+ this,
+ EventDTO.EventStatus.PAUSED,
+ () -> service.pauseEvent(auth, eventId)
+ .enqueue(refreshCallback)));
+ break;
+ case RESUMED:
+ btn.setOnClickListener(
+ v -> showConfirmStatusChangeDialog(
+ this,
+ EventDTO.EventStatus.RESUMED,
+ () -> service.resumeEvent(auth, eventId)
+ .enqueue(refreshCallback)));
+ break;
+ case FINISHED:
+ btn.setOnClickListener(
+ v -> showConfirmStatusChangeDialog(
+ this,
+ EventDTO.EventStatus.FINISHED,
+ () -> service.finishEvent(auth, eventId)
+ .enqueue(refreshCallback)));
+ break;
+ case CANCELLED:
+ btn.setOnClickListener(
+ v -> showConfirmStatusChangeDialog(
+ this,
+ EventDTO.EventStatus.CANCELLED,
+ () -> service.cancelEvent(auth, eventId)
+ .enqueue(refreshCallback)));
+ break;
+ case ARCHIVED:
+ btn.setOnClickListener(
+ v -> showConfirmStatusChangeDialog(
+ this,
+ EventDTO.EventStatus.ARCHIVED,
+ () -> service.archiveEvent(auth, eventId)
+ .enqueue(refreshCallback)));
+ break;
+ default:
+ throw new IllegalStateException("Wrong status: " + status);
+ }
+ return btn;
+ }
+
+ private void showConfirmStatusChangeDialog(
+ Context ctx, EventDTO.EventStatus newStatus, Runnable onConfirmed) {
+ String message = "Вы точно хотите выполнить действие?\n\n"
+ + resolveStatusAction(ctx, newStatus);
+
+ new AlertDialog.Builder(ctx)
+ .setTitle("Подтвердите действие")
+ .setMessage(message)
+ .setPositiveButton("Да", (dialog, which) -> {
+ dialog.dismiss();
+ onConfirmed.run();
+ })
+ .setNegativeButton("Отмена", (dialog, which) -> dialog.dismiss())
+ .show();
+ }
+
+ private final BaseOnNotAuthenticatedCallback refreshCallback
+ = new BaseOnNotAuthenticatedCallback<>(this, onAuthFail) {
+ @Override
+ public void onResponse(Call call, Response resp) {
+ super.onResponse(call, resp);
+ if (resp.isSuccessful()) {
+ viewModel.init();
+ }
+ }
+ };
+
public static void dispatchToProfileEventActivity(Context ctx, String eventId) {
ctx.startActivity(createProfileEventActivityIntent(ctx, eventId));
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/PublishEventActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/PublishEventActivity.java
new file mode 100644
index 0000000..0e57f2a
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/PublishEventActivity.java
@@ -0,0 +1,246 @@
+package com.tom.meeter.context.event.activity;
+
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.checkToken;
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.getAuthHeader;
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.getUserUuid;
+import static com.tom.meeter.context.event.activity.EventLocationMapActivity.EXTRA_LAT;
+import static com.tom.meeter.context.event.activity.EventLocationMapActivity.EXTRA_LNG;
+import static com.tom.meeter.context.event.activity.EventLocationMapActivity.createEventLocationMapActivityIntent;
+import static com.tom.meeter.context.event.utils.Utils.createPublishEventRequest;
+import static com.tom.meeter.context.event.utils.Utils.currentUserIsEventCreator;
+import static com.tom.meeter.context.event.utils.Utils.dumpEventDispatcherError;
+import static com.tom.meeter.context.image.activity.BaseUploadActivity.PHOTO_PATH_RESULT;
+import static com.tom.meeter.infrastructure.common.CommonHelper.UI_DATE_TIME_FORMAT;
+import static com.tom.meeter.infrastructure.common.CommonHelper.dateOrNull;
+import static com.tom.meeter.infrastructure.common.CommonHelper.handleEventStatus;
+import static com.tom.meeter.infrastructure.common.CommonHelper.textOrNull;
+import static com.tom.meeter.infrastructure.common.DateHelper.showDateTimePicker;
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.showMessage;
+
+import android.accounts.AccountManager;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.tom.meeter.App;
+import com.tom.meeter.R;
+import com.tom.meeter.context.event.factory.EventAssistedFactory;
+import com.tom.meeter.context.event.message.UpdateEventRequest;
+import com.tom.meeter.context.event.service.EventService;
+import com.tom.meeter.context.event.viewmodel.EventViewModel;
+import com.tom.meeter.context.image.ImageDownloader;
+import com.tom.meeter.context.image.activity.UploadEventImageActivity;
+import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.token.service.TokenService;
+import com.tom.meeter.databinding.ActivityEventPublishBinding;
+import com.tom.meeter.infrastructure.common.ImagesHelper;
+import com.tom.meeter.infrastructure.http.BaseOnNotAuthenticatedCallback;
+import com.tom.meeter.infrastructure.http.HttpCodes;
+
+import java.util.Objects;
+
+import javax.inject.Inject;
+
+import retrofit2.Call;
+import retrofit2.Response;
+
+public class PublishEventActivity extends AppCompatActivity {
+
+ private static final String TAG = PublishEventActivity.class.getCanonicalName();
+
+ @Inject
+ TokenService tokenService;
+ @Inject
+ EventService service;
+ @Inject
+ EventAssistedFactory assistedFactory;
+ @Inject
+ ImageDownloader imgDownloader;
+
+ private final Runnable onNotAuthenticated = this::recreate;
+ private ActivityEventPublishBinding binding;
+ private AccountManager accountManager;
+ private EventViewModel viewModel;
+ private EventDTO eventCache;
+
+ private final ActivityResultLauncher mapResult = registerForActivityResult(
+ new ActivityResultContracts.StartActivityForResult(),
+ result -> {
+ if (result.getResultCode() != RESULT_OK || result.getData() == null) {
+ return;
+ }
+ double lat = result.getData().getDoubleExtra(EXTRA_LAT, 0.0);
+ double lng = result.getData().getDoubleExtra(EXTRA_LNG, 0.0);
+ binding.latitude.setText(String.valueOf(lat));
+ binding.longitude.setText(String.valueOf(lng));
+ });
+ ;
+
+ private final ActivityResultLauncher imageUploadLauncher =
+ registerForActivityResult(
+ new ActivityResultContracts.StartActivityForResult(),
+ result -> {
+ if (result.getResultCode() != Activity.RESULT_OK || result.getData() == null) {
+ return;
+ }
+ String photoPath = result.getData().getStringExtra(PHOTO_PATH_RESULT);
+ downloadAndUpdateLayoutPhoto(photoPath);
+ binding.photoPath.setText(photoPath);
+ });
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ logMethod(TAG, this);
+
+ if (EventDispatcherActivity.isIncorrect(this)) {
+ return;
+ }
+
+ binding = ActivityEventPublishBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
+
+ ((App) getApplication()).getEventComponent().inject(this);
+
+ accountManager = AccountManager.get(this);
+ //setToken(accountManager, Launcher.EXPIRED);
+ checkToken((token) -> onInit(), this::finish, this, tokenService);
+ }
+
+ private void onInit() {
+ viewModel = new ViewModelProvider(
+ this,
+ assistedFactory.factory(
+ assistedFactory,
+ EventDispatcherActivity.getEventId(this),
+ this, onNotAuthenticated))
+ .get(EventViewModel.class);
+
+ binding.swipeRefresh.setOnRefreshListener(() -> viewModel.init());
+
+ initLayout();
+
+ viewModel.getEvent()
+ .observe(this, event -> {
+ if (!currentUserIsEventCreator(accountManager, event)) {
+ dumpEventDispatcherError(TAG, getUserUuid(accountManager), event);
+ finish();
+ return;
+ }
+ binding.swipeRefresh.setRefreshing(false);
+ eventCache = event;
+ updateLayout();
+ viewModel.getEventPhoto()
+ .observe(this, this::updateLayoutPhoto);
+ });
+ }
+
+ private void initLayout() {
+ binding.selectStartingDateButton.setOnClickListener(
+ v -> showDateTimePicker(this, binding.starting));
+ binding.selectEndingDateButton.setOnClickListener(
+ v -> showDateTimePicker(this, binding.ending));
+ binding.locationMapButton.setOnClickListener(
+ v -> mapResult.launch(
+ createEventLocationMapActivityIntent(this, eventCache.getId())));
+
+ binding.publishButton.setOnClickListener(v -> {
+ UpdateEventRequest req = createPublishEventRequest(eventCache, binding);
+ service.publishEvent(getAuthHeader(accountManager), eventCache.getId(), req)
+ .enqueue(new BaseOnNotAuthenticatedCallback<>(this, onNotAuthenticated) {
+ @Override
+ public void onResponse(
+ Call call, Response resp) {
+ super.onResponse(call, resp);
+ if (resp.code() != HttpCodes.OK) {
+ showMessage(PublishEventActivity.this,
+ "Unable to publish the event...");
+ updateLayout();
+ return;
+ }
+ String oldPhotoPath = eventCache.getPhotoPath();
+ eventCache = resp.body();
+ if (!Objects.equals(oldPhotoPath, eventCache.getPhotoPath())) {
+ downloadAndUpdateLayoutPhoto(eventCache.getPhotoPath());
+ }
+ showMessage(PublishEventActivity.this, R.string.published);
+ setResult(RESULT_OK);
+ finish();
+ }
+ });
+ });
+ binding.selectPhotoButton.setOnClickListener(
+ v -> imageUploadLauncher.launch(
+ new Intent(this, UploadEventImageActivity.class)));
+ }
+
+ void downloadAndUpdateLayoutPhoto(String photoPath) {
+ imgDownloader.downloadEventImage(
+ photoPath, this, ImagesHelper::bigCircleImage,
+ this::updateLayoutPhoto, onNotAuthenticated);
+ }
+
+ private void updateLayoutPhoto(Bitmap photo) {
+ binding.photo.setImageBitmap(photo);
+ }
+
+ private void updateLayout() {
+ binding.photoPath.setText(eventCache.getPhotoPath());
+ handleEventStatus(this, binding.status, eventCache.getStatus());
+ binding.name.setText(eventCache.getName());
+ binding.eventCreated.setText(UI_DATE_TIME_FORMAT.format(eventCache.getCreated()));
+
+ binding.description.setText(eventCache.getDescription());
+ binding.latitude.setText(textOrNull(eventCache.getLatitude()));
+ binding.longitude.setText(textOrNull(eventCache.getLongitude()));
+ binding.starting.setText(dateOrNull(eventCache.getStarting()));
+ binding.ending.setText(dateOrNull(eventCache.getEnding()));
+ binding.city.setText(eventCache.getCity());
+ }
+
+
+ @Nullable
+ @Override
+ public View onCreateView(
+ @Nullable View parent, @NonNull String name, @NonNull Context ctx,
+ @NonNull AttributeSet attrs) {
+ return super.onCreateView(parent, name, ctx, attrs);
+ }
+
+ @Override
+ protected void onDestroy() {
+ logMethod(TAG, this);
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onStop() {
+ logMethod(TAG, this);
+ super.onStop();
+ }
+
+ @Override
+ protected void onPause() {
+ logMethod(TAG, this);
+ super.onPause();
+ }
+
+ public static Intent createPublishEventActivityIntent(Context ctx, String eventId) {
+ return new Intent(ctx, PublishEventActivity.class)
+ .putExtra(EventDispatcherActivity.EVENT_ID_KEY, eventId);
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/ScheduleEventActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/ScheduleEventActivity.java
new file mode 100644
index 0000000..7e0ab35
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/ScheduleEventActivity.java
@@ -0,0 +1,177 @@
+package com.tom.meeter.context.event.activity;
+
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.checkToken;
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.getAuthHeader;
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.getUserUuid;
+import static com.tom.meeter.context.event.utils.Utils.createScheduleEventRequest;
+import static com.tom.meeter.context.event.utils.Utils.currentUserIsEventCreator;
+import static com.tom.meeter.context.event.utils.Utils.dumpEventDispatcherError;
+import static com.tom.meeter.infrastructure.common.CommonHelper.dateOrNull;
+import static com.tom.meeter.infrastructure.common.DateHelper.showDateTimePicker;
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.showMessage;
+
+import android.accounts.AccountManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.lifecycle.ViewModelProvider;
+
+import com.tom.meeter.App;
+import com.tom.meeter.R;
+import com.tom.meeter.context.event.factory.EventAssistedFactory;
+import com.tom.meeter.context.event.service.EventService;
+import com.tom.meeter.context.event.viewmodel.EventViewModel;
+import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.token.service.TokenService;
+import com.tom.meeter.databinding.ActivityEventScheduleBinding;
+import com.tom.meeter.infrastructure.http.BaseOnNotAuthenticatedCallback;
+import com.tom.meeter.infrastructure.http.HttpCodes;
+
+import javax.inject.Inject;
+
+import retrofit2.Call;
+import retrofit2.Response;
+
+public class ScheduleEventActivity extends AppCompatActivity {
+
+ private static final String TAG = ScheduleEventActivity.class.getCanonicalName();
+
+ @Inject
+ TokenService tokenService;
+ @Inject
+ EventService service;
+ @Inject
+ EventAssistedFactory assistedFactory;
+
+ private final Runnable onNotAuthenticated = this::recreate;
+ private ActivityEventScheduleBinding binding;
+ private AccountManager accountManager;
+ private EventViewModel viewModel;
+ private EventDTO eventCache;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ logMethod(TAG, this);
+
+ if (EventDispatcherActivity.isIncorrect(this)) {
+ return;
+ }
+
+ binding = ActivityEventScheduleBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
+
+ ((App) getApplication()).getEventComponent().inject(this);
+
+ accountManager = AccountManager.get(this);
+
+ //setToken(accountManager, Launcher.EXPIRED);
+ checkToken((token) -> onInit(), this::finish, this, tokenService);
+ }
+
+ private void onInit() {
+ viewModel = new ViewModelProvider(
+ this,
+ assistedFactory.factory(
+ assistedFactory,
+ EventDispatcherActivity.getEventId(this),
+ this, onNotAuthenticated))
+ .get(EventViewModel.class);
+
+ binding.swipeRefresh.setOnRefreshListener(() -> viewModel.init());
+
+ initLayout();
+
+ viewModel.getEvent()
+ .observe(this, event -> {
+ if (!currentUserIsEventCreator(accountManager, event)) {
+ dumpEventDispatcherError(TAG, getUserUuid(accountManager), event);
+ finish();
+ return;
+ }
+ binding.swipeRefresh.setRefreshing(false);
+ eventCache = event;
+ updateLayout();
+ });
+ }
+
+ private void initLayout() {
+ binding.selectStartingDateButton.setOnClickListener(
+ v -> showDateTimePicker(this, binding.starting));
+ binding.selectEndingDateButton.setOnClickListener(
+ v -> showDateTimePicker(this, binding.ending));
+
+ binding.scheduleButton.setOnClickListener(v -> {
+ service.scheduleEvent(
+ getAuthHeader(accountManager),
+ eventCache.getId(),
+ createScheduleEventRequest(eventCache, binding))
+ .enqueue(new BaseOnNotAuthenticatedCallback<>(this, onNotAuthenticated) {
+ @Override
+ public void onResponse(
+ Call call, Response resp) {
+ super.onResponse(call, resp);
+ if (resp.code() != HttpCodes.OK) {
+ showMessage(ScheduleEventActivity.this,
+ "Unable to schedule the event...");
+ updateLayout();
+ return;
+ }
+ showMessage(ScheduleEventActivity.this, R.string.scheduled);
+ setResult(RESULT_OK);
+ finish();
+ }
+ });
+ });
+ }
+
+ private void updateLayout() {
+ binding.name.setText(eventCache.getName());
+ binding.starting.setText(dateOrNull(eventCache.getStarting()));
+ binding.ending.setText(dateOrNull(eventCache.getEnding()));
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(
+ @Nullable View parent, @NonNull String name, @NonNull Context ctx,
+ @NonNull AttributeSet attrs) {
+ return super.onCreateView(parent, name, ctx, attrs);
+ }
+
+ @Override
+ protected void onDestroy() {
+ logMethod(TAG, this);
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onStop() {
+ logMethod(TAG, this);
+ super.onStop();
+ }
+
+ @Override
+ protected void onPause() {
+ logMethod(TAG, this);
+ super.onPause();
+ }
+
+ public static void dispatchToScheduleEventActivity(Context ctx, String eventId) {
+ ctx.startActivity(createScheduleEventActivityIntent(ctx, eventId));
+ }
+
+ public static Intent createScheduleEventActivityIntent(Context ctx, String eventId) {
+ return new Intent(ctx, ScheduleEventActivity.class)
+ .putExtra(EventDispatcherActivity.EVENT_ID_KEY, eventId);
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/UserEventActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/UserEventActivity.java
index 0efff9d..b420dac 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/UserEventActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/UserEventActivity.java
@@ -1,6 +1,7 @@
package com.tom.meeter.context.event.activity;
import static com.tom.meeter.context.auth.infrastructure.AuthHelper.checkToken;
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.getUserUuid;
import static com.tom.meeter.context.event.activity.EventOnMapActivity.dispatchToEventOnMapActivity;
import static com.tom.meeter.context.event.utils.Utils.currentUserIsEventCreator;
import static com.tom.meeter.context.event.utils.Utils.dumpEventDispatcherError;
@@ -16,25 +17,25 @@
import android.content.Intent;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import com.tom.meeter.App;
+import com.tom.meeter.R;
import com.tom.meeter.context.event.factory.EventAssistedFactory;
import com.tom.meeter.context.event.service.EventService;
import com.tom.meeter.context.event.viewmodel.EventViewModel;
import com.tom.meeter.context.network.dto.EventDTO;
import com.tom.meeter.context.token.service.TokenService;
import com.tom.meeter.databinding.ActivityEventReadableBinding;
+import com.tom.meeter.infrastructure.components.activity.BaseBackToolbarActivity;
import javax.inject.Inject;
-public class UserEventActivity extends AppCompatActivity {
+public class UserEventActivity extends BaseBackToolbarActivity {
private static final String TAG = UserEventActivity.class.getCanonicalName();
@@ -55,41 +56,42 @@ protected void onCreate(Bundle savedInstanceState) {
logMethod(TAG, this);
- Bundle extras = getIntent().getExtras();
- if (extras == null) {
- Log.d(TAG, "Unable to create event activity without extras.");
- finish();
- return;
- }
- String eventId = extras.getString(EventDispatcherActivity.EVENT_ID_KEY);
- if (eventId == null) {
- Log.d(TAG, "Unable to create event activity without 'event_id' provided.");
- finish();
+ if (EventDispatcherActivity.isIncorrect(this)) {
return;
}
+ binding = ActivityEventReadableBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
+ setupToolbar(binding.includeToolbar.toolbar, R.string.view_event);
+
((App) getApplication()).getEventComponent().inject(this);
+
accountManager = AccountManager.get(this);
//setToken(accountManager, Launcher.EXPIRED);
- checkToken((token) -> onInit(eventId),
- this::finish, accountManager, this, tokenService);
+ checkToken((token) -> onInit(), this::finish, this, tokenService);
}
- private void onInit(String eventId) {
+ private void onInit() {
viewModel = new ViewModelProvider(
this,
assistedFactory.factory(
- assistedFactory, eventId, this, this::recreate))
+ assistedFactory,
+ EventDispatcherActivity.getEventId(this),
+ this, this::recreate))
.get(EventViewModel.class);
+ binding.swipeRefresh.setOnRefreshListener(() -> viewModel.init());
+
viewModel.getEvent()
.observe(this, event -> {
if (currentUserIsEventCreator(accountManager, event)) {
- dumpEventDispatcherError(TAG, accountManager, event);
+ dumpEventDispatcherError(TAG, getUserUuid(accountManager), event);
finish();
return;
}
+ binding.swipeRefresh.setRefreshing(false);
initLayout(event);
viewModel.getEventPhoto()
.observe(
@@ -100,10 +102,6 @@ private void onInit(String eventId) {
}
private void initLayout(EventDTO event) {
- binding = ActivityEventReadableBinding.inflate(getLayoutInflater());
- View view = binding.getRoot();
- setContentView(view);
-
binding.eventCreator.setOnClickListener(
v -> dispatchToUserActivity(this, event.getCreatorId()));
binding.locationMapButton.setOnClickListener(
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/message/ScheduleEventRequest.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/message/ScheduleEventRequest.java
new file mode 100644
index 0000000..1aa05c9
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/message/ScheduleEventRequest.java
@@ -0,0 +1,33 @@
+package com.tom.meeter.context.event.message;
+
+import java.time.OffsetDateTime;
+import java.util.Optional;
+
+public class ScheduleEventRequest {
+
+ private Optional starting;
+ private Optional ending;
+
+ public ScheduleEventRequest() {
+ }
+
+ public Optional getStarting() {
+ return starting;
+ }
+
+ public Optional getEnding() {
+ return ending;
+ }
+
+ public void setStarting(OffsetDateTime starting) {
+ this.starting = Optional.ofNullable(starting);
+ }
+
+ public void setEnding(OffsetDateTime ending) {
+ this.ending = Optional.ofNullable(ending);
+ }
+
+ public boolean isEmpty() {
+ return starting == null && ending == null;
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/service/EventService.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/service/EventService.java
index 0d21f5a..7760511 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/event/service/EventService.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/service/EventService.java
@@ -2,31 +2,94 @@
import static com.tom.meeter.infrastructure.common.Globals.AUTH_HEADER;
+import com.tom.meeter.context.event.message.ScheduleEventRequest;
import com.tom.meeter.context.event.message.UpdateEventRequest;
import com.tom.meeter.context.network.dto.EventDTO;
+import java.util.Set;
+
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.PATCH;
+import retrofit2.http.POST;
import retrofit2.http.Path;
public interface EventService {
@GET("/event/{id}")
- Call getEvent(@Header(AUTH_HEADER) String authHeader, @Path("id") String eventId);
+ Call getEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
@PATCH("/event/{id}")
Call updateEvent(
- @Header(AUTH_HEADER) String authHeader, @Path("id") String eventId,
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId,
@Body UpdateEventRequest req);
@DELETE("/event/{id}")
- Call deleteEvent(@Header(AUTH_HEADER) String authHeader, @Path("id") String eventId);
+ Call deleteEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
@GET("/event/{id}/am_i_creator")
- Call amICreator(@Header(AUTH_HEADER) String authHeader, @Path("id") String eventId);
+ Call amICreator(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
+
+ @GET("/event/{id}/available-transitions")
+ Call> availableTransitions(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
+
+ @POST("/event/{id}/publish")
+ Call publishEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId,
+ @Body UpdateEventRequest req);
+
+ @POST("/event/{id}/schedule")
+ Call scheduleEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId,
+ @Body ScheduleEventRequest req);
+
+ @POST("/event/{id}/unpublish")
+ Call unpublishEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
+
+ @POST("/event/{id}/start")
+ Call startEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
+
+ @POST("/event/{id}/pause")
+ Call pauseEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
+
+ @POST("/event/{id}/resume")
+ Call resumeEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
+
+ @POST("/event/{id}/finish")
+ Call finishEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
+
+ @POST("/event/{id}/cancel")
+ Call cancelEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
+
+ @POST("/event/{id}/archive")
+ Call archiveEvent(
+ @Header(AUTH_HEADER) String authHeader,
+ @Path("id") String eventId);
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/utils/Utils.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/utils/Utils.java
index 8d1d87b..7d76d5e 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/event/utils/Utils.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/utils/Utils.java
@@ -8,9 +8,12 @@
import android.util.Log;
import com.tom.meeter.context.auth.infrastructure.AuthHelper;
+import com.tom.meeter.context.event.message.ScheduleEventRequest;
import com.tom.meeter.context.event.message.UpdateEventRequest;
import com.tom.meeter.context.network.dto.EventDTO;
import com.tom.meeter.databinding.ActivityEventEditableBinding;
+import com.tom.meeter.databinding.ActivityEventPublishBinding;
+import com.tom.meeter.databinding.ActivityEventScheduleBinding;
import java.time.OffsetDateTime;
import java.util.Objects;
@@ -59,15 +62,68 @@ public static UpdateEventRequest createUpdateEventRequest(
return req;
}
+ public static UpdateEventRequest createPublishEventRequest(
+ EventDTO event, ActivityEventPublishBinding binding) {
+ UpdateEventRequest req = new UpdateEventRequest();
+
+ String eventNameChange = getStringOrNull(binding.name.getText());
+ if (!Objects.equals(event.getName(), eventNameChange)) {
+ req.setName(eventNameChange);
+ }
+ String eventDescrChange = getStringOrNull(binding.description.getText());
+ if (!Objects.equals(event.getDescription(), eventDescrChange)) {
+ req.setDescription(eventDescrChange);
+ }
+ OffsetDateTime eventStartingChange = getOffsetDateTime(binding.starting.getText());
+ if (!Objects.equals(event.getStarting(), eventStartingChange)) {
+ req.setStarting(eventStartingChange);
+ }
+ OffsetDateTime eventEndingChange = getOffsetDateTime(binding.ending.getText());
+ if (!Objects.equals(event.getEnding(), eventEndingChange)) {
+ req.setEnding(eventEndingChange);
+ }
+ String eventCityChange = getStringOrNull(binding.city.getText());
+ if (!Objects.equals(event.getCity(), eventCityChange)) {
+ req.setCity(eventCityChange);
+ }
+ Double eventLatitudeChange = getDoubleOrNull(binding.latitude.getText());
+ if (!Objects.equals(event.getLatitude(), eventLatitudeChange)) {
+ req.setLatitude(eventLatitudeChange);
+ }
+ Double eventLongitudeChange = getDoubleOrNull(binding.longitude.getText());
+ if (!Objects.equals(event.getLongitude(), eventLongitudeChange)) {
+ req.setLongitude(eventLongitudeChange);
+ }
+ String photoPathChange = getStringOrNull(binding.photoPath.getText());
+ if (!Objects.equals(event.getPhotoPath(), photoPathChange)) {
+ req.setPhotoPath(photoPathChange);
+ }
+ return req;
+ }
+
+ public static ScheduleEventRequest createScheduleEventRequest(
+ EventDTO event, ActivityEventScheduleBinding binding) {
+ ScheduleEventRequest req = new ScheduleEventRequest();
+ OffsetDateTime eventStartingChange = getOffsetDateTime(binding.starting.getText());
+ if (!Objects.equals(event.getStarting(), eventStartingChange)) {
+ req.setStarting(eventStartingChange);
+ }
+ OffsetDateTime eventEndingChange = getOffsetDateTime(binding.ending.getText());
+ if (!Objects.equals(event.getEnding(), eventEndingChange)) {
+ req.setEnding(eventEndingChange);
+ }
+ return req;
+ }
+
public static boolean currentUserIsEventCreator(
AccountManager am, EventDTO event) {
return AuthHelper.getUserUuid(am).equals(event.getCreatorId());
}
public static void dumpEventDispatcherError(
- String tag, AccountManager am, EventDTO event) {
+ String tag, String userId, EventDTO event) {
Log.e(tag, "System error. EventDispatcher did wrong dispatching. " +
- "Current user is [" + AuthHelper.getUserUuid(am) + "], " +
+ "Current user is [" + userId + "], " +
"eventId [" + event.getId() + "], eventCreatorId [" + event.getCreatorId() + "]. " +
"Please, check server code and related entities.");
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/viewmodel/EventViewModel.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/viewmodel/EventViewModel.java
index 1df56dc..2db8481 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/event/viewmodel/EventViewModel.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/viewmodel/EventViewModel.java
@@ -1,6 +1,7 @@
package com.tom.meeter.context.event.viewmodel;
import static com.tom.meeter.context.auth.infrastructure.AuthHelper.getAuthHeader;
+import static com.tom.meeter.context.event.utils.Utils.currentUserIsEventCreator;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import android.accounts.AccountManager;
@@ -19,6 +20,8 @@
import com.tom.meeter.infrastructure.http.BaseOnNotAuthenticatedCallback;
import com.tom.meeter.infrastructure.http.HttpCodes;
+import java.util.Set;
+
import dagger.assisted.Assisted;
import dagger.assisted.AssistedInject;
import retrofit2.Call;
@@ -35,6 +38,7 @@ public class EventViewModel extends ViewModel {
private final Runnable onNotAuthenticated;
private final MutableLiveData event = new MutableLiveData<>();
+ private final MutableLiveData> transitions = new MutableLiveData<>();
private final MutableLiveData eventPhoto = new MutableLiveData<>();
@AssistedInject
@@ -53,7 +57,9 @@ public EventViewModel(
}
public void init() {
- eventService.getEvent(getAuthHeader(AccountManager.get(ctx)), eventId).enqueue(
+ AccountManager am = AccountManager.get(ctx);
+ String auth = getAuthHeader(am);
+ eventService.getEvent(auth, eventId).enqueue(
//TODO check toast...
new BaseOnNotAuthenticatedCallback<>(ctx, onNotAuthenticated) {
@Override
@@ -63,19 +69,39 @@ public void onResponse(Call call, Response resp) {
if (resp.code() != HttpCodes.OK || eventResp == null) {
return;
}
- event.setValue(eventResp);
+ event.postValue(eventResp);
+ if (currentUserIsEventCreator(am, eventResp)) {
+ fetchEventTransitions(auth);
+ }
String photoPath = eventResp.getPhotoPath();
if (photoPath == null) {
return;
}
imageDownloader.downloadEventImage(
photoPath, ctx, ImagesHelper::bigCircleImage,
- eventPhoto::setValue, onNotAuthenticated);
+ eventPhoto::postValue, onNotAuthenticated);
}
}
);
}
+ private void fetchEventTransitions(String auth) {
+ eventService.availableTransitions(auth, eventId).enqueue(
+ new BaseOnNotAuthenticatedCallback<>(ctx, onNotAuthenticated) {
+ @Override
+ public void onResponse(
+ Call> call,
+ Response> resp) {
+ super.onResponse(call, resp);
+ Set eventStatuses = resp.body();
+ if (resp.code() != HttpCodes.OK || eventStatuses == null) {
+ return;
+ }
+ transitions.postValue(eventStatuses);
+ }
+ });
+ }
+
@Override
protected void onCleared() {
logMethod(TAG, this);
@@ -89,4 +115,8 @@ public LiveData getEvent() {
public LiveData getEventPhoto() {
return eventPhoto;
}
+
+ public LiveData> getTransitions() {
+ return transitions;
+ }
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/launcher/Launcher.java b/AndroidClient/src/main/java/com/tom/meeter/context/launcher/Launcher.java
index f9d9e85..e5a421a 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/launcher/Launcher.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/launcher/Launcher.java
@@ -84,7 +84,7 @@ private void initialize() {
} else if (accounts.length == 1) {
//accountManager.setAuthToken(accounts[0], AUTH_TYPE, EXPIRED);
showMessage(Launcher.this, getString(R.string.check_token));
- checkToken((ign) -> dispatch(), this::finish, accountManager, this, tokenService);
+ checkToken((ign) -> dispatch(), this::finish, this, tokenService);
} else {
removeAllAccounts();
createAccountAndContinue();
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/network/service/EventHandlers.java b/AndroidClient/src/main/java/com/tom/meeter/context/network/service/EventHandlers.java
new file mode 100644
index 0000000..2304238
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/network/service/EventHandlers.java
@@ -0,0 +1,94 @@
+package com.tom.meeter.context.network.service;
+
+import static com.tom.meeter.context.network.service.SocketIOService.EVENTS_NOTIFICATIONS_CHANNEL;
+import static com.tom.meeter.context.network.service.SocketIOService.EVENTS_SEARCH_CHANNEL;
+import static com.tom.meeter.context.network.service.SocketIOService.NEW_SUBSCRIBER_CHANNEL;
+import static com.tom.meeter.context.network.utils.SocketIOCodes.NEW_SUBSCRIBER_CODE;
+import static com.tom.meeter.context.network.utils.Utils.getSimpleResponse;
+import static com.tom.meeter.context.notification.NotificationHelper.sendEventDeletedNotification;
+import static com.tom.meeter.context.notification.NotificationHelper.sendEventNotification;
+import static com.tom.meeter.context.notification.NotificationHelper.sendNotificationNewSubscriber;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.network.dto.UserDTO;
+import com.tom.meeter.context.network.exception.IncorrectResponseType;
+import com.tom.meeter.context.network.utils.SocketIOEventCode;
+import com.tom.meeter.infrastructure.eventbus.events.IncomeEvents;
+
+import org.greenrobot.eventbus.EventBus;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Arrays;
+
+public class EventHandlers {
+
+ private static final String TAG = EventHandlers.class.getCanonicalName();
+
+ private static final String CODE_KEY = "code";
+ private static final String MESSAGE_KEY = "message";
+ private static final String USER_KEY = "user";
+ private static final String EVENT_KEY = "event";
+ private static final String EVENT_ID_KEY = "eventId";
+
+ private EventHandlers() {
+ }
+
+ static void eventsNotificationsChannel(Context ctx, Object... args) {
+ JSONObject response = getSimpleResponse(JSONObject.class, args);
+ Log.d(TAG, EVENTS_NOTIFICATIONS_CHANNEL + " : " + response);
+ try {
+ int code = response.getInt(CODE_KEY);
+ SocketIOEventCode eventNotifyCode = SocketIOEventCode.fromCode(code);
+ if (eventNotifyCode == null) {
+ Log.d(TAG, "Unrecognized event code: " + code);
+ return;
+ }
+ JSONObject msg = response.getJSONObject(MESSAGE_KEY);
+ UserDTO user = new UserDTO(msg.getJSONObject(USER_KEY));
+
+ if (eventNotifyCode == SocketIOEventCode.DELETED) {
+ sendEventDeletedNotification(ctx, user, msg.getString(EVENT_ID_KEY));
+ return;
+ }
+ sendEventNotification(
+ ctx, user, eventNotifyCode,
+ new EventDTO(msg.getJSONObject(EVENT_KEY)));
+ } catch (JSONException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static void newSubscriberNotificationsChannel(Context ctx, Object... args) {
+ JSONObject response = getSimpleResponse(JSONObject.class, args);
+ Log.d(TAG, NEW_SUBSCRIBER_CHANNEL + " : " + response);
+ try {
+ if (response.getInt(CODE_KEY) == NEW_SUBSCRIBER_CODE) {
+ sendNotificationNewSubscriber(
+ ctx,
+ new UserDTO(response.getJSONObject(MESSAGE_KEY)));
+ }
+ } catch (JSONException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static void greetingsHandler(Object... args) {
+ Log.d(TAG, "SocketIO server welcomes the client. " + Arrays.toString(args));
+ }
+
+ static void eventsSearchHandler(Object... args) {
+ try {
+ JSONArray response = getSimpleResponse(JSONArray.class, args);
+ Log.d(TAG, EVENTS_SEARCH_CHANNEL + " : " + response);
+ EventBus.getDefault().post(IncomeEvents.fromJsonArray(response));
+ } catch (IncorrectResponseType e) {
+ JSONObject response = getSimpleResponse(JSONObject.class, args);
+ Log.e(TAG, EVENTS_SEARCH_CHANNEL + " : " + response);
+ }
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/network/service/NotificationHelper.java b/AndroidClient/src/main/java/com/tom/meeter/context/network/service/NotificationHelper.java
new file mode 100644
index 0000000..67a7a19
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/network/service/NotificationHelper.java
@@ -0,0 +1,60 @@
+package com.tom.meeter.context.network.service;
+
+import static com.tom.meeter.infrastructure.common.CommonHelper.getAppLogo;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+
+import androidx.core.app.NotificationCompat;
+
+import com.tom.meeter.R;
+import com.tom.meeter.context.launcher.Launcher;
+
+public class NotificationHelper {
+
+ private NotificationHelper() {
+ }
+
+ private static final String CHANNEL_ID = "socket_channel";
+
+ static void createNotificationChannel(Context ctx) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ NotificationChannel channel = new NotificationChannel(
+ CHANNEL_ID,
+ ctx.getString(R.string.network_channel),
+ NotificationManager.IMPORTANCE_LOW);
+ NotificationManager manager = ctx.getSystemService(NotificationManager.class);
+ if (manager == null) {
+ return;
+ }
+ manager.createNotificationChannel(channel);
+ }
+ }
+
+ static Notification buildForegroundNotification(Context ctx) {
+
+ Intent notificationIntent = new Intent(ctx, Launcher.class);
+ notificationIntent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ ctx,
+ 0,
+ notificationIntent,
+ PendingIntent.FLAG_IMMUTABLE
+ );
+
+ return new NotificationCompat.Builder(ctx, CHANNEL_ID)
+ .setContentTitle(ctx.getString(R.string.app_name))
+ .setContentText(ctx.getString(R.string.press_to_open_the_application))
+ .setContentIntent(pendingIntent)
+ .setSmallIcon(getAppLogo())
+ .setOngoing(true)
+ .build();
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/network/service/SocketIOService.java b/AndroidClient/src/main/java/com/tom/meeter/context/network/service/SocketIOService.java
index bf20039..5107bcc 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/network/service/SocketIOService.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/network/service/SocketIOService.java
@@ -1,12 +1,12 @@
package com.tom.meeter.context.network.service;
import static com.tom.meeter.context.auth.infrastructure.AuthHelper.peekToken;
-import static com.tom.meeter.context.network.utils.SocketIOCodes.NEW_SUBSCRIBER_CODE;
-import static com.tom.meeter.context.notification.NotificationHelper.sendEventDeletedNotification;
-import static com.tom.meeter.context.notification.NotificationHelper.sendEventNotification;
-import static com.tom.meeter.context.notification.NotificationHelper.sendNotificationNewSubscriber;
-import static com.tom.meeter.infrastructure.common.CommonHelper.getAppLogo;
-import static com.tom.meeter.infrastructure.common.Globals.AUTH_HEADER;
+import static com.tom.meeter.context.network.service.EventHandlers.eventsNotificationsChannel;
+import static com.tom.meeter.context.network.service.EventHandlers.newSubscriberNotificationsChannel;
+import static com.tom.meeter.context.network.service.NotificationHelper.buildForegroundNotification;
+import static com.tom.meeter.context.network.service.NotificationHelper.createNotificationChannel;
+import static com.tom.meeter.context.network.utils.Utils.readFlags;
+import static com.tom.meeter.context.network.utils.Utils.setupOptions;
import static com.tom.meeter.infrastructure.common.Globals.getSocketIOPath;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import static io.socket.client.Socket.EVENT_CONNECT;
@@ -15,41 +15,20 @@
import android.accounts.AccountManager;
import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
-import android.os.Build;
import android.os.IBinder;
import android.util.Log;
-import androidx.core.app.NotificationCompat;
-
-import com.tom.meeter.R;
-import com.tom.meeter.context.launcher.Launcher;
import com.tom.meeter.context.network.domain.SearchForEvents;
-import com.tom.meeter.context.network.dto.EventDTO;
-import com.tom.meeter.context.network.dto.UserDTO;
-import com.tom.meeter.context.network.exception.IncorrectResponseType;
-import com.tom.meeter.context.network.utils.SocketIOEventCode;
-import com.tom.meeter.infrastructure.common.Globals;
-import com.tom.meeter.infrastructure.eventbus.events.IncomeEvents;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
import java.io.IOException;
import java.net.SocketTimeoutException;
-import java.net.URISyntaxException;
+import java.net.URI;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
import io.socket.client.IO;
import io.socket.client.Socket;
@@ -61,19 +40,12 @@ public class SocketIOService extends Service {
public static final String STOP_CMD = "STOP";
- private static final String GREETINGS_CHANNEL = "greetings";
- private static final String EVENTS_SEARCH_CHANNEL = "events:search";
- private static final String EVENTS_NOTIFICATIONS_CHANNEL = "events:notifications";
- private static final String NEW_SUBSCRIBER_CHANNEL = "user:subscription:new";
+ static final String GREETINGS_CHANNEL = "greetings";
+ static final String EVENTS_SEARCH_CHANNEL = "events:search";
+ static final String EVENTS_NOTIFICATIONS_CHANNEL = "events:notifications";
+ static final String NEW_SUBSCRIBER_CHANNEL = "user:subscription:new";
- private static final String CODE_KEY = "code";
private static final String UNAUTHORIZED = "401";
- private static final String MESSAGE_KEY = "message";
- private static final String USER_KEY = "user";
- private static final String EVENT_KEY = "event";
- private static final String EVENT_ID_KEY = "eventId";
-
- private static final String CHANNEL_ID = "socket_channel";
private AccountManager accountManager;
private Socket socketClient;
@@ -93,10 +65,10 @@ public IBinder onBind(Intent intent) {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- Log.d(TAG, "SocketIOService onStartCommand(). " +
- "already started? " + initialized
- + " intent: " + intent + " flags: " + flags
- + " readFlags: " + readFlags(flags) + " startId: " + startId);
+ logMethod(TAG, this,
+ "already started? " + initialized,
+ "intent: " + intent, "flags: " + flags,
+ "readFlags: " + readFlags(flags), " startId: " + startId);
if (intent != null && STOP_CMD.equals(intent.getAction())) {
stopForeground(true);
@@ -107,26 +79,12 @@ public int onStartCommand(Intent intent, int flags, int startId) {
lastKnownAuthToken = peekToken(accountManager);
initializeSocketClient(false, lastKnownAuthToken);
- Notification notification = buildForegroundNotification();
- createNotificationChannel();
+ Notification notification = buildForegroundNotification(this);
+ createNotificationChannel(this);
startForeground(1, notification);
return START_STICKY;
}
- private void createNotificationChannel() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- NotificationChannel channel = new NotificationChannel(
- CHANNEL_ID,
- getString(R.string.network_channel),
- NotificationManager.IMPORTANCE_LOW);
- NotificationManager manager = getSystemService(NotificationManager.class);
- if (manager == null) {
- return;
- }
- manager.createNotificationChannel(channel);
- }
- }
-
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
@@ -154,28 +112,6 @@ public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
}
- private Notification buildForegroundNotification() {
-
- Intent notificationIntent = new Intent(this, Launcher.class);
- notificationIntent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-
- PendingIntent pendingIntent = PendingIntent.getActivity(
- this,
- 0,
- notificationIntent,
- PendingIntent.FLAG_IMMUTABLE
- );
-
- return new NotificationCompat.Builder(this, CHANNEL_ID)
- .setContentTitle(getString(R.string.app_name))
- .setContentText(getString(R.string.press_to_open_the_application))
- .setContentIntent(pendingIntent)
- .setSmallIcon(getAppLogo())
- .setOngoing(true)
- .build();
- }
-
private void initializeSocketClient(boolean forceInit, String authToken) {
if (initialized && !forceInit) {
Log.d(TAG, "SocketIOService is not going to initialize, " +
@@ -184,11 +120,7 @@ private void initializeSocketClient(boolean forceInit, String authToken) {
}
String uri = getSocketIOPath(getApplicationContext());
Log.d(TAG, "Configuring SocketIOClient for server: " + uri);
- try {
- socketClient = IO.socket(uri, setupOptions(authToken));
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
+ socketClient = IO.socket(URI.create(uri), setupOptions(authToken));
socketClient.on(EVENT_CONNECT,
args -> {
@@ -212,7 +144,7 @@ private void initializeSocketClient(boolean forceInit, String authToken) {
return;
}
if (UNAUTHORIZED.equals(ioException.getMessage())) {
- Log.i(TAG, "SocketIOService received authorization error. " +
+ Log.i(TAG, "SocketIOService received an authorization error. " +
"It is not possible to connect to the server with provided authorization. " +
"Server is going to disconnect and not going to receive any " +
"messages until recreateServer() is called.");
@@ -223,18 +155,27 @@ private void initializeSocketClient(boolean forceInit, String authToken) {
}
});
- socketClient.on(GREETINGS_CHANNEL, SocketIOService::greetingsHandler);
- socketClient.on(EVENTS_SEARCH_CHANNEL, SocketIOService::eventsSearchHandler);
- socketClient.on(EVENTS_NOTIFICATIONS_CHANNEL, this::eventsNotificationsChannel);
- socketClient.on(NEW_SUBSCRIBER_CHANNEL, this::newSubscriberNotificationsChannel);
+ socketClient.on(GREETINGS_CHANNEL, EventHandlers::greetingsHandler);
+ socketClient.on(EVENTS_SEARCH_CHANNEL, EventHandlers::eventsSearchHandler);
+ socketClient.on(EVENTS_NOTIFICATIONS_CHANNEL,
+ args -> eventsNotificationsChannel(SocketIOService.this, args));
+ socketClient.on(NEW_SUBSCRIBER_CHANNEL,
+ args -> newSubscriberNotificationsChannel(SocketIOService.this, args));
socketClient.connect();
EventBus.getDefault().register(this);
- Log.d(TAG, "SocketIOClient is going to start... connected? {"
- + socketClient.connected() + "}, isActive? {" + socketClient.isActive() + "}.");
+ Log.d(TAG, "SocketIOClient is going to start. " +
+ "connected? {" + socketClient.connected() + "}, " +
+ "isActive? {" + socketClient.isActive() + "}.");
socketClient.emit(GREETINGS_CHANNEL, "Client greetings.");
initialized = true;
}
+ @Subscribe
+ public void onMessageEvent(SearchForEvents event) {
+ Log.d(TAG, "onMessageEvent: [" + EVENTS_SEARCH_CHANNEL + "] : " + event);
+ socketClient.emit(EVENTS_SEARCH_CHANNEL, event.toJson());
+ }
+
@Override
public void onDestroy() {
logMethod(TAG, this);
@@ -242,7 +183,7 @@ public void onDestroy() {
super.onDestroy();
}
- public void recreateServer() {
+ private void recreateServer() {
disconnect();
lastKnownAuthToken = peekToken(accountManager);
initializeSocketClient(initialized, lastKnownAuthToken);
@@ -255,111 +196,4 @@ private void disconnect() {
socketClient.off();
initialized = false;
}
-
- @Subscribe
- public void onMessageEvent(SearchForEvents event) {
- Log.d(TAG, "onMessageEvent: [" + EVENTS_SEARCH_CHANNEL + "] : " + event);
- socketClient.emit(EVENTS_SEARCH_CHANNEL, event.toJson());
- }
-
- private void eventsNotificationsChannel(Object... args) {
- JSONObject response = getSimpleResponse(JSONObject.class, args);
- Log.d(TAG, EVENTS_NOTIFICATIONS_CHANNEL + " : " + response);
- try {
- int code = response.getInt(CODE_KEY);
- SocketIOEventCode eventNotifyCode = SocketIOEventCode.fromCode(code);
- if (eventNotifyCode == null) {
- Log.d(TAG, "Unrecognized event code: " + code);
- return;
- }
- JSONObject msg = response.getJSONObject(MESSAGE_KEY);
- UserDTO user = new UserDTO(msg.getJSONObject(USER_KEY));
-
- if (eventNotifyCode == SocketIOEventCode.DELETED) {
- sendEventDeletedNotification(this, user, msg.getString(EVENT_ID_KEY));
- return;
- }
- sendEventNotification(
- this, user, eventNotifyCode,
- new EventDTO(msg.getJSONObject(EVENT_KEY)));
- } catch (JSONException e) {
- throw new RuntimeException(e);
- }
- }
-
- private void newSubscriberNotificationsChannel(Object... args) {
- JSONObject response = getSimpleResponse(JSONObject.class, args);
- Log.d(TAG, NEW_SUBSCRIBER_CHANNEL + " : " + response);
- try {
- if (response.getInt(CODE_KEY) == NEW_SUBSCRIBER_CODE) {
- sendNotificationNewSubscriber(
- this,
- new UserDTO(response.getJSONObject(MESSAGE_KEY)));
- }
- } catch (JSONException e) {
- throw new RuntimeException(e);
- }
- }
-
- private static String readFlags(int flags) {
- if ((flags & START_FLAG_REDELIVERY) == START_FLAG_REDELIVERY)
- return "START_FLAG_REDELIVERY";
- if ((flags & START_FLAG_RETRY) == START_FLAG_RETRY)
- return "START_FLAG_RETRY";
- if (flags == 0) {
- return "zero";
- }
- throw new RuntimeException("flag???" + flags);
- }
-
- private static IO.Options setupOptions(String authToken) {
- IO.Options result = new IO.Options();
- result.extraHeaders = setupAuthHeader(authToken);
- return result;
- }
-
- private static Map> setupAuthHeader(
- String authToken) {
- Map> result = new HashMap<>();
- result.put(
- AUTH_HEADER,
- Collections.singletonList(
- Globals.getAuthHeader(authToken)));
- return result;
- }
-
- private static void greetingsHandler(Object... args) {
- Log.d(TAG, "SocketIO server welcomes the client. " + Arrays.toString(args));
- }
-
- private static void eventsSearchHandler(Object... args) {
- try {
- JSONArray response = getSimpleResponse(JSONArray.class, args);
- Log.d(TAG, EVENTS_SEARCH_CHANNEL + " : " + response);
- EventBus.getDefault().post(IncomeEvents.fromJsonArray(response));
- } catch (IncorrectResponseType e) {
- JSONObject response = getSimpleResponse(JSONObject.class, args);
- Log.e(TAG, EVENTS_SEARCH_CHANNEL + " : " + response);
- }
- }
-
- private static T getSimpleResponse(
- Class aClass, Object[] args) {
- if (!validateSingleMessageResponse(aClass, args)) {
- throw new IncorrectResponseType("Incorrect response for " + aClass
- + " with response " + Arrays.toString(args));
- }
- return (T) args[0];
- }
-
- private static boolean validateSingleMessageResponse(
- Class> aClass, Object... args) {
- if (args.length != 1) {
- return false;
- }
- if (!aClass.isInstance(args[0])) {
- return false;
- }
- return true;
- }
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/network/utils/Utils.java b/AndroidClient/src/main/java/com/tom/meeter/context/network/utils/Utils.java
new file mode 100644
index 0000000..cd4468c
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/network/utils/Utils.java
@@ -0,0 +1,69 @@
+package com.tom.meeter.context.network.utils;
+
+import static android.app.Service.START_FLAG_REDELIVERY;
+import static android.app.Service.START_FLAG_RETRY;
+import static com.tom.meeter.infrastructure.common.Globals.AUTH_HEADER;
+
+import com.tom.meeter.context.network.exception.IncorrectResponseType;
+import com.tom.meeter.infrastructure.common.Globals;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import io.socket.client.IO;
+
+public class Utils {
+ private Utils() {
+ }
+
+ public static IO.Options setupOptions(String authToken) {
+ IO.Options result = new IO.Options();
+ result.extraHeaders = setupAuthHeader(authToken);
+ return result;
+ }
+
+ static Map> setupAuthHeader(String authToken) {
+ Map> result = new HashMap<>();
+ result.put(
+ AUTH_HEADER,
+ Collections.singletonList(
+ Globals.getAuthHeader(authToken)));
+ return result;
+ }
+
+ public static String readFlags(int flags) {
+ if ((flags & START_FLAG_REDELIVERY) == START_FLAG_REDELIVERY)
+ return "START_FLAG_REDELIVERY";
+ if ((flags & START_FLAG_RETRY) == START_FLAG_RETRY)
+ return "START_FLAG_RETRY";
+ if (flags == 0) {
+ return "zero";
+ }
+ throw new RuntimeException("flag???" + flags);
+ }
+
+
+ public static T getSimpleResponse(
+ Class aClass, Object[] args) {
+ if (!validateSingleMessageResponse(aClass, args)) {
+ throw new IncorrectResponseType("Incorrect response for " + aClass
+ + " with response " + Arrays.toString(args));
+ }
+ return (T) args[0];
+ }
+
+ public static boolean validateSingleMessageResponse(
+ Class> aClass, Object... args) {
+ if (args.length != 1) {
+ return false;
+ }
+ if (!aClass.isInstance(args[0])) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/DrawerUtils.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/DrawerUtils.java
index 1cdcefc..9161303 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/DrawerUtils.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/DrawerUtils.java
@@ -9,6 +9,7 @@
import static com.tom.meeter.context.profile.component.activity.ProfileActivity.DRAWER_OPEN_SOURCE_ID;
import static com.tom.meeter.context.profile.component.activity.ProfileActivity.DRAWER_PROFILE_ID;
import static com.tom.meeter.context.profile.component.activity.ProfileActivity.DRAWER_SETTINGS_ID;
+import static com.tom.meeter.context.profile.component.activity.ProfileActivity.DRAWER_YOUR_EVENTS_ID;
import android.util.Log;
@@ -53,6 +54,9 @@ static IIcon googleMaterialIconPack(Long id) {
return GoogleMaterial.Icon.gmd_event;
//return GoogleMaterial.Icon.gmd_perm_contact_calendar;
}
+ if (id == DRAWER_YOUR_EVENTS_ID) {
+ return GoogleMaterial.Icon.gmd_event;
+ }
if (id == DRAWER_NOTIFICATION_ID) {
//return GoogleMaterial.Icon.gmd_visibility;
//return GoogleMaterial.Icon.gmd_notifications;
@@ -87,6 +91,9 @@ static IIcon fontAwesomeIconPack(Long id) {
if (id == DRAWER_NEW_EVENT_ID) {
return FontAwesome.Icon.faw_calendar;
}
+ if (id == DRAWER_YOUR_EVENTS_ID) {
+ return FontAwesome.Icon.faw_calendar;
+ }
if (id == DRAWER_NOTIFICATION_ID) {
return FontAwesome.Icon.faw_eye;
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/ProfileActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/ProfileActivity.java
index 20ee2ac..c7f9323 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/ProfileActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/ProfileActivity.java
@@ -14,6 +14,7 @@
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Intent;
+import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
@@ -21,46 +22,55 @@
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
-import android.widget.ImageView;
-import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
+import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.mikepenz.iconics.typeface.IIcon;
+import com.mikepenz.materialdrawer.AccountHeader;
+import com.mikepenz.materialdrawer.AccountHeaderBuilder;
import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.DrawerBuilder;
+import com.mikepenz.materialdrawer.holder.StringHolder;
import com.mikepenz.materialdrawer.model.DividerDrawerItem;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
+import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem;
import com.mikepenz.materialdrawer.model.SectionDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import com.tom.meeter.App;
import com.tom.meeter.R;
-import com.tom.meeter.context.auth.activity.LoginActivity;
import com.tom.meeter.context.auth.infrastructure.AuthHelper;
+import com.tom.meeter.context.image.ImageDownloader;
+import com.tom.meeter.context.launcher.Launcher;
import com.tom.meeter.context.network.service.SocketIOService;
import com.tom.meeter.context.profile.component.StatusesFilterDialog;
import com.tom.meeter.context.profile.component.fragment.CreateEventFragment;
import com.tom.meeter.context.profile.component.fragment.EventsFragment;
import com.tom.meeter.context.profile.component.fragment.ProfileEventsFragment;
import com.tom.meeter.context.profile.component.fragment.ProfileFragment;
+import com.tom.meeter.context.profile.component.viewmodel.ProfileViewModel;
+import com.tom.meeter.context.profile.factory.ProfileAssistedFactory;
import com.tom.meeter.context.profile.message.SettingsResponse;
import com.tom.meeter.context.profile.service.ProfileService;
import com.tom.meeter.context.profile.service.SettingsService;
import com.tom.meeter.context.token.service.TokenService;
-import com.tom.meeter.databinding.ProfileActivityBinding;
+import com.tom.meeter.databinding.ActivityProfileBinding;
import com.tom.meeter.infrastructure.common.Globals;
+import com.tom.meeter.infrastructure.common.ImagesHelper;
import com.tom.meeter.infrastructure.http.ErrorLogger;
import com.tom.meeter.infrastructure.http.HttpCodes;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -76,32 +86,36 @@ public class ProfileActivity extends AppCompatActivity {
private static final String TAG = ProfileActivity.class.getCanonicalName();
- static final long DRAWER_PROFILE_ID = 0;
+ static final short DRAWER_PROFILE_ID = 0;
static final String PROFILE_FRAGMENT_TAG = "profile_fragment_tag";
- static final long DRAWER_EVENTS_ID = 1;
+ static final short DRAWER_EVENTS_ID = 1;
static final String EVENTS_FRAGMENT_TAG = "events_fragment_tag";
- static final long DRAWER_NEW_EVENT_ID = 2;
+ static final short DRAWER_NEW_EVENT_ID = 2;
static final String NEW_EVENT_FRAGMENT_TAG = "new_event_fragment_tag";
- static final long DRAWER_NOTIFICATION_ID = 3;
+ static final short DRAWER_YOUR_EVENTS_ID = 3;
+ static final String YOUR_EVENTS_FRAGMENT_TAG = "your_events_fragment_tag";
+
+ static final short DRAWER_NOTIFICATION_ID = 4;
static final String NOTIFICATIONS_FRAGMENT_TAG = "notifications_fragment_tag";
- static final long DRAWER_SETTINGS_ID = 10; // -> no need a tag.
+ static final short DRAWER_SETTINGS_ID = 10; // -> no need a tag.
- static final long DRAWER_HELP_ID = 11;
- static final long DRAWER_OPEN_SOURCE_ID = 12;
- static final long DRAWER_CONTACT_ID = 13;
- static final long DRAWER_LOGOUT_ID = 99;
+ static final short DRAWER_HELP_ID = 11;
+ static final short DRAWER_OPEN_SOURCE_ID = 12;
+ static final short DRAWER_CONTACT_ID = 13;
+ static final short DRAWER_LOGOUT_ID = 99;
- private static final Map DRAWER_FRAGMENT_TAGS = new HashMap<>();
+ private static final Map DRAWER_FRAGMENT_TAGS = new HashMap<>();
static {
DRAWER_FRAGMENT_TAGS.put(DRAWER_PROFILE_ID, PROFILE_FRAGMENT_TAG);
DRAWER_FRAGMENT_TAGS.put(DRAWER_EVENTS_ID, EVENTS_FRAGMENT_TAG);
DRAWER_FRAGMENT_TAGS.put(DRAWER_NEW_EVENT_ID, NEW_EVENT_FRAGMENT_TAG);
+ DRAWER_FRAGMENT_TAGS.put(DRAWER_YOUR_EVENTS_ID, YOUR_EVENTS_FRAGMENT_TAG);
DRAWER_FRAGMENT_TAGS.put(DRAWER_NOTIFICATION_ID, NOTIFICATIONS_FRAGMENT_TAG);
//DRAWER_SETTINGS_ID intentionally don't need to have a tag,
@@ -114,8 +128,10 @@ public class ProfileActivity extends AppCompatActivity {
*/
}
- private Toolbar toolbar;
private boolean showMenu = false;
+ private ProfileDrawerItem profile;
+ private AccountHeader header;
+ private static final short PROFILE_ID = 1;
enum IconPackEnum {
FONT_AWESOME,
@@ -123,31 +139,29 @@ enum IconPackEnum {
}
private IconPackEnum icons = IconPackEnum.FONT_AWESOME;
- private final Map drawerFragmentNames = new HashMap<>();
+ private final Map drawerFragmentNames = new HashMap<>();
- private ProfileActivityBinding binding;
+ private ActivityProfileBinding binding;
// flag to load home fragment when user presses back key
private boolean shouldLoadHomeFragOnBackPress = true;
- // urls to load navigation header background image
- // and profile image
- private ImageView imgNavHeaderBg, imgProfile;
- private TextView txtName, txtWebsite;
-
private FloatingActionButton fab;
@Inject
SettingsService settingsService;
@Inject
+ ImageDownloader imgDownloader;
+ @Inject
ProfileService profileService;
@Inject
TokenService tokenService;
+ @Inject
+ ProfileAssistedFactory assistedFactory;
private AccountManager accountManager;
-
- private long lastNavItemId = DRAWER_PROFILE_ID;
-
+ private ProfileViewModel viewModel;
+ private short lastNavItemId = DRAWER_PROFILE_ID;
private Drawer drawer = null;
public ProfileActivity() {
@@ -176,11 +190,11 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
}
private void hideToolbar() {
- toolbar.setVisibility(View.GONE);
+ binding.profileActivityToolbar.setVisibility(View.GONE);
}
private void showToolbar() {
- toolbar.setVisibility(View.VISIBLE);
+ binding.profileActivityToolbar.setVisibility(View.VISIBLE);
}
@Override
@@ -189,17 +203,18 @@ protected void onCreate(Bundle savedInstanceState) {
logMethod(TAG, this);
- binding = ProfileActivityBinding.inflate(getLayoutInflater());
+ binding = ActivityProfileBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
((App) getApplication()).getProfileComponent().inject(this);
+
accountManager = AccountManager.get(this);
//setToken(accountManager, Launcher.EXPIRED);
checkToken(
(token) -> onInit(savedInstanceState),
- this::finish, accountManager, this, tokenService);
+ this::finish, this, tokenService);
}
private void onInit(Bundle savedInstanceState) {
@@ -207,16 +222,46 @@ private void onInit(Bundle savedInstanceState) {
ContextCompat.startForegroundService(
this, new Intent(this, SocketIOService.class));
- loadPrefsFromServer();
+ loadPrefsFromServer(null);
- toolbar = binding.profileActivityToolbar;
- setSupportActionBar(toolbar);
+ setSupportActionBar(binding.profileActivityToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setupNameMapping(
drawerFragmentNames,
getResources().getStringArray(R.array.nav_item_activity_titles));
- setupDrawer(toolbar, icons);
+ setupDrawer(icons);
+
+ viewModel = new ViewModelProvider(
+ this,
+ assistedFactory.factory(
+ assistedFactory, this, this::recreate))
+ .get(ProfileViewModel.class);
+
+ viewModel.getProfile()
+ .observe(
+ this,
+ user -> {
+ profile.withName(user.getName() + " " + user.getSurname());
+ String photoPath = user.getPhotoPath();
+ if (photoPath == null) {
+ header.updateProfile(profile);
+ return;
+ }
+ imgDownloader.downloadUserImage(
+ photoPath, this,
+ ImagesHelper::bigCircleImage,
+ (photo) -> header.updateProfile(profile.withIcon(photo)),
+ this::recreate);
+ });
+
+ viewModel.getEvents()
+ .observe(
+ this,
+ es -> drawer.updateBadge(
+ DRAWER_YOUR_EVENTS_ID,
+ new StringHolder(String.valueOf(es.size())))
+ );
drawer.getAdapter()
.withOnBindViewHolderListener(new DrawerUtils.OnBindViewHolderListenerImplBase());
@@ -229,43 +274,27 @@ private void onInit(Bundle savedInstanceState) {
}
}
- private void loadPrefsFromServer() {
- settingsService.getSettings(AuthHelper.getAuthHeader(accountManager)).enqueue(
+ private void loadPrefsFromServer(@Nullable String auth) {
+ settingsService.getSettings(getAuthFrom(auth)).enqueue(
new ErrorLogger<>(this) {
@Override
public void onResponse(
- Call call, Response resp) {
- if (resp.code() == HttpCodes.NOT_AUTHENTICATED) {
+ Call call,
+ Response resp) {
+ if (resp.code() == HttpCodes.NOT_AUTHENTICATED && auth == null) {
invalidateToken(accountManager, ProfileActivity.this,
- fresh -> loadPrefsFromServerRetry(fresh), () -> finishAndRemoveTask());
- }
- if (resp.code() == HttpCodes.NOT_FOUND) {
- // As no settings on the server ...
- cleanLocalPrefs(ProfileActivity.this);
- return;
- }
- if (resp.body() == null) {
+ token -> loadPrefsFromServer(Globals.getAuthHeader(token)),
+ () -> finishAndRemoveTask());
return;
}
- // As settings exist on the server...
- updateLocalPrefs(ProfileActivity.this, resp.body());
- }
- });
- }
- private void loadPrefsFromServerRetry(String freshToken) {
- settingsService.getSettings(Globals.getAuthHeader(freshToken))
- .enqueue(new ErrorLogger<>(this) {
- @Override
- public void onResponse(
- Call call, Response resp) {
if (resp.code() == HttpCodes.NOT_FOUND) {
cleanLocalPrefs(ProfileActivity.this);
// no settings on the server etc...
return;
}
if (resp.body() == null) {
- Log.d(TAG, "ProfileActivity: /settings returns null on retry...");
+ Log.d(TAG, "ProfileActivity: /settings returns null...");
return;
}
// As settings exist on the server...
@@ -274,10 +303,14 @@ public void onResponse(
});
}
+ @NonNull
+ private String getAuthFrom(@Nullable String auth) {
+ return auth != null ? auth : AuthHelper.getAuthHeader(accountManager);
+ }
+
@Override
public void onBackPressed() {
logMethod(TAG, this);
- //drawer.updateBadge(DRAWER_CONTACT_ID, new StringHolder("okok"));
//switchDrawerIcons();
//updateDrawerIcons(drawer, GOOGLE_MATERIAL_ICONS);
@@ -320,13 +353,13 @@ protected void onDestroy() {
private boolean onDrawerItemClickListener(
View view, int position, IDrawerItem, ?> drawerItem) {
- long identifier = drawerItem.getIdentifier();
+ short identifier = (short) drawerItem.getIdentifier();
Log.d(TAG, "User selected drawer item: "
+ identifier + " previous was: " + lastNavItemId);
if (identifier == DRAWER_PROFILE_ID
|| identifier == DRAWER_EVENTS_ID
|| identifier == DRAWER_NEW_EVENT_ID
- || identifier == DRAWER_NOTIFICATION_ID) {
+ || identifier == DRAWER_YOUR_EVENTS_ID) {
lastNavItemId = identifier;
} else if (identifier == DRAWER_LOGOUT_ID) {
handleLogout();
@@ -358,6 +391,7 @@ private void renderSelectedFragment() {
// if user select the current navigation menu again, don't do anything
// just close the navigation drawer
FragmentManager fm = getSupportFragmentManager();
+ dumpFragmentManagerState(fm);
if (fm.findFragmentByTag(tag) != null) {
drawer.closeDrawer();
//toggleFab();
@@ -367,10 +401,9 @@ private void renderSelectedFragment() {
// Since new navigation comes...
setupActionBarTitle(lastNavItemId);
- if (!fm.isStateSaved()) {
- replaceFragment(fm, () -> createFragment(lastNavItemId), () -> tag)
- .run();
- }
+ replaceFragment(
+ fm, () -> createFragment(lastNavItemId), () -> tag)
+ .run();
// show or hide the fab button
@@ -382,19 +415,34 @@ private void renderSelectedFragment() {
//invalidateOptionsMenu();
}
+ private void dumpFragmentManagerState(FragmentManager fm) {
+ List fragments = fm.getFragments();
+ logMethod(TAG, this,
+ "isStateSaved: " + fm.isStateSaved(),
+ "fragments size: " + fragments.size());
+ for (Fragment f : fragments) {
+ Log.d(TAG, f.toString());
+ }
+ StringWriter sw = new StringWriter();
+ fm.dump(TAG, null, new PrintWriter(sw), null);
+ Log.d(TAG, sw.toString());
+ }
+
private void restoreSettings() {
logMethod(TAG, this);
- String tag = getCurrentFragmentTag(getSupportFragmentManager());
+ FragmentManager fm = getSupportFragmentManager();
+ dumpFragmentManagerState(fm);
+ String tag = getCurrentFragmentTag(fm);
if (EVENTS_FRAGMENT_TAG.equals(tag)) {
showMenu = true;
}
- Long fragmentId = getFragmentIdByTag(tag);
+ Short fragmentId = getFragmentIdByTag(tag);
drawer.setSelection(fragmentId, false);
setupActionBarTitle(fragmentId);
drawer.closeDrawer();
}
- private void setupActionBarTitle(Long fragmentId) {
+ private void setupActionBarTitle(Short fragmentId) {
String title = requireNonNull(
drawerFragmentNames.get(fragmentId),
"Drawer toolbar title should be present.");
@@ -405,8 +453,8 @@ private void setupActionBarTitle(Long fragmentId) {
}
@NonNull
- private static Long getFragmentIdByTag(String tag) {
- for (Long id : DRAWER_FRAGMENT_TAGS.keySet()) {
+ private static Short getFragmentIdByTag(String tag) {
+ for (Short id : DRAWER_FRAGMENT_TAGS.keySet()) {
if (tag.equals(DRAWER_FRAGMENT_TAGS.get(id))) {
return id;
}
@@ -425,43 +473,48 @@ private static String getCurrentFragmentTag(FragmentManager fm) {
}
private void handleLogout() {
- Intent stopIntent = new Intent(this, SocketIOService.class);
- stopIntent.setAction(SocketIOService.STOP_CMD);
- startService(stopIntent);
+ startService(
+ new Intent(this, SocketIOService.class)
+ .setAction(SocketIOService.STOP_CMD));
cleanLocalPrefs(this);
Account acc = getSingleAccount(accountManager);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
accountManager.removeAccount(
acc, this, future -> {
Log.d(TAG, "Account '" + acc.name + "' removed.");
- Intent intent = new Intent(this, LoginActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(intent);
+ startActivity(
+ new Intent(this, Launcher.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
finish();
}, null);
}
}
private static void setupNameMapping(
- Map mapping, String[] namesFromResources) {
+ Map mapping, String[] namesFromResources) {
mapping.put(DRAWER_PROFILE_ID, namesFromResources[0]);
mapping.put(DRAWER_EVENTS_ID, namesFromResources[1]);
mapping.put(DRAWER_NEW_EVENT_ID, namesFromResources[2]);
- mapping.put(DRAWER_NOTIFICATION_ID, namesFromResources[3]);
- mapping.put(DRAWER_SETTINGS_ID, namesFromResources[4]);
+ mapping.put(DRAWER_YOUR_EVENTS_ID, namesFromResources[3]);
+ mapping.put(DRAWER_NOTIFICATION_ID, namesFromResources[4]);
+ mapping.put(DRAWER_SETTINGS_ID, namesFromResources[5]);
}
private static Runnable replaceFragment(
FragmentManager fm, Provider fragmentP, Provider currentTagP) {
return () -> {
+ if (fm.isStateSaved()) {
+ Log.e(TAG, "in replaceFragment(), but state is saved, nothing to do. ");
+ return;
+ }
// update the main content by replacing fragments
FragmentTransaction txn = fm.beginTransaction();
//txn.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
txn.replace(R.id.profile_activity_frame, fragmentP.get(), currentTagP.get());
// for some reasons txn.commit leads to errors
// and txn.commitAllowingStateLoss doesn't
- txn.commit();
- //txn.commitAllowingStateLoss();
+ //txn.commit();
+ txn.commitAllowingStateLoss();
};
}
@@ -474,8 +527,10 @@ private static Fragment createFragment(long navigationMenuIndex) {
result = new EventsFragment();
} else if (navigationMenuIndex == DRAWER_NEW_EVENT_ID) {
result = new CreateEventFragment();
- } else if (navigationMenuIndex == DRAWER_NOTIFICATION_ID) {
+ } else if (navigationMenuIndex == DRAWER_YOUR_EVENTS_ID) {
result = new ProfileEventsFragment();
+/* } else if (navigationMenuIndex == DRAWER_NOTIFICATION_ID) {
+ result = new ProfileEventsFragment();*/
} else {
result = new ProfileFragment();
}
@@ -517,20 +572,36 @@ public void onDrawerSlide(View drawerView, float slideOffset) {
};
}
- private void setupDrawer(Toolbar toolbar, IconPackEnum icons) {
+ private void setupDrawer(IconPackEnum icons) {
drawer = new DrawerBuilder()
.withActivity(this)
- .withToolbar(toolbar)
+ //? .withFullscreen(true)
+ //.withSliderBackgroundColorRes(R.color.navigationBarColor)
+ .withAccountHeader(
+ header = new AccountHeaderBuilder()
+ .withActivity(this)
+ .withTextColor(Color.WHITE)
+ .withHeaderBackground(R.color.navigationBarColor)
+ /*.withHeaderBackground(R.drawable.nav_menu_header_bg)*/
+ .addProfiles(profile = new ProfileDrawerItem()
+ .withIdentifier(PROFILE_ID)
+ .withName("...")
+ //.withEmail("Email")
+ .withIcon(R.drawable.user_500x500_removebg))
+ .withSelectionListEnabledForSingleProfile(false)
+ .build())
+ .withToolbar(binding.profileActivityToolbar)
.withActionBarDrawerToggle(true)
- .withHeader(R.layout.drawer_header)
+ //.withHeader(R.layout.drawer_header)
.addDrawerItems(
new PrimaryDrawerItem()
- .withIdentifier(DRAWER_PROFILE_ID).withName(R.string.drawer_item_profile)
- .withBadge("99"),
+ .withIdentifier(DRAWER_PROFILE_ID).withName(R.string.drawer_item_profile),
new PrimaryDrawerItem()
.withIdentifier(DRAWER_EVENTS_ID).withName(R.string.drawer_item_events),
new PrimaryDrawerItem()
.withIdentifier(DRAWER_NEW_EVENT_ID).withName(R.string.drawer_item_new_event),
+ new PrimaryDrawerItem()
+ .withIdentifier(DRAWER_YOUR_EVENTS_ID).withName(R.string.your_events),
new PrimaryDrawerItem()
.withIdentifier(DRAWER_NOTIFICATION_ID).withName(R.string.drawer_item_notifications)
.withBadge("6"),
@@ -556,6 +627,7 @@ private void setupDrawer(Toolbar toolbar, IconPackEnum icons) {
this::getCurrentFocus,
() -> (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE)))
.build();
+ drawer.getDrawerLayout().setFitsSystemWindows(false);
updateDrawerIcons(icons);
}
@@ -573,6 +645,7 @@ private void updateDrawerIcons(IconPackEnum iconPack) {
updateIconFor(drawer, iconProvider, DRAWER_PROFILE_ID);
updateIconFor(drawer, iconProvider, DRAWER_EVENTS_ID);
updateIconFor(drawer, iconProvider, DRAWER_NEW_EVENT_ID);
+ updateIconFor(drawer, iconProvider, DRAWER_YOUR_EVENTS_ID);
updateIconFor(drawer, iconProvider, DRAWER_NOTIFICATION_ID);
updateIconFor(drawer, iconProvider, DRAWER_SETTINGS_ID);
updateIconFor(drawer, iconProvider, DRAWER_HELP_ID);
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SettingsActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SettingsActivity.java
index 6fd56e3..78a1159 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SettingsActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SettingsActivity.java
@@ -12,14 +12,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
import com.tom.meeter.App;
import com.tom.meeter.R;
import com.tom.meeter.context.profile.component.fragment.SettingsFragment;
import com.tom.meeter.context.profile.message.SettingsCreateOrUpdate;
import com.tom.meeter.context.profile.service.SettingsService;
-import com.tom.meeter.databinding.SettingsActivityBinding;
+import com.tom.meeter.databinding.ActivitySettingsBinding;
import com.tom.meeter.infrastructure.common.PreferencesHelper;
import javax.inject.Inject;
@@ -31,7 +30,7 @@ public class SettingsActivity extends AppCompatActivity {
@Inject
SettingsService settingsService;
- private SettingsActivityBinding binding;
+ private ActivitySettingsBinding binding;
private boolean trackUserBeforeChange;
private int searchAreaBeforeChange;
@@ -42,22 +41,17 @@ protected void onCreate(Bundle savedInstanceState) {
logMethod(TAG, this);
- ((App) getApplication()).getProfileComponent().inject(this);
-
- binding = SettingsActivityBinding.inflate(getLayoutInflater());
+ binding = ActivitySettingsBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
- Toolbar toolbar = binding.settingsActivityToolbar;
- setSupportActionBar(toolbar);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- readCurrentPreferences();
+ ((App) getApplication()).getProfileComponent().inject(this);
- // below line is to change
- // the title of our action bar.
+ setSupportActionBar(binding.includeToolbar.toolbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.settings);
+ readCurrentPreferences();
// below line is used to check if
// frame layout is empty or not.
if (savedInstanceState != null) {
@@ -148,4 +142,4 @@ protected void onRestart() {
logMethod(TAG, this);
super.onRestart();
}
-}
\ No newline at end of file
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SubscribersActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SubscribersActivity.java
index 3d7e687..8841780 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SubscribersActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SubscribersActivity.java
@@ -49,9 +49,7 @@ protected void onCreate(Bundle savedInstanceState) {
((App) getApplication()).getProfileComponent().inject(this);
accountManager = AccountManager.get(this);
- checkToken(
- this::onInit, this::finish,
- accountManager, this, tokenService);
+ checkToken(this::onInit, this::finish, this, tokenService);
}
private void onInit(String token) {
@@ -67,8 +65,13 @@ private void onInit(String token) {
assistedFactory.factory(assistedFactory, this, onAuthFail))
.get(ProfileSubscribersViewModel.class);
+ binding.swipeRefreshLayout.setOnRefreshListener(() -> viewModel.init());
+
viewModel.getSubscribers()
- .observe(this, subs -> adapter.setData(subs));
+ .observe(this, subs -> {
+ binding.swipeRefreshLayout.setRefreshing(false);
+ adapter.setData(subs);
+ });
}
@Override
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SubscriptionsActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SubscriptionsActivity.java
index 58e1aff..6ba05df 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SubscriptionsActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/activity/SubscriptionsActivity.java
@@ -49,9 +49,7 @@ protected void onCreate(Bundle savedInstanceState) {
((App) getApplication()).getProfileComponent().inject(this);
accountManager = AccountManager.get(this);
- checkToken(
- (token) -> onInit(), this::finish,
- accountManager, this, tokenService);
+ checkToken((token) -> onInit(), this::finish, this, tokenService);
}
private void onInit() {
@@ -67,8 +65,13 @@ private void onInit() {
assistedFactory.factory(assistedFactory, this, onAuthFail))
.get(ProfileSubscriptionsViewModel.class);
+ binding.swipeRefreshLayout.setOnRefreshListener(() -> viewModel.init());
+
viewModel.getSubscriptions()
- .observe(this, subs -> adapter.setData(subs));
+ .observe(this, subs -> {
+ binding.swipeRefreshLayout.setRefreshing(false);
+ adapter.setData(subs);
+ });
}
@Override
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/binder/EventBinderImpl.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/binder/EventBinderImpl.java
index b0d318e..8b28e51 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/binder/EventBinderImpl.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/binder/EventBinderImpl.java
@@ -1,6 +1,7 @@
package com.tom.meeter.context.profile.component.binder;
import static com.tom.meeter.infrastructure.common.CommonHelper.handleEventStatus;
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import android.accounts.AccountManager;
import android.content.Context;
@@ -57,6 +58,7 @@ public void setOnAuthFailAction(Runnable onAuthFail) {
@Override
public void bind(EventViewHolder holder, EventDTO event) {
+ logMethod(TAG, this);
//Log.d(TAG, "Current thread: " + Thread.currentThread().getName());
String photoPath = event.getPhotoPath();
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ActiveEventsFragment.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ActiveEventsFragment.java
index 016fff0..cb1150e 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ActiveEventsFragment.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ActiveEventsFragment.java
@@ -90,4 +90,10 @@ public void onDestroy() {
EventBus.getDefault().unregister(this);
logMethod(TAG, this, "Unregistered event bus");
}
+
+ @Override
+ public void onDestroyView() {
+ logMethod(TAG, this);
+ super.onDestroyView();
+ }
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/CreateEventFragment.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/CreateEventFragment.java
index 4891fb0..065460d 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/CreateEventFragment.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/CreateEventFragment.java
@@ -49,6 +49,7 @@
import com.tom.meeter.context.image.ImageDownloader;
import com.tom.meeter.context.image.activity.UploadEventImageActivity;
import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.profile.component.activity.ProfileActivity;
import com.tom.meeter.context.profile.message.CreateEventRequest;
import com.tom.meeter.context.profile.service.ProfileService;
import com.tom.meeter.databinding.FragmentCreateEventBinding;
@@ -136,7 +137,8 @@ public void onServiceDisconnected(ComponentName name) {
});
ctx.bindService(
- new Intent(ctx, LocationTrackerService.class), sConn, BIND_AUTO_CREATE);
+ new Intent(ctx, LocationTrackerService.class),
+ sConn, BIND_AUTO_CREATE);
}
@Nullable
@@ -246,7 +248,11 @@ private void showEventDialog(EventDTO event) {
requireContext(), event.getId()))
.setNegativeButton(
R.string.back,
- (dialog, which) -> dialog.dismiss())
+ (dialog, which) -> {
+ startActivity(new Intent(requireContext(), ProfileActivity.class));
+ requireActivity().finish();
+ dialog.dismiss();
+ })
.show();
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/EventsFragment.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/EventsFragment.java
index 268c3dc..65ad080 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/EventsFragment.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/EventsFragment.java
@@ -7,10 +7,13 @@
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentPagerAdapter;
+import androidx.fragment.app.FragmentActivity;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
+import androidx.viewpager2.widget.ViewPager2;
+import com.google.android.material.tabs.TabLayoutMediator;
import com.tom.meeter.R;
import com.tom.meeter.databinding.FragmentEventsBinding;
@@ -24,10 +27,9 @@ public class EventsFragment extends Fragment {
private static final String TAG = EventsFragment.class.getCanonicalName();
- FragmentEventsBinding binding;
+ private FragmentEventsBinding binding;
public EventsFragment() {
- // Required empty public constructor
logMethod(TAG, this);
}
@@ -49,52 +51,76 @@ public View onCreateView(
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
logMethod(TAG, this);
- binding.fragmentEventsViewpager.setAdapter(
- createViewPagerAdapter(
- getChildFragmentManager(),
- getString(R.string.map),
- getString(R.string.events),
- getString(R.string.your_events)));
-
- binding.fragmentEventsTabs.setupWithViewPager(binding.fragmentEventsViewpager);
+
+ ViewPagerAdapter adapter = createViewPagerAdapter(requireActivity());
+
+ ViewPager2 viewPager = binding.fragmentEventsViewpager;
+ viewPager.setAdapter(adapter);
+ viewPager.setOffscreenPageLimit(1);
+
+ new TabLayoutMediator(
+ binding.fragmentEventsTabs, viewPager,
+ (tab, position) -> tab.setText(adapter.getPageTitle(position))
+ ).attach();
+
+ viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
+ @Override
+ public void onPageSelected(int position) {
+ super.onPageSelected(position);
+ // Disable tab scroll for GMaps fragment ([0]).
+ viewPager.setUserInputEnabled(position != 0);
+ }
+ });
}
- private static ViewPagerAdapter createViewPagerAdapter(
- FragmentManager fMgr, String mapTitle,
- String eventsTitle, String yourEventsTitle) {
- ViewPagerAdapter adapter = new ViewPagerAdapter(fMgr);
- adapter.addFragment(new GoogleMapsFragment(), mapTitle);
- adapter.addFragment(new ActiveEventsFragment(), eventsTitle);
- adapter.addFragment(new ProfileEventsFragment(), yourEventsTitle);
+ private static ViewPagerAdapter createViewPagerAdapter(FragmentActivity activity) {
+ ViewPagerAdapter adapter = new ViewPagerAdapter(activity);
+ adapter.addFragment(new GoogleMapsFragment(), activity.getString(R.string.on_map));
+ adapter.addFragment(new ActiveEventsFragment(), activity.getString(R.string.listed));
+ adapter.addFragment(new ProfileEventsFragment(), activity.getString(R.string.your));
return adapter;
}
- static class ViewPagerAdapter extends FragmentPagerAdapter {
+ @Override
+ public void onDestroyView() {
+ logMethod(TAG, this);
+ super.onDestroyView();
+ }
+
+ @Override
+ public void onDestroy() {
+ logMethod(TAG, this);
+ super.onDestroy();
+ }
+
+ static class ViewPagerAdapter extends FragmentStateAdapter {
+
private final List fragments = new ArrayList<>();
- private final List fragmentsTitles = new ArrayList<>();
+ private final List fragmentTitles = new ArrayList<>();
- public ViewPagerAdapter(FragmentManager manager) {
- super(manager);
+ public ViewPagerAdapter(
+ @NonNull FragmentActivity fragmentActivity) {
+ super(fragmentActivity);
}
+ public void addFragment(Fragment fragment, String title) {
+ fragments.add(fragment);
+ fragmentTitles.add(title);
+ }
+
+ @NonNull
@Override
- public Fragment getItem(int position) {
+ public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
- public int getCount() {
+ public int getItemCount() {
return fragments.size();
}
- public void addFragment(Fragment fragment, String title) {
- fragments.add(fragment);
- fragmentsTitles.add(title);
- }
-
- @Override
- public CharSequence getPageTitle(int position) {
- return fragmentsTitles.get(position);
+ public String getPageTitle(int position) {
+ return fragmentTitles.get(position);
}
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/GoogleMapsFragment.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/GoogleMapsFragment.java
index cd4ef48..091c897 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/GoogleMapsFragment.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/GoogleMapsFragment.java
@@ -143,15 +143,17 @@ public void onServiceDisconnected(ComponentName name) {
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
logMethod(TAG, this);
+ View root = inflater.inflate(
+ R.layout.sub_fragment_gmaps, container, false);
GoogleMapOptions opts = new GoogleMapOptions();
opts.zoomControlsEnabled(true);
SupportMapFragment sMapFragment = SupportMapFragment.newInstance(opts);
sMapFragment.getMapAsync(this);
- getParentFragmentManager()
+ getChildFragmentManager()
.beginTransaction()
.replace(R.id.event_fragment_sub_fragment_gmap, sMapFragment)
.commit();
- return inflater.inflate(R.layout.sub_fragment_gmaps, container, false);
+ return root;
}
@Override
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ProfileEventsFragment.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ProfileEventsFragment.java
index 02ca837..6f9e40f 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ProfileEventsFragment.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ProfileEventsFragment.java
@@ -19,7 +19,7 @@
import com.tom.meeter.context.profile.component.adapter.EventsAdapter;
import com.tom.meeter.context.profile.component.viewmodel.ProfileEventsViewModel;
import com.tom.meeter.context.profile.factory.ProfileEventsAssistedFactory;
-import com.tom.meeter.databinding.SubFragmentUserEventsBinding;
+import com.tom.meeter.databinding.FragmentUserEventsBinding;
import com.tom.meeter.infrastructure.common.InfrastructureHelper;
import javax.inject.Inject;
@@ -33,7 +33,7 @@ public class ProfileEventsFragment extends Fragment {
@Inject
EventsAdapter adapter;
- private SubFragmentUserEventsBinding binding;
+ private FragmentUserEventsBinding binding;
private final Runnable onAuthFail =
() -> InfrastructureHelper.restartActivityFromFragment(this);
@@ -64,29 +64,34 @@ public void onCreate(Bundle savedInstanceState) {
@Override
public View onCreateView(
- @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ @NonNull LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
logMethod(TAG, this);
- binding = SubFragmentUserEventsBinding.inflate(inflater, container, false);
+ binding = FragmentUserEventsBinding.inflate(
+ inflater, container, false);
return binding.getRoot();
}
@Override
- public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ public void onViewCreated(
+ @NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
logMethod(TAG, this);
viewModel = new ViewModelProvider(
this,
assistedFactory.factory(
- assistedFactory, requireContext(),
- () -> InfrastructureHelper.restartActivityFromFragment(this)))
+ assistedFactory, requireContext(), onAuthFail))
.get(ProfileEventsViewModel.class);
- binding.userEventsFragmentRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
- binding.userEventsFragmentRecyclerView.setAdapter(adapter);
+ binding.eventsRecyclerView.setLayoutManager(
+ new LinearLayoutManager(getActivity()));
+ binding.eventsRecyclerView.setAdapter(adapter);
viewModel.getEvents()
- .observe(getViewLifecycleOwner(), events -> adapter.setData(events));
+ .observe(
+ getViewLifecycleOwner(),
+ events -> adapter.setData(events));
}
@Override
@@ -103,13 +108,13 @@ public void onStop() {
@Override
public void onDestroyView() {
- super.onDestroyView();
logMethod(TAG, this);
+ super.onDestroyView();
}
@Override
public void onDestroy() {
- super.onDestroy();
logMethod(TAG, this);
+ super.onDestroy();
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ProfileFragment.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ProfileFragment.java
index fb580f6..2aa1380 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ProfileFragment.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/fragment/ProfileFragment.java
@@ -65,7 +65,7 @@ public class ProfileFragment extends Fragment {
@Inject
ProfileAssistedFactory assistedFactory;
@Inject
- ImageDownloader imageDownloader;
+ ImageDownloader imgDownloader;
@Inject
ProfileService service;
@Inject
@@ -79,10 +79,6 @@ public class ProfileFragment extends Fragment {
private boolean isEditableModeEnabled = false;
private UserDTO userCache;
- public ProfileFragment() {
- logMethod(TAG, this);
- }
-
private final ActivityResultLauncher imageUploadLauncher =
registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
@@ -94,6 +90,10 @@ public ProfileFragment() {
}
});
+ public ProfileFragment() {
+ logMethod(TAG, this);
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -127,16 +127,22 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
assistedFactory.factory(assistedFactory, ctx, onAuthFail))
.get(ProfileViewModel.class);
+ binding.swipeRefreshLayout.setOnRefreshListener(() -> viewModel.init());
+
LifecycleOwner owner = getViewLifecycleOwner();
viewModel.getProfile()
.observe(
owner,
user -> {
+ binding.swipeRefreshLayout.setRefreshing(false);
userCache = user;
updateLayoutValues();
});
- binding.events.setLayoutManager(new GridLayoutManager(getContext(), 2));
+ binding.events.setLayoutManager(
+ new GridLayoutManager(
+ getContext(),
+ EventsCardAdapter.calculateNoOfColumns(150)));
binding.events.setAdapter(adapter);
viewModel.getEvents()
@@ -195,7 +201,7 @@ private void updateLayoutValues() {
}
void downloadAndUpdateLayoutPhoto(String photoPath) {
- imageDownloader.downloadUserImage(
+ imgDownloader.downloadUserImage(
photoPath, requireContext(), ImagesHelper::bigCircleImage,
this::updateLayoutPhoto, onAuthFail);
}
@@ -206,7 +212,13 @@ private void updateLayoutPhoto(Bitmap photo) {
private void switchEditMode() {
isEditableModeEnabled = !isEditableModeEnabled;
- binding.btnPhoto.setEnabled(isEditableModeEnabled);
+ if (isEditableModeEnabled) {
+ binding.btnPhoto.setVisibility(View.VISIBLE);
+ binding.photoPath.setVisibility(View.VISIBLE);
+ } else {
+ binding.btnPhoto.setVisibility(View.GONE);
+ binding.photoPath.setVisibility(View.GONE);
+ }
binding.name.setEnabled(isEditableModeEnabled);
binding.surname.setEnabled(isEditableModeEnabled);
binding.birthday.setEnabled(isEditableModeEnabled);
@@ -229,13 +241,13 @@ public void onStop() {
@Override
public void onDestroyView() {
- super.onDestroyView();
logMethod(TAG, this);
+ super.onDestroyView();
}
@Override
public void onDestroy() {
- super.onDestroy();
logMethod(TAG, this);
+ super.onDestroy();
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewholder/SubscriberViewHolder.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewholder/SubscriberViewHolder.java
index bbed795..60846de 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewholder/SubscriberViewHolder.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewholder/SubscriberViewHolder.java
@@ -24,8 +24,9 @@ public void bind(
binding.subscriberName.setText(name + " " + surname);
if (photo != null) {
binding.photo.setImageBitmap(photo);
+ } else {
+ binding.photo.setImageResource(R.drawable.user_500x500_removebg);
}
-
binding.subUnsubBtn.setOnClickListener(subUnSubClickListener);
binding.subCard.setOnClickListener(cardClickListener);
binding.subUnsubBtn.setText(isAmSubscribedTo ? R.string.unsubscribe : R.string.subscribe);
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileEventsViewModel.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileEventsViewModel.java
index 0f5b0db..27aef60 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileEventsViewModel.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileEventsViewModel.java
@@ -54,7 +54,7 @@ public void onResponse(
if (response.code() != HttpCodes.OK || response.body() == null) {
return;
}
- events.setValue(response.body());
+ events.postValue(response.body());
return;
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileSubscribersViewModel.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileSubscribersViewModel.java
index dfce7d8..83957a2 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileSubscribersViewModel.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileSubscribersViewModel.java
@@ -85,7 +85,7 @@ public void onResponse(
subscriber,
mySubscriptions.get(subscriber.getId()) != null));
}
- ProfileSubscribersViewModel.this.subscribers.setValue(result);
+ ProfileSubscribersViewModel.this.subscribers.postValue(result);
return;
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileSubscriptionsViewModel.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileSubscriptionsViewModel.java
index 75dedc0..a2567eb 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileSubscriptionsViewModel.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileSubscriptionsViewModel.java
@@ -59,7 +59,7 @@ public void onResponse(Call> call, Response> resp) {
for (UserDTO subscription : resp.body()) {
result.add(new Subscriber(subscription, true));
}
- subscriptions.setValue(result);
+ subscriptions.postValue(result);
return;
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileViewModel.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileViewModel.java
index 120b97a..6f29c90 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileViewModel.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/component/viewmodel/ProfileViewModel.java
@@ -62,7 +62,7 @@ public void onResponse(Call call, Response resp) {
return;
}
UserDTO user = resp.body();
- profile.setValue(user);
+ profile.postValue(user);
String photoPath = user.getPhotoPath();
if (photoPath == null) {
return;
@@ -70,7 +70,7 @@ public void onResponse(Call call, Response resp) {
imageDownloader.downloadUserImage(
photoPath, ctx,
ImagesHelper::bigCircleImage,
- photo::setValue,
+ photo::postValue,
onNotAuthenticated);
return;
}
@@ -85,7 +85,7 @@ public void onResponse(
if (resp.code() != HttpCodes.OK || resp.body() == null) {
return;
}
- events.setValue(resp.body());
+ events.postValue(resp.body());
return;
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/service/ProfileService.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/service/ProfileService.java
index 736e15e..82312e3 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/service/ProfileService.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/service/ProfileService.java
@@ -48,9 +48,5 @@ Call updateProfile(
@Deprecated
@GET("/user/{id}")
Call getUser(@Header(AUTH_HEADER) String authHeader, @Path("id") String userId);
-/* soon...
- @GET("/publish")
- Call publishEvent(
- @Header(AUTH_HEADER) String authHeader, @Body CreateEventRequest req);*/
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserActivity.java
index f4d8d93..d7a3bba 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserActivity.java
@@ -10,12 +10,10 @@
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.showMessage;
-import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
@@ -31,6 +29,7 @@
import com.tom.meeter.context.token.service.TokenService;
import com.tom.meeter.context.user.factory.UserAssistedFactory;
import com.tom.meeter.context.user.service.UserService;
+import com.tom.meeter.context.user.utils.Utils;
import com.tom.meeter.context.user.viewmodel.UserViewModel;
import com.tom.meeter.databinding.ActivityUserBinding;
import com.tom.meeter.infrastructure.common.Globals;
@@ -48,12 +47,11 @@
public class UserActivity extends AppCompatActivity {
private static final String TAG = UserActivity.class.getCanonicalName();
- public static final String USER_ID_KEY = "user_id";
@Inject
TokenService tokenService;
@Inject
- UserService userService;
+ UserService service;
@Inject
UserAssistedFactory assistedFactory;
@Inject
@@ -61,8 +59,6 @@ public class UserActivity extends AppCompatActivity {
private ActivityUserBinding binding;
private UserViewModel viewModel;
- private String userId;
- private AccountManager accountManager;
private Boolean amISubscriber;
private final Runnable onAuthFail = this::recreate;
@@ -72,10 +68,20 @@ protected void onCreate(Bundle savedInstanceState) {
logMethod(TAG, this);
- if (!validate()) {
+ if (Utils.isIncorrect(this)) {
return;
}
+ if (Utils.getUserId(this).equals(AuthHelper.getUserUuid(this))) {
+ startActivity(new Intent(this, ProfileActivity.class));
+ finish();
+ return;
+ }
+
+ binding = ActivityUserBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
+
((App) getApplication()).getUserComponent().inject(this);
adapter.initialize(
@@ -83,43 +89,18 @@ protected void onCreate(Bundle savedInstanceState) {
event -> dispatchToEventActivity(this, event.getId()));
//setToken(accountManager, Launcher.EXPIRED);
- checkToken(this::onInit, this::finish, accountManager, this, tokenService);
- }
-
- private boolean validate() {
- Bundle extras = getIntent().getExtras();
- if (extras == null) {
- Log.d(TAG, "Unable to create user activity without extras.");
- finish();
- return false;
- }
- userId = extras.getString(USER_ID_KEY);
- if (userId == null) {
- Log.d(TAG, "Unable to create user activity without 'user_id' provided.");
- finish();
- return false;
- }
- accountManager = AccountManager.get(this);
- if (userId.equals(AuthHelper.getUserUuid(accountManager))) {
- startActivity(new Intent(this, ProfileActivity.class));
- finish();
- return false;
- }
- return true;
+ checkToken(this::onInit, this::finish, this, tokenService);
}
private void onInit(String token) {
- binding = ActivityUserBinding.inflate(getLayoutInflater());
- View view = binding.getRoot();
- setContentView(view);
-
+ String userId = Utils.getUserId(this);
binding.subscribeBtn.setOnClickListener(v -> {
if (amISubscriber == null) {
// As not initialized atm...
return;
}
if (amISubscriber) {
- userService.unsubscribe(Globals.getAuthHeader(token), userId).enqueue(
+ service.unsubscribe(Globals.getAuthHeader(token), userId).enqueue(
new BaseOnNotAuthenticatedCallback<>(this, onAuthFail) {
@Override
public void onResponse(Call call, Response resp) {
@@ -132,7 +113,7 @@ public void onResponse(Call call, Response resp) {
}
});
} else {
- userService.subscribe(Globals.getAuthHeader(token), userId).enqueue(
+ service.subscribe(Globals.getAuthHeader(token), userId).enqueue(
new BaseOnNotAuthenticatedCallback<>(this, onAuthFail) {
@Override
public void onResponse(Call call, Response resp) {
@@ -153,11 +134,17 @@ public void onResponse(Call call, Response resp) {
assistedFactory, userId, this, onAuthFail))
.get(UserViewModel.class);
- binding.events.setLayoutManager(new GridLayoutManager(this, 2));
+ binding.swipeRefreshLayout.setOnRefreshListener(() -> viewModel.init());
+
+ binding.events.setLayoutManager(
+ new GridLayoutManager(
+ this,
+ EventsCardAdapter.calculateNoOfColumns(150)));
binding.events.setAdapter(adapter);
viewModel.getUser()
.observe(this, user -> {
+ binding.swipeRefreshLayout.setRefreshing(false);
binding.name.setText(user.getName());
binding.gender.setText(genderResolver(getApplicationContext(), user.getGender()));
@@ -220,6 +207,6 @@ public static void dispatchToUserActivity(Context ctx, String userId) {
public static Intent createUserActivityIntent(Context ctx, String userId) {
return new Intent(ctx, UserActivity.class)
- .putExtra(USER_ID_KEY, userId);
+ .putExtra(Utils.USER_ID_KEY, userId);
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserSubscribersActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserSubscribersActivity.java
index d0b5c7f..022bbd8 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserSubscribersActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserSubscribersActivity.java
@@ -3,12 +3,10 @@
import static com.tom.meeter.context.auth.infrastructure.AuthHelper.checkToken;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
-import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
@@ -21,6 +19,7 @@
import com.tom.meeter.context.token.service.TokenService;
import com.tom.meeter.context.user.components.adapter.UsersAdapter;
import com.tom.meeter.context.user.factory.UserSubscribersAssistedFactory;
+import com.tom.meeter.context.user.utils.Utils;
import com.tom.meeter.context.user.viewmodel.UserSubscribersViewModel;
import com.tom.meeter.databinding.ActivityProfileSubscribersBinding;
@@ -38,10 +37,8 @@ public class UserSubscribersActivity extends AppCompatActivity {
UsersAdapter adapter;
private final Runnable onAuthFail = this::recreate;
- private AccountManager accountManager;
private ActivityProfileSubscribersBinding binding;
private UserSubscribersViewModel viewModel;
- private String userId;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -49,33 +46,24 @@ protected void onCreate(Bundle savedInstanceState) {
logMethod(TAG, this);
- Bundle extras = getIntent().getExtras();
- if (extras == null) {
- Log.d(TAG, "Unable to create user activity without extras.");
- finish();
- return;
- }
- userId = extras.getString(UserActivity.USER_ID_KEY);
- if (userId == null) {
- Log.d(TAG, "Unable to create user activity without 'user_id' provided.");
- finish();
+ if (Utils.isIncorrect(this)) {
return;
}
+ binding = ActivityProfileSubscribersBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
+
((App) getApplication()).getUserComponent().inject(this);
- accountManager = AccountManager.get(this);
adapter.initialize(this, onAuthFail);
//setToken(accountManager, Launcher.EXPIRED);
- checkToken(this::onInit, this::finish, accountManager, this, tokenService);
+ checkToken(this::onInit, this::finish, this, tokenService);
}
private void onInit(String token) {
logMethod(TAG, this);
- binding = ActivityProfileSubscribersBinding.inflate(getLayoutInflater());
- View view = binding.getRoot();
- setContentView(view);
binding.recyclerSubscribers.setLayoutManager(new LinearLayoutManager(this));
binding.recyclerSubscribers.setAdapter(adapter);
@@ -83,11 +71,18 @@ private void onInit(String token) {
viewModel = new ViewModelProvider(
this,
assistedFactory.factory(
- assistedFactory, userId, this, onAuthFail))
+ assistedFactory,
+ Utils.getUserId(this),
+ this, onAuthFail))
.get(UserSubscribersViewModel.class);
+ binding.swipeRefreshLayout.setOnRefreshListener(() -> viewModel.init());
+
viewModel.getSubscribers()
- .observe(this, subs -> adapter.setData(subs));
+ .observe(this, subs -> {
+ binding.swipeRefreshLayout.setRefreshing(false);
+ adapter.setData(subs);
+ });
}
@Nullable
@@ -140,6 +135,6 @@ public static void dispatchToUserSubscribersActivity(Context ctx, String userId)
private static Intent createUserSubscribersActivityIntent(Context ctx, String userId) {
return new Intent(ctx, UserSubscribersActivity.class)
- .putExtra(UserActivity.USER_ID_KEY, userId);
+ .putExtra(Utils.USER_ID_KEY, userId);
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserSubscriptionsActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserSubscriptionsActivity.java
index cee895c..553d4e5 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserSubscriptionsActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserSubscriptionsActivity.java
@@ -3,12 +3,10 @@
import static com.tom.meeter.context.auth.infrastructure.AuthHelper.checkToken;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
-import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
@@ -21,6 +19,7 @@
import com.tom.meeter.context.token.service.TokenService;
import com.tom.meeter.context.user.components.adapter.UsersAdapter;
import com.tom.meeter.context.user.factory.UserSubscriptionsAssistedFactory;
+import com.tom.meeter.context.user.utils.Utils;
import com.tom.meeter.context.user.viewmodel.UserSubscriptionsViewModel;
import com.tom.meeter.databinding.ActivityProfileSubscriptionsBinding;
@@ -39,8 +38,6 @@ public class UserSubscriptionsActivity extends AppCompatActivity {
private ActivityProfileSubscriptionsBinding binding;
private UserSubscriptionsViewModel viewModel;
- private AccountManager accountManager;
- private String userId;
private final Runnable onAuthFail = this::recreate;
@Override
@@ -49,16 +46,7 @@ protected void onCreate(Bundle savedInstanceState) {
logMethod(TAG, this);
- Bundle extras = getIntent().getExtras();
- if (extras == null) {
- Log.d(TAG, "Unable to create user activity without extras.");
- finish();
- return;
- }
- userId = extras.getString(UserActivity.USER_ID_KEY);
- if (userId == null) {
- Log.d(TAG, "Unable to create user activity without 'user_id' provided.");
- finish();
+ if (Utils.isIncorrect(this)) {
return;
}
@@ -67,12 +55,11 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(view);
((App) getApplication()).getUserComponent().inject(this);
- accountManager = AccountManager.get(this);
adapter.initialize(this, onAuthFail);
//setToken(accountManager, Launcher.EXPIRED);
- checkToken(this::onInit, this::finish, accountManager, this, tokenService);
+ checkToken(this::onInit, this::finish, this, tokenService);
}
private void onInit(String token) {
@@ -81,14 +68,21 @@ private void onInit(String token) {
viewModel = new ViewModelProvider(
this,
assistedFactory.factory(
- assistedFactory, userId, this, onAuthFail))
+ assistedFactory,
+ Utils.getUserId(this),
+ this, onAuthFail))
.get(UserSubscriptionsViewModel.class);
+ binding.swipeRefreshLayout.setOnRefreshListener(() -> viewModel.init());
+
binding.recyclerSubscriptions.setLayoutManager(new LinearLayoutManager(this));
binding.recyclerSubscriptions.setAdapter(adapter);
viewModel.getSubscriptions()
- .observe(this, subs -> adapter.setData(subs));
+ .observe(this, subs -> {
+ binding.swipeRefreshLayout.setRefreshing(false);
+ adapter.setData(subs);
+ });
}
@Nullable
@@ -141,6 +135,6 @@ public static void dispatchToUserSubscriptionsActivity(Context ctx, String userI
private static Intent createUserSubscriptionsActivityIntent(Context ctx, String userId) {
return new Intent(ctx, UserSubscriptionsActivity.class)
- .putExtra(UserActivity.USER_ID_KEY, userId);
+ .putExtra(Utils.USER_ID_KEY, userId);
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/user/utils/Utils.java b/AndroidClient/src/main/java/com/tom/meeter/context/user/utils/Utils.java
new file mode 100644
index 0000000..5eda255
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/utils/Utils.java
@@ -0,0 +1,37 @@
+package com.tom.meeter.context.user.utils;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+public class Utils {
+
+ private static final String TAG = Utils.class.getCanonicalName();
+
+ public static final String USER_ID_KEY = "user_id";
+
+ private Utils() {
+ }
+
+ public static boolean isIncorrect(Activity activity) {
+ Bundle extras = activity.getIntent().getExtras();
+ if (extras == null) {
+ Log.d(TAG, "Unable to create ["
+ + activity.getClass().getCanonicalName()
+ + "] without extras.");
+ activity.finish();
+ return true;
+ }
+ if (extras.getString(USER_ID_KEY) == null) {
+ Log.d(TAG, "Unable to create user activity without ["
+ + USER_ID_KEY + "] provided.");
+ activity.finish();
+ return true;
+ }
+ return false;
+ }
+
+ public static String getUserId(Activity activity) {
+ return activity.getIntent().getExtras().getString(USER_ID_KEY);
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserSubscribersViewModel.java b/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserSubscribersViewModel.java
index bf1757a..a5a5184 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserSubscribersViewModel.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserSubscribersViewModel.java
@@ -56,7 +56,7 @@ public void onResponse(Call> call, Response> resp) {
if (resp.code() != HttpCodes.OK || resp.body() == null) {
return;
}
- subscribers.setValue(resp.body());
+ subscribers.postValue(resp.body());
return;
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserSubscriptionsViewModel.java b/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserSubscriptionsViewModel.java
index 4b21784..18bd634 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserSubscriptionsViewModel.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserSubscriptionsViewModel.java
@@ -51,12 +51,13 @@ public void init() {
service.getSubscriptions(getAuthHeader(AccountManager.get(ctx)), userId).enqueue(
new BaseOnNotAuthenticatedCallback<>(ctx, onNotAuthenticated) {
@Override
- public void onResponse(Call> call, Response> resp) {
+ public void onResponse(
+ Call> call, Response> resp) {
super.onResponse(call, resp);
if (resp.code() != HttpCodes.OK || resp.body() == null) {
return;
}
- subscriptions.setValue(resp.body());
+ subscriptions.postValue(resp.body());
return;
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserViewModel.java b/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserViewModel.java
index ee64d11..a999098 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserViewModel.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserViewModel.java
@@ -67,7 +67,7 @@ public void onResponse(
return;
}
UserDTO user = resp.body();
- UserViewModel.this.user.setValue(user);
+ UserViewModel.this.user.postValue(user);
String photoPath = user.getPhotoPath();
if (photoPath == null) {
return;
@@ -75,7 +75,7 @@ public void onResponse(
imgDownloader.downloadUserImage(
photoPath, ctx,
ImagesHelper::bigCircleImage,
- photo::setValue,
+ photo::postValue,
onNotAuthenticated);
return;
}
@@ -91,7 +91,7 @@ public void onResponse(
if (resp.code() != HttpCodes.OK) {
return;
}
- amISubscriber.setValue(resp.body());
+ amISubscriber.postValue(resp.body());
return;
}
}
@@ -106,7 +106,7 @@ public void onResponse(
if (resp.code() != HttpCodes.OK) {
return;
}
- events.setValue(resp.body());
+ events.postValue(resp.body());
return;
}
});
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/CommonHelper.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/CommonHelper.java
index f77b9b5..6481811 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/CommonHelper.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/CommonHelper.java
@@ -21,6 +21,7 @@
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
@@ -39,6 +40,7 @@ private CommonHelper() {
DateTimeFormatter.ofPattern("HH:mm");
private static Map nameToStatusMapping;
+ private static Map statusToActionMapping;
public static final String EMPTY_STR = "";
@@ -50,6 +52,14 @@ public static EventDTO.EventStatus resolveStatus(Context ctx, String statusName)
return nameToStatusMapping.get(statusName);
}
+ public static String resolveStatusAction(
+ Context ctx, EventDTO.EventStatus status) {
+ if (statusToActionMapping == null) {
+ initializeStatusToActionMapping(ctx);
+ }
+ return statusToActionMapping.get(status);
+ }
+
private static void initializeNameToStatusMapping(Context ctx) {
String[] statuses = ctx.getResources().getStringArray(R.array.statuses);
nameToStatusMapping = new HashMap<>(statuses.length);
@@ -67,6 +77,21 @@ private static void initializeNameToStatusMapping(Context ctx) {
// nameToStatusMapping.put(statuses[9], EventDTO.EventStatus.ARCHIVED);
}
+ private static void initializeStatusToActionMapping(Context ctx) {
+ String[] statuses = ctx.getResources().getStringArray(R.array.event_actions);
+ statusToActionMapping = new EnumMap<>(EventDTO.EventStatus.class);
+ //statusToActionMapping.put(EventDTO.EventStatus.CREATED, statuses[0]);
+ statusToActionMapping.put(EventDTO.EventStatus.PUBLISHED, statuses[0]);
+ statusToActionMapping.put(EventDTO.EventStatus.UNPUBLISHED, statuses[1]);
+ statusToActionMapping.put(EventDTO.EventStatus.SCHEDULED, statuses[2]);
+ statusToActionMapping.put(EventDTO.EventStatus.STARTED, statuses[3]);
+ statusToActionMapping.put(EventDTO.EventStatus.PAUSED, statuses[4]);
+ statusToActionMapping.put(EventDTO.EventStatus.RESUMED, statuses[5]);
+ statusToActionMapping.put(EventDTO.EventStatus.CANCELLED, statuses[6]);
+ statusToActionMapping.put(EventDTO.EventStatus.FINISHED, statuses[7]);
+ statusToActionMapping.put(EventDTO.EventStatus.ARCHIVED, statuses[8]);
+ }
+
public static String genderResolver(Context ctx, UserDTO.UserGender gender) {
return switch (gender) {
case FEMALE -> ctx.getString(R.string.female_gender);
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/Globals.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/Globals.java
index b3949a4..a558831 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/Globals.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/Globals.java
@@ -54,7 +54,7 @@ public static String getServerPath(Context ctx) {
+ p.getProperty(SERVER_IP_PROPERTY)
+ ":"
+ Integer.valueOf(p.getProperty(SERVER_PORT_PROPERTY));
- Log.d(TAG, "Server URL is [" + serverPath + "].");
+ Log.i(TAG, "Server URL is [" + serverPath + "].");
return serverPath;
}
@@ -67,7 +67,7 @@ public static String getSocketIOPath(Context ctx) {
+ p.getProperty(SERVER_IP_PROPERTY)
+ ":"
+ Integer.valueOf(p.getProperty(SERVER_IO_PORT_PROPERTY));
- Log.d(TAG, "SocketIO path is [" + socketIOPath + "].");
+ Log.i(TAG, "SocketIO path is [" + socketIOPath + "].");
return socketIOPath;
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/activity/BaseBackToolbarActivity.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/activity/BaseBackToolbarActivity.java
new file mode 100644
index 0000000..6e0aabf
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/activity/BaseBackToolbarActivity.java
@@ -0,0 +1,32 @@
+package com.tom.meeter.infrastructure.components.activity;
+
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
+
+import android.util.Log;
+import android.view.MenuItem;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+
+public abstract class BaseBackToolbarActivity extends AppCompatActivity {
+
+ private static final String TAG = BaseBackToolbarActivity.class.getCanonicalName();
+
+ protected void setupToolbar(Toolbar toolbar, int titleResId) {
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setTitle(titleResId);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ logMethod(TAG, this);
+ if (item.getItemId() == android.R.id.home) {
+ Log.d(TAG, "Home pressed");
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/adapter/EventsCardAdapter.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/adapter/EventsCardAdapter.java
index d16d3d3..39fa938 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/adapter/EventsCardAdapter.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/adapter/EventsCardAdapter.java
@@ -1,6 +1,8 @@
package com.tom.meeter.infrastructure.components.adapter;
import android.content.Context;
+import android.content.res.Resources;
+import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -40,4 +42,11 @@ public CardItemHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType
CardItemBinding.inflate(
LayoutInflater.from(parent.getContext()), parent, false));
}
+
+ public static int calculateNoOfColumns(float columnWidthDp) {
+ DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
+ float screenWidthDp = displayMetrics.widthPixels / displayMetrics.density;
+ int noOfColumns = (int) (screenWidthDp / columnWidthDp);
+ return Math.max(1, noOfColumns);
+ }
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/binder/SimpleEventBinderImpl.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/binder/SimpleEventBinderImpl.java
index 2bdc64d..930259e 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/binder/SimpleEventBinderImpl.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/binder/SimpleEventBinderImpl.java
@@ -1,5 +1,8 @@
package com.tom.meeter.infrastructure.components.binder;
+import static com.tom.meeter.infrastructure.common.CommonHelper.handleEventStatus;
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
+
import android.content.Context;
import com.tom.meeter.context.image.ImageDownloader;
@@ -42,13 +45,17 @@ public void setOnAuthFailAction(Runnable onAuthFail) {
@Override
public void bind(CardItemHolder holder, EventDTO event) {
- holder.bind(event.getName(), null, (view) -> listener.onClick(event));
+ logMethod(TAG, this);
+ holder.bind(
+ event.getName(), null,
+ (view) -> listener.onClick(event),
+ v -> handleEventStatus(ctx, v, event.getStatus()));
String photoPath = event.getPhotoPath();
if (photoPath == null) {
return;
}
imageDownloader.downloadEventImage(
- photoPath, ctx, ImagesHelper::circleImage,
+ photoPath, ctx, ImagesHelper::bigCircleImage,
holder::updatePhoto, onAuthFail);
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/viewholder/CardItemHolder.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/viewholder/CardItemHolder.java
index 9a2d5c3..9965508 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/viewholder/CardItemHolder.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/components/viewholder/CardItemHolder.java
@@ -2,11 +2,14 @@
import android.graphics.Bitmap;
import android.view.View;
+import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.tom.meeter.databinding.CardItemBinding;
+import java.util.function.Consumer;
+
public class CardItemHolder extends RecyclerView.ViewHolder {
private final CardItemBinding binding;
@@ -17,10 +20,12 @@ public CardItemHolder(CardItemBinding binding) {
}
public void bind(
- String name, Bitmap photo, View.OnClickListener clickListener) {
+ String name, Bitmap photo, View.OnClickListener clickListener,
+ Consumer statusC) {
binding.textView.setText(name);
binding.imageView.setImageBitmap(photo);
binding.card.setOnClickListener(clickListener);
+ statusC.accept(binding.status);
}
public void updatePhoto(Bitmap photo) {
diff --git a/AndroidClient/src/main/res/drawable-hdpi/meeter_new_logo_64x64_1.png b/AndroidClient/src/main/res/drawable-hdpi/meeter_new_logo_64x64_1.png
new file mode 100644
index 0000000..e7ad242
Binary files /dev/null and b/AndroidClient/src/main/res/drawable-hdpi/meeter_new_logo_64x64_1.png differ
diff --git a/AndroidClient/src/main/res/drawable/bg_button_selected.xml b/AndroidClient/src/main/res/drawable/bg_button_selected.xml
index cecfec4..7453253 100644
--- a/AndroidClient/src/main/res/drawable/bg_button_selected.xml
+++ b/AndroidClient/src/main/res/drawable/bg_button_selected.xml
@@ -2,4 +2,4 @@
-
\ No newline at end of file
+
diff --git a/AndroidClient/src/main/res/drawable/bg_button_unselected.xml b/AndroidClient/src/main/res/drawable/bg_button_unselected.xml
index 215c9fe..26d993e 100644
--- a/AndroidClient/src/main/res/drawable/bg_button_unselected.xml
+++ b/AndroidClient/src/main/res/drawable/bg_button_unselected.xml
@@ -1,7 +1,5 @@
-
-
-
+
-
\ No newline at end of file
+
diff --git a/AndroidClient/src/main/res/layout/activity_event_editable.xml b/AndroidClient/src/main/res/layout/activity_event_editable.xml
index 0645dff..919c9c9 100644
--- a/AndroidClient/src/main/res/layout/activity_event_editable.xml
+++ b/AndroidClient/src/main/res/layout/activity_event_editable.xml
@@ -1,288 +1,313 @@
-
+ android:layout_height="match_parent">
-
-
-
-
-
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
-
-
+
-
+ android:layout_height="match_parent">
-
-
-
-
-
-
-
+ android:orientation="vertical"
+ android:padding="16dp">
+
+
-
-
-
+
-
-
-
-
-
-
+
-
+
+
-
-
-
+
+
+
+
+
-
+ android:layout_marginTop="12dp"
+ android:background="@drawable/edit_text_background_border"
+ android:orientation="vertical"
+ android:padding="16dp" />
-
-
-
-
-
-
+
+
-
+
-
+
-
-
-
+
-
+
+
+
+
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/AndroidClient/src/main/res/layout/activity_event_publish.xml b/AndroidClient/src/main/res/layout/activity_event_publish.xml
new file mode 100644
index 0000000..6bf27f9
--- /dev/null
+++ b/AndroidClient/src/main/res/layout/activity_event_publish.xml
@@ -0,0 +1,303 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndroidClient/src/main/res/layout/activity_event_readable.xml b/AndroidClient/src/main/res/layout/activity_event_readable.xml
index 326fda1..f5ee2e3 100644
--- a/AndroidClient/src/main/res/layout/activity_event_readable.xml
+++ b/AndroidClient/src/main/res/layout/activity_event_readable.xml
@@ -1,231 +1,241 @@
-
+ android:layout_height="match_parent">
-
-
-
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="match_parent">
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_marginTop="15dp"
+ android:background="@drawable/edit_text_background_border"
+ android:orientation="vertical"
+ android:padding="16dp">
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
diff --git a/AndroidClient/src/main/res/layout/activity_event_schedule.xml b/AndroidClient/src/main/res/layout/activity_event_schedule.xml
new file mode 100644
index 0000000..76a9778
--- /dev/null
+++ b/AndroidClient/src/main/res/layout/activity_event_schedule.xml
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AndroidClient/src/main/res/layout/profile_activity.xml b/AndroidClient/src/main/res/layout/activity_profile.xml
similarity index 89%
rename from AndroidClient/src/main/res/layout/profile_activity.xml
rename to AndroidClient/src/main/res/layout/activity_profile.xml
index c50e59c..6a06d33 100644
--- a/AndroidClient/src/main/res/layout/profile_activity.xml
+++ b/AndroidClient/src/main/res/layout/activity_profile.xml
@@ -8,13 +8,15 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="4dp"
+ android:background="?attr/colorPrimaryDark"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
@@ -38,4 +40,4 @@
-
\ No newline at end of file
+
diff --git a/AndroidClient/src/main/res/layout/activity_profile_subscribers.xml b/AndroidClient/src/main/res/layout/activity_profile_subscribers.xml
index a9b532b..ba98374 100644
--- a/AndroidClient/src/main/res/layout/activity_profile_subscribers.xml
+++ b/AndroidClient/src/main/res/layout/activity_profile_subscribers.xml
@@ -1,25 +1,32 @@
-
+ android:layout_height="match_parent">
-
-
-
-
-
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="16dp">
+
+
+
+
+
+
-
\ No newline at end of file
+
+
diff --git a/AndroidClient/src/main/res/layout/activity_profile_subscriptions.xml b/AndroidClient/src/main/res/layout/activity_profile_subscriptions.xml
index 66c658d..d3bf394 100644
--- a/AndroidClient/src/main/res/layout/activity_profile_subscriptions.xml
+++ b/AndroidClient/src/main/res/layout/activity_profile_subscriptions.xml
@@ -1,25 +1,31 @@
-
+ android:layout_height="match_parent">
-
-
-
-
-
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="16dp">
+
+
+
+
+
+
-
\ No newline at end of file
+
+
diff --git a/AndroidClient/src/main/res/layout/activity_settings.xml b/AndroidClient/src/main/res/layout/activity_settings.xml
new file mode 100644
index 0000000..4b81bbc
--- /dev/null
+++ b/AndroidClient/src/main/res/layout/activity_settings.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/AndroidClient/src/main/res/layout/activity_user.xml b/AndroidClient/src/main/res/layout/activity_user.xml
index 07f286c..69abe06 100644
--- a/AndroidClient/src/main/res/layout/activity_user.xml
+++ b/AndroidClient/src/main/res/layout/activity_user.xml
@@ -1,217 +1,185 @@
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="match_parent"
+ android:fillViewport="true">
+ android:gravity="center_horizontal"
+ android:orientation="vertical"
+ android:paddingTop="20dp"
+ android:paddingBottom="20dp"
+ tools:context=".context.user.activity.UserActivity">
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+ android:orientation="horizontal">
+
+
+
+
+
-
-
+
-
+
+
+
+
-
+ android:layout_marginTop="20dp"
+ android:text="@string/user_events"
+ android:textAlignment="center"
+ android:textSize="20sp" />
-
-
-
-
-
-
-
+
+
+
+
diff --git a/AndroidClient/src/main/res/layout/card_item.xml b/AndroidClient/src/main/res/layout/card_item.xml
index 62a5a73..d0fd59b 100644
--- a/AndroidClient/src/main/res/layout/card_item.xml
+++ b/AndroidClient/src/main/res/layout/card_item.xml
@@ -1,10 +1,10 @@
@@ -29,5 +29,19 @@
android:text="@string/app_name"
android:textAlignment="center"
android:textStyle="bold" />
+
+
\ No newline at end of file
diff --git a/AndroidClient/src/main/res/layout/fragment_create_event.xml b/AndroidClient/src/main/res/layout/fragment_create_event.xml
index e64e172..01aea17 100644
--- a/AndroidClient/src/main/res/layout/fragment_create_event.xml
+++ b/AndroidClient/src/main/res/layout/fragment_create_event.xml
@@ -3,38 +3,35 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+ android:padding="16dp">
-
+ android:background="@drawable/edit_text_background_border"
+ android:gravity="center_horizontal"
+ android:orientation="vertical"
+ android:padding="16dp">
-
-
+
@@ -86,19 +81,16 @@
-
@@ -109,25 +101,21 @@
android:layout_centerHorizontal="true"
android:layout_marginStart="50dp"
android:hint="@string/description"
- android:textAlignment="center"
android:textSize="20sp" />
-
+ android:background="@drawable/edit_text_background_border"
+ android:orientation="vertical">
@@ -149,7 +134,6 @@
android:id="@+id/location_buttons_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/longitude"
android:layout_marginLeft="10dp"
android:layout_marginTop="15dp"
android:layout_marginRight="10dp">
@@ -169,27 +153,25 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="@string/map"
+ android:text="@string/on_map"
android:textAllCaps="false"
android:textSize="14sp" />
-
+
-
+ android:background="@drawable/edit_text_background_border"
+ android:orientation="vertical">
@@ -210,7 +189,6 @@
android:id="@+id/date_buttons_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@+id/starts_date_validator"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal"
@@ -237,9 +215,7 @@
android:id="@+id/starts_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@+id/date_buttons_layout"
- android:layout_centerHorizontal="true"
- android:layout_marginStart="50dp"
+ android:layout_marginHorizontal="25dp"
android:hint="@string/starting_time"
android:inputType="time"
android:textAlignment="center"
@@ -249,7 +225,6 @@
android:id="@+id/start_time_buttons_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@+id/starts_time"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal"
@@ -278,9 +253,7 @@
android:id="@+id/ends_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@+id/start_time_buttons_layout"
- android:layout_centerHorizontal="true"
- android:layout_marginStart="50dp"
+ android:layout_marginHorizontal="25dp"
android:hint="@string/ends"
android:inputType="date"
android:textAlignment="center"
@@ -290,10 +263,7 @@
android:id="@+id/ends_date_validator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@+id/ends_date"
- android:layout_centerHorizontal="true"
- android:layout_marginStart="50dp"
- android:hint="Date validity"
+ android:hint="@string/date_validity"
android:textAlignment="center"
android:textSize="20sp" />
@@ -301,7 +271,6 @@
android:id="@+id/end_date_buttons_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@+id/ends_date_validator"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal"
@@ -328,9 +297,7 @@
android:id="@+id/ends_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@+id/end_date_buttons_layout"
- android:layout_centerHorizontal="true"
- android:layout_marginStart="50dp"
+ android:layout_marginHorizontal="25dp"
android:hint="@string/ending_time"
android:inputType="time"
android:textAlignment="center"
@@ -340,7 +307,6 @@
android:id="@+id/end_time_buttons_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@+id/ends_time"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal"
@@ -364,14 +330,12 @@
android:text="@string/other"
android:textAllCaps="false" />
-
+
@@ -390,11 +354,9 @@
android:id="@+id/create_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@+id/city_layout"
- android:layout_centerHorizontal="true"
- android:layout_marginTop="47dp"
+ android:layout_marginTop="18dp"
android:enabled="false"
android:text="@string/create_event"
android:textAllCaps="false" />
-
+
diff --git a/AndroidClient/src/main/res/layout/fragment_events.xml b/AndroidClient/src/main/res/layout/fragment_events.xml
index 1aed818..5711d85 100644
--- a/AndroidClient/src/main/res/layout/fragment_events.xml
+++ b/AndroidClient/src/main/res/layout/fragment_events.xml
@@ -1,31 +1,27 @@
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
-
-
-
-
+ app:tabGravity="fill"
+ app:tabIndicatorColor="@android:color/white"
+ app:tabMode="fixed"
+ app:tabSelectedTextColor="@android:color/white"
+ app:tabTextColor="@android:color/white" />
+
-
-
-
-
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
-
-
\ No newline at end of file
diff --git a/AndroidClient/src/main/res/layout/fragment_profile.xml b/AndroidClient/src/main/res/layout/fragment_profile.xml
index 5549a9f..e44dbba 100644
--- a/AndroidClient/src/main/res/layout/fragment_profile.xml
+++ b/AndroidClient/src/main/res/layout/fragment_profile.xml
@@ -1,253 +1,256 @@
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ android:orientation="vertical"
+ tools:context=".context.profile.component.fragment.ProfileFragment">
+
+
+
+
+
-
+ android:text="Photo path"
+ android:textSize="20sp"
+ android:visibility="gone" />
-
+
-
-
-
-
+ android:text="@string/select_photo"
+ android:textAllCaps="false"
+ android:textSize="20sp"
+ android:visibility="gone" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
-
+
+
+
+
+
-
+
-
+ android:text="@string/edit"
+ android:textAllCaps="false"
+ android:textSize="20sp" />
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/AndroidClient/src/main/res/layout/sub_fragment_user_events.xml b/AndroidClient/src/main/res/layout/fragment_user_events.xml
similarity index 82%
rename from AndroidClient/src/main/res/layout/sub_fragment_user_events.xml
rename to AndroidClient/src/main/res/layout/fragment_user_events.xml
index 33db302..e342e24 100644
--- a/AndroidClient/src/main/res/layout/sub_fragment_user_events.xml
+++ b/AndroidClient/src/main/res/layout/fragment_user_events.xml
@@ -4,8 +4,8 @@
android:layout_height="match_parent">
-
\ No newline at end of file
+
diff --git a/AndroidClient/src/main/res/layout/include_toolbar.xml b/AndroidClient/src/main/res/layout/include_toolbar.xml
new file mode 100644
index 0000000..bb64bc8
--- /dev/null
+++ b/AndroidClient/src/main/res/layout/include_toolbar.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/AndroidClient/src/main/res/layout/profile_account_header.xml b/AndroidClient/src/main/res/layout/profile_account_header.xml
new file mode 100644
index 0000000..0522bdd
--- /dev/null
+++ b/AndroidClient/src/main/res/layout/profile_account_header.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
diff --git a/AndroidClient/src/main/res/layout/settings_activity.xml b/AndroidClient/src/main/res/layout/settings_activity.xml
deleted file mode 100644
index f1b8294..0000000
--- a/AndroidClient/src/main/res/layout/settings_activity.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/AndroidClient/src/main/res/values-en/arrays.xml b/AndroidClient/src/main/res/values-en/arrays.xml
index 0df33a6..9efdc00 100644
--- a/AndroidClient/src/main/res/values-en/arrays.xml
+++ b/AndroidClient/src/main/res/values-en/arrays.xml
@@ -25,4 +25,16 @@
- Cancelled
- Finished
+
+ - Publish
+ - Unpublish
+ - Schedule
+ - Start
+ - Pause
+ - Resume
+ - Cancel
+ - Finish
+ - Archive
+
+
\ No newline at end of file
diff --git a/AndroidClient/src/main/res/values-en/strings.xml b/AndroidClient/src/main/res/values-en/strings.xml
index 8c8726d..a14aa21 100644
--- a/AndroidClient/src/main/res/values-en/strings.xml
+++ b/AndroidClient/src/main/res/values-en/strings.xml
@@ -68,15 +68,16 @@
- Profile
- Events
- New event
+ - Your events
- Notifications
- Settings
Starts at (hh:mm)
Ends at (hh:mm)
Now
- Map
- Events
- Your events
+ On map
+ Listed
+ Your
User information
Me
Location changed
@@ -256,6 +257,14 @@
Select one status at least.
Apply
Select interested event statuses
+ Publish
+ Published
+ Schedule
+ Scheduling event
+ Scheduled
+ Date validity
+ Your events
+ View event
- 360p
diff --git a/AndroidClient/src/main/res/values-ru-rRU/arrays.xml b/AndroidClient/src/main/res/values-ru-rRU/arrays.xml
index c86f118..89c0c59 100644
--- a/AndroidClient/src/main/res/values-ru-rRU/arrays.xml
+++ b/AndroidClient/src/main/res/values-ru-rRU/arrays.xml
@@ -20,9 +20,21 @@
- Снято c публикации
- Запланировано
- Началось
- - Остановлено
+ - Приостановлено
- Продолжено
- Отменено
- Завершено
+
+ - Опубликовать
+ - Снять с публикации
+ - Запланировать
+ - Начать
+ - Приостановить
+ - Продолжить
+ - Отменить
+ - Закончить
+ - Архивировать
+
+
\ No newline at end of file
diff --git a/AndroidClient/src/main/res/values-ru-rRU/strings.xml b/AndroidClient/src/main/res/values-ru-rRU/strings.xml
index b5dea35..c17b200 100644
--- a/AndroidClient/src/main/res/values-ru-rRU/strings.xml
+++ b/AndroidClient/src/main/res/values-ru-rRU/strings.xml
@@ -68,15 +68,16 @@
- Профиль
- События
- Новое событие
+ - Ваши события
- Уведомления
- Настройки
Начинается в (чч:мм)
Заканчивается в (чч:мм)
Сейчас
- Карта
- События
- Ваши события
+ На карте
+ Списком
+ Ваши
Пользовательская информация
Я
Локация изменена
@@ -254,6 +255,14 @@
Выберите хотя бы один статус.
Применить
Выберите интересующие статусы событий
+ Опубликовать
+ Опубликовано
+ Запланировать
+ Планирование события
+ Запланировано
+ Валидность даты
+ Ваши события
+ Просмотр события
- 360p
diff --git a/AndroidClient/src/main/res/values/arrays.xml b/AndroidClient/src/main/res/values/arrays.xml
index d63552b..9efdc00 100644
--- a/AndroidClient/src/main/res/values/arrays.xml
+++ b/AndroidClient/src/main/res/values/arrays.xml
@@ -25,5 +25,16 @@
- Cancelled
- Finished
+
+ - Publish
+ - Unpublish
+ - Schedule
+ - Start
+ - Pause
+ - Resume
+ - Cancel
+ - Finish
+ - Archive
+
\ No newline at end of file
diff --git a/AndroidClient/src/main/res/values/colors.xml b/AndroidClient/src/main/res/values/colors.xml
index 9dd7d44..c5f49d5 100644
--- a/AndroidClient/src/main/res/values/colors.xml
+++ b/AndroidClient/src/main/res/values/colors.xml
@@ -1,23 +1,27 @@
+
#125688
- #125688
+ #262626
#FFFFFF
#FFFFFF
- #000000
- #cdd4d9
+
+ #262626
+ #262626
+ #1A1919
#c8e8ff
#b1c0ca
#C0DEEF
- #BBDEFB
- #64B5F6
- #2196F3
- #EF9C1B
- #11ED18
- #FFE60F
- #11ED18
- #FB450D
- #BC0606
- #90A4AE
+ #E3F2FD
+ #1976D2
+ #6A9BED
+ #F57C00
+ #388E3C
+ #FBC02D
+ #388E3C
+ #D84315
+ #B71C1C
+ #607D8B
diff --git a/AndroidClient/src/main/res/values/strings.xml b/AndroidClient/src/main/res/values/strings.xml
index 6ff65b4..938f864 100644
--- a/AndroidClient/src/main/res/values/strings.xml
+++ b/AndroidClient/src/main/res/values/strings.xml
@@ -67,15 +67,16 @@
- Profile
- Events
- New event
+ - Your events
- Notifications
- Settings
Starts at (hh:mm)
Ends at (hh:mm)
Now
- Map
- Events
- Your events
+ On map
+ Listed
+ Your
User information
Me
Location changed
@@ -254,6 +255,14 @@
Select one status at least.
Apply
Select interested event statuses
+ Publish
+ Published
+ Schedule
+ Scheduling event
+ Scheduled
+ Date validity
+ Your events
+ View event
- 360p
diff --git a/AndroidClient/src/main/res/values/styles.xml b/AndroidClient/src/main/res/values/styles.xml
index 4a0c061..a494a7f 100644
--- a/AndroidClient/src/main/res/values/styles.xml
+++ b/AndroidClient/src/main/res/values/styles.xml
@@ -10,6 +10,8 @@
- @color/colorPrimary
- @color/colorPrimaryDark
- @color/colorAccent
+ - @color/navigationBarColor
+ - @color/statusBarColor