diff --git a/AndroidClient/build.gradle b/AndroidClient/build.gradle
index ab31dce..74add1e 100644
--- a/AndroidClient/build.gradle
+++ b/AndroidClient/build.gradle
@@ -4,12 +4,12 @@ plugins {
android {
namespace 'com.tom.meeter'
- compileSdk 33
+ compileSdk 35
defaultConfig {
applicationId "com.tom.meeter"
minSdk 21
- targetSdk 33
+ targetSdk 35
versionCode 1
versionName "1.0"
diff --git a/AndroidClient/src/main/AndroidManifest.xml b/AndroidClient/src/main/AndroidManifest.xml
index 46bf8f8..7fdabcf 100644
--- a/AndroidClient/src/main/AndroidManifest.xml
+++ b/AndroidClient/src/main/AndroidManifest.xml
@@ -56,7 +56,6 @@
-
+ android:parentActivityName=".context.profile.activity.ProfileActivity" />
+
+
+
+
(15, false));
}
- @Singleton
+ @AppScope
@NonNull
@Provides
- public EventService provideEventService() {
+ public EventService provideEventService(Application app) {
return new Retrofit.Builder()
- .baseUrl(SERVER_URL)
+ .baseUrl(getServerPath(app))
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(EventService.class);
}
- @Singleton
+ @AppScope
@NonNull
@Provides
public EventDatabase provideEventDb(Application app) {
@@ -95,30 +102,19 @@ public EventDatabase provideEventDb(Application app) {
.build();
}
- @Singleton
+ @AppScope
@NonNull
@Provides
public EventDao provideEventDao(EventDatabase eventDatabase) {
return eventDatabase.eventDao();
}
- @Singleton
- @NonNull
- @Provides
- public AuthService provideAuthService() {
- return new Retrofit.Builder()
- .baseUrl(SERVER_URL)
- .addConverterFactory(GsonConverterFactory.create())
- .build()
- .create(AuthService.class);
- }
-
- @Singleton
+ @AppScope
@NonNull
@Provides
- public SettingsService provideSettingsService() {
+ public SettingsService provideSettingsService(Application app) {
return new Retrofit.Builder()
- .baseUrl(SERVER_URL)
+ .baseUrl(getServerPath(app))
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(SettingsService.class);
diff --git a/AndroidClient/src/main/java/com/tom/meeter/AppScope.java b/AndroidClient/src/main/java/com/tom/meeter/AppScope.java
new file mode 100644
index 0000000..1a8e43c
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/AppScope.java
@@ -0,0 +1,11 @@
+package com.tom.meeter;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Scope;
+
+@Scope
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AppScope {
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/components/ExpandableHeightGridView.java b/AndroidClient/src/main/java/com/tom/meeter/components/ExpandableHeightGridView.java
new file mode 100644
index 0000000..b9afe48
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/components/ExpandableHeightGridView.java
@@ -0,0 +1,46 @@
+package com.tom.meeter.components;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.widget.GridView;
+
+public class ExpandableHeightGridView extends GridView {
+ private boolean expanded = false;
+
+ public ExpandableHeightGridView(Context context) {
+ super(context);
+ }
+
+ public ExpandableHeightGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public ExpandableHeightGridView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public boolean isExpanded() {
+ return expanded;
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (isExpanded()) {
+ // Calculate entire height by providing a very large height hint.
+ // View.MEASURED_SIZE_MASK represents the largest height possible.
+ int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
+ MeasureSpec.AT_MOST);
+ super.onMeasure(widthMeasureSpec, expandSpec);
+
+ ViewGroup.LayoutParams params = getLayoutParams();
+ params.height = getMeasuredHeight();
+ } else {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ public void setExpanded(boolean expanded) {
+ this.expanded = expanded;
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/auth/AuthComponent.java b/AndroidClient/src/main/java/com/tom/meeter/context/auth/AuthComponent.java
new file mode 100644
index 0000000..4828d15
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/auth/AuthComponent.java
@@ -0,0 +1,32 @@
+package com.tom.meeter.context.auth;
+
+import android.app.Application;
+
+import com.tom.meeter.context.auth.activity.LoginActivity;
+import com.tom.meeter.context.auth.activity.RegistrationActivity;
+import com.tom.meeter.context.auth.infrastructure.AccountAuthenticator;
+
+import javax.inject.Singleton;
+
+import dagger.BindsInstance;
+import dagger.Component;
+
+@Singleton
+@Component(modules = {AuthModule.class})
+public interface AuthComponent {
+
+ @Component.Builder
+ interface Builder {
+ @BindsInstance
+ Builder application(Application application);
+
+ AuthComponent build();
+ }
+
+
+ void inject(LoginActivity loginActivity);
+
+ void inject(RegistrationActivity registrationActivity);
+
+ void inject(AccountAuthenticator accountAuthenticator);
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/auth/AuthModule.java b/AndroidClient/src/main/java/com/tom/meeter/context/auth/AuthModule.java
new file mode 100644
index 0000000..2738374
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/auth/AuthModule.java
@@ -0,0 +1,39 @@
+package com.tom.meeter.context.auth;
+
+import static com.tom.meeter.infrastructure.common.Globals.getServerPath;
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
+
+import android.app.Application;
+
+import androidx.annotation.NonNull;
+
+import com.tom.meeter.AppModule;
+import com.tom.meeter.context.auth.service.AuthService;
+
+import javax.inject.Singleton;
+
+import dagger.Module;
+import dagger.Provides;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+@Module
+public class AuthModule {
+
+ private static final String TAG = AppModule.class.getCanonicalName();
+
+ public AuthModule() {
+ logMethod(TAG, this);
+ }
+
+ @Singleton
+ @NonNull
+ @Provides
+ public AuthService provideAuthService(Application app) {
+ return new Retrofit.Builder()
+ .baseUrl(getServerPath(app))
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ .create(AuthService.class);
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/auth/activity/LoginActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/auth/activity/LoginActivity.java
index 596bf5f..8e5c9f1 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/auth/activity/LoginActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/auth/activity/LoginActivity.java
@@ -53,7 +53,7 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
logMethod(TAG, this);
- ((App) getApplication()).getComponent().inject(this);
+ ((App) getApplication()).getAuthComponent().inject(this);
accountManager = AccountManager.get(this);
@@ -199,9 +199,8 @@ private void finishLogin(Intent intent) {
String accountType = intent.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
String token = intent.getStringExtra(AccountManager.KEY_AUTHTOKEN);
String pass = intent.getStringExtra(AccountAuthenticator.USER_PASS_KEY);
- boolean addNewAcc = getIntent().getBooleanExtra(AccountAuthenticator.IS_ADDING_NEW_ACCOUNT_KEY, false);
Account account = new Account(login, accountType);
- if (addNewAcc) {
+ if (getIntent().getBooleanExtra(AccountAuthenticator.IS_ADDING_NEW_ACCOUNT_KEY, false)) {
// Creating the account on the device and setting the auth token we got
// (Not setting the auth token will cause another call to the server to authenticate the user)
accountManager.addAccountExplicitly(account, pass, null);
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/auth/activity/RegistrationActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/auth/activity/RegistrationActivity.java
index 835660f..3cb67e4 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/auth/activity/RegistrationActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/auth/activity/RegistrationActivity.java
@@ -49,7 +49,7 @@ public class RegistrationActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
logMethod(TAG, this);
- ((App) getApplication()).getComponent().inject(this);
+ ((App) getApplication()).getAuthComponent().inject(this);
binding = RegisterActivityBinding.inflate(getLayoutInflater());
binding.registerRegisterBtn.setOnClickListener(v -> submit());
TextWatcher watcher = new TextWatcher() {
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/auth/infrastructure/AccountAuthenticator.java b/AndroidClient/src/main/java/com/tom/meeter/context/auth/infrastructure/AccountAuthenticator.java
index b7088ba..a77443f 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/auth/infrastructure/AccountAuthenticator.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/auth/infrastructure/AccountAuthenticator.java
@@ -49,7 +49,7 @@ public AccountAuthenticator(Context context) {
super(context);
this.context = context;
accountManager = AccountManager.get(context);
- ((App) context.getApplicationContext()).getComponent().inject(this);
+ ((App) context.getApplicationContext()).getAuthComponent().inject(this);
}
@Override
@@ -89,8 +89,7 @@ public Bundle getAuthToken(
if (password != null) {
Response resp;
try {
- resp = authService.login(new LoginBody(account.name, password))
- .execute();
+ resp = authService.login(new LoginBody(account.name, password)).execute();
} catch (ConnectException e) {
Log.d(TAG, "AccountAuthenticator: "
+ context.getResources().getString(R.string.server_is_unreachable));
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/auth/infrastructure/AuthHelper.java b/AndroidClient/src/main/java/com/tom/meeter/context/auth/infrastructure/AuthHelper.java
index 9b2e9c4..4cb135c 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/auth/infrastructure/AuthHelper.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/auth/infrastructure/AuthHelper.java
@@ -1,10 +1,33 @@
package com.tom.meeter.context.auth.infrastructure;
+import static com.tom.meeter.context.auth.infrastructure.AccountAuthenticator.ACCOUNT_TYPE;
+import static com.tom.meeter.context.auth.infrastructure.AccountAuthenticator.AUTH_TYPE;
+
import android.accounts.Account;
import android.accounts.AccountManager;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.tom.meeter.R;
+import com.tom.meeter.context.token.service.TokenService;
+import com.tom.meeter.infrastructure.common.Globals;
+import com.tom.meeter.infrastructure.http.DisconnectLogger;
+import com.tom.meeter.infrastructure.http.HttpCodes;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import retrofit2.Call;
+import retrofit2.Response;
public final class AuthHelper {
+ private static final String TAG = AuthHelper.class.getCanonicalName();
+
public static RuntimeException freshNotImplementedError() {
return new RuntimeException("Multiple accounts are not supported yet.");
}
@@ -13,18 +36,84 @@ private AuthHelper() {
}
public static String peekToken(AccountManager am) {
- Account[] accounts = am.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
- if (accounts.length != 1) {
- throw freshNotImplementedError();
- }
- return am.peekAuthToken(accounts[0], AccountAuthenticator.AUTH_TYPE);
+ return am.peekAuthToken(getSingleAccount(am), AccountAuthenticator.AUTH_TYPE);
}
public static void setToken(AccountManager am, String token) {
+ am.setAuthToken(getSingleAccount(am), AccountAuthenticator.AUTH_TYPE, token);
+ }
+
+ public static Account getSingleAccount(AccountManager am) {
Account[] accounts = am.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
if (accounts.length != 1) {
- throw freshNotImplementedError();
+ throw AuthHelper.freshNotImplementedError();
}
- am.setAuthToken(accounts[0], AccountAuthenticator.AUTH_TYPE, token);
+ return accounts[0];
+ }
+
+ public static void checkToken(
+ Consumer onToken, Runnable onCancelledAuth,
+ AccountManager am, Activity activity, TokenService tokenService) {
+ Account account = getSingleAccount(am);
+ String token = am.peekAuthToken(account, AUTH_TYPE);
+ if (token == null) {
+ am.getAuthToken(
+ account, AUTH_TYPE, null, activity,
+ future -> {
+ Bundle result;
+ try {
+ result = future.getResult();
+ } catch (AuthenticatorException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (OperationCanceledException e) {
+ onCancelledAuth.run();
+ return;
+ }
+ onToken.accept(result.getString(AccountManager.KEY_AUTHTOKEN));
+ }, null);
+ return;
+ }
+ tokenService.checkToken(Globals.getAuthHeader(token)).enqueue(
+ new DisconnectLogger<>(activity) {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.code() == HttpCodes.NOT_AUTHENTICATED) {
+ invalidateToken(am, activity, onToken, onCancelledAuth);
+ }
+ if (response.code() == HttpCodes.OK) {
+ onToken.accept(token);
+ }
+ }
+ });
+ }
+
+ public static void invalidateToken(
+ AccountManager am, Activity activity, Consumer onToken,
+ Runnable onCancelledAuth) {
+ Account account = getSingleAccount(am);
+ String token = am.peekAuthToken(account, AUTH_TYPE);
+ Toast.makeText(activity, R.string.refreshing_the_token, Toast.LENGTH_SHORT).show();
+ Log.i(TAG, "AuthHelper invalidating token for: " +
+ activity.getComponentName() + " : "
+ + activity.getResources().getString(R.string.refreshing_the_token));
+ am.invalidateAuthToken(ACCOUNT_TYPE, token);
+ am.getAuthToken(
+ account, AUTH_TYPE, null, activity,
+ future -> {
+ Bundle result;
+ try {
+ result = future.getResult();
+ } catch (AuthenticatorException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (OperationCanceledException e) {
+ onCancelledAuth.run();
+ return;
+ }
+ onToken.accept(result.getString(AccountManager.KEY_AUTHTOKEN));
+ }, 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
new file mode 100644
index 0000000..4c46446
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/EventComponent.java
@@ -0,0 +1,25 @@
+package com.tom.meeter.context.event;
+
+import android.app.Application;
+
+import com.tom.meeter.context.event.service.EventService;
+
+import javax.inject.Singleton;
+
+import dagger.BindsInstance;
+import dagger.Component;
+
+@Singleton
+@Component(modules = {EventModule.class})
+public interface EventComponent {
+
+ EventService provideEventService();
+
+ @Component.Builder
+ interface Builder {
+ @BindsInstance
+ Builder application(Application application);
+
+ EventComponent build();
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/EventModule.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/EventModule.java
new file mode 100644
index 0000000..8c54e61
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/EventModule.java
@@ -0,0 +1,38 @@
+package com.tom.meeter.context.event;
+
+import static com.tom.meeter.infrastructure.common.Globals.getServerPath;
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
+
+import android.app.Application;
+
+import androidx.annotation.NonNull;
+
+import com.tom.meeter.context.event.service.EventService;
+
+import javax.inject.Singleton;
+
+import dagger.Module;
+import dagger.Provides;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+@Module
+public class EventModule {
+
+ private static final String TAG = EventModule.class.getCanonicalName();
+
+ public EventModule() {
+ logMethod(TAG, this);
+ }
+
+ @Singleton
+ @NonNull
+ @Provides
+ public EventService provideEventService(Application app) {
+ return new Retrofit.Builder()
+ .baseUrl(getServerPath(app))
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ .create(EventService.class);
+ }
+}
\ No newline at end of file
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventActivity.java
new file mode 100644
index 0000000..7e9bd4a
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/activity/EventActivity.java
@@ -0,0 +1,102 @@
+package com.tom.meeter.context.event.activity;
+
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.checkToken;
+import static com.tom.meeter.infrastructure.Image.ImagesHelper.getCircleBitmap;
+import static com.tom.meeter.infrastructure.Image.ImagesHelper.randomPicResource;
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
+
+import android.accounts.AccountManager;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+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.ViewModelProviders;
+
+import com.tom.meeter.App;
+import com.tom.meeter.context.event.viewmodel.EventViewModel;
+import com.tom.meeter.context.token.service.TokenService;
+import com.tom.meeter.context.user.activity.UserActivity;
+import com.tom.meeter.databinding.EventLayoutBinding;
+import com.tom.meeter.infrastructure.injection.viewmodel.ViewModelFactory;
+
+import javax.inject.Inject;
+
+public class EventActivity extends AppCompatActivity {
+ public static final String EVENT_ID_KEY = "event_id";
+ private static final String TAG = EventActivity.class.getCanonicalName();
+ EventLayoutBinding binding;
+ @Inject
+ TokenService tokenService;
+ @Inject
+ ViewModelFactory viewModelFactory;
+ private EventViewModel eventViewModel;
+ private String eventId;
+ private AccountManager accountManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ logMethod(TAG, this);
+
+ Bundle extras = getIntent().getExtras();
+ if (extras == null) {
+ Log.d(TAG, "Unable to create event activity without extras.");
+ finish();
+ return;
+ }
+ eventId = extras.getString(EVENT_ID_KEY);
+ if (eventId == null) {
+ Log.d(TAG, "Unable to create event activity without 'event_id' provided.");
+ finish();
+ return;
+ }
+
+ ((App) getApplication()).getComponent().inject(this);
+ accountManager = AccountManager.get(this);
+
+ //setToken(accountManager, Launcher.EXPIRED);
+ checkToken(this::onInit, this::finish, accountManager, this, tokenService);
+ }
+
+ private void onInit(String token) {
+ binding = EventLayoutBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
+
+ eventViewModel = ViewModelProviders.of(this, viewModelFactory)
+ .get(EventViewModel.class);
+ eventViewModel.fetchEventInformation(token, eventId, this);
+ eventViewModel.getEventLiveData()
+ .observe(this, event -> {
+ if (event != null) {
+ Bitmap src = BitmapFactory.decodeResource(getResources(), randomPicResource());
+ Bitmap scaled = Bitmap.createScaledBitmap(src, 150, 150, true);
+ Bitmap circled = getCircleBitmap(scaled);
+ binding.eventPhoto.setImageBitmap(circled);
+ binding.eventName.setText(event.getName());
+ binding.eventDescription.setText(event.getDescription());
+ binding.eventCreatorIdBtn.setOnClickListener(v -> {
+ startActivity(new Intent(this, UserActivity.class)
+ .putExtra(UserActivity.USER_ID_KEY, event.getCreatorId()));
+ });
+ }
+ });
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(
+ @Nullable View parent, @NonNull String name, @NonNull Context ctx,
+ @NonNull AttributeSet attrs) {
+ return super.onCreateView(parent, name, ctx, attrs);
+ }
+}
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
new file mode 100644
index 0000000..993dc69
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/service/EventService.java
@@ -0,0 +1,15 @@
+package com.tom.meeter.context.event.service;
+
+import static com.tom.meeter.infrastructure.common.Globals.AUTH_HEADER;
+
+import com.tom.meeter.context.network.dto.EventDTO;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.Path;
+
+public interface EventService {
+ @GET("/event/{id}")
+ Call getEvent(@Header(AUTH_HEADER) String authHeader, @Path("id") String eventId);
+}
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
new file mode 100644
index 0000000..3d8546a
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/event/viewmodel/EventViewModel.java
@@ -0,0 +1,66 @@
+package com.tom.meeter.context.event.viewmodel;
+
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+import com.tom.meeter.context.event.service.EventService;
+import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.user.viewmodel.UserViewModel;
+import com.tom.meeter.infrastructure.common.Globals;
+import com.tom.meeter.infrastructure.http.DisconnectLogger;
+import com.tom.meeter.infrastructure.http.HttpCodes;
+
+import javax.inject.Inject;
+
+import retrofit2.Call;
+import retrofit2.Response;
+
+public class EventViewModel extends ViewModel {
+
+ private static final String TAG = UserViewModel.class.getCanonicalName();
+
+ private final MutableLiveData eventLiveData = new MutableLiveData<>();
+
+ private final EventService eventService;
+
+ @Inject
+ public EventViewModel(EventService eventService) {
+ logMethod(TAG, this);
+ this.eventService = eventService;
+ }
+
+ public void fetchEventInformation(String token, String eventId, Activity activity) {
+ eventService.getEvent(Globals.getAuthHeader(token), eventId).enqueue(
+ new DisconnectLogger<>(activity) {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.code() == HttpCodes.OK && response.body() != null) {
+ eventLiveData.setValue(response.body());
+ return;
+ }
+ if (response.code() == HttpCodes.NOT_AUTHENTICATED) {
+ activity.recreate();
+ }
+ Log.i(TAG, "/event/{id}: " + response.code() + " : " + response.body());
+ }
+ }
+ );
+ }
+
+ @Override
+ protected void onCleared() {
+ logMethod(TAG, this);
+ super.onCleared();
+ }
+
+ public LiveData getEventLiveData() {
+ return eventLiveData;
+ }
+}
+
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/gps/service/LocationTrackerService.java b/AndroidClient/src/main/java/com/tom/meeter/context/gps/service/LocationTrackerService.java
index a6bc528..8dccf6b 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/gps/service/LocationTrackerService.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/gps/service/LocationTrackerService.java
@@ -7,9 +7,9 @@
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static com.tom.meeter.infrastructure.common.Constants.APP_PROPERTIES;
-import static com.tom.meeter.infrastructure.common.Constants.LOCATION_DISTANCE_PROPERTY;
-import static com.tom.meeter.infrastructure.common.Constants.LOCATION_TIME_PROPERTY;
+import static com.tom.meeter.infrastructure.common.Globals.APP_PROPERTIES;
+import static com.tom.meeter.infrastructure.common.Globals.LOCATION_DISTANCE_PROPERTY;
+import static com.tom.meeter.infrastructure.common.Globals.LOCATION_TIME_PROPERTY;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import android.app.AlertDialog;
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 3b178f5..2167c48 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
@@ -2,6 +2,7 @@
import static com.tom.meeter.context.auth.infrastructure.AccountAuthenticator.ACCOUNT_TYPE;
import static com.tom.meeter.context.auth.infrastructure.AccountAuthenticator.AUTH_TYPE;
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.checkToken;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.showMessage;
@@ -23,21 +24,14 @@
import com.tom.meeter.App;
import com.tom.meeter.R;
+import com.tom.meeter.context.token.service.TokenService;
import com.tom.meeter.context.profile.activity.ProfileActivity;
-import com.tom.meeter.context.profile.user.domain.User;
-import com.tom.meeter.context.profile.user.service.UserService;
import com.tom.meeter.databinding.LauncherBinding;
-import com.tom.meeter.infrastructure.common.Constants;
-import com.tom.meeter.infrastructure.http.AuthInvalidatorOnAuthFail;
-import com.tom.meeter.infrastructure.http.HttpCodes;
import java.io.IOException;
import javax.inject.Inject;
-import retrofit2.Call;
-import retrofit2.Response;
-
public class Launcher extends AppCompatActivity {
private static final String TAG = Launcher.class.getCanonicalName();
@@ -48,15 +42,14 @@ public class Launcher extends AppCompatActivity {
private AccountManager accountManager;
private LauncherBinding binding;
-
@Inject
- UserService profileService;
+ TokenService tokenService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
logMethod(TAG, this);
- ((App) getApplication()).getComponent().inject(this);
+ ((App) getApplication()).getTokenComponent().inject(this);
accountManager = AccountManager.get(this);
binding = LauncherBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
@@ -91,20 +84,24 @@ private void initialize() {
} else if (accounts.length == 1) {
//accountManager.setAuthToken(accounts[0], AUTH_TYPE, EXPIRED);
showMessage(Launcher.this, getString(R.string.check_token));
- checkExistingToken(accounts[0]);
+ checkToken((ign) -> dispatch(), this::finish, accountManager, this, tokenService);
} else {
removeAllAccounts();
createAccountAndContinue();
}
}
+ private void dispatch() {
+ startActivity(new Intent(Launcher.this, ProfileActivity.class));
+ }
+
private void createAccountAndContinue() {
accountManager.addAccount(
ACCOUNT_TYPE, AUTH_TYPE, null, null, this,
- addAccountBundleF -> {
+ bundleF -> {
Bundle bnd;
try {
- bnd = addAccountBundleF.getResult();
+ bnd = bundleF.getResult();
} catch (OperationCanceledException | AuthenticatorException | IOException e) {
showMessage(this, e.getMessage());
finish();
@@ -112,7 +109,7 @@ private void createAccountAndContinue() {
}
showMessage(this, getString(R.string.account_created));
Log.d(TAG, "AddNewAccount Bundle is " + bnd);
- startActivity(new Intent(Launcher.this, ProfileActivity.class));
+ dispatch();
},
null);
}
@@ -124,42 +121,6 @@ private void removeAllAccounts() {
}
}
- private void checkExistingToken(Account account) {
- String token = accountManager.peekAuthToken(account, AUTH_TYPE);
- if (token == null) {
- accountManager.getAuthToken(
- account, AUTH_TYPE, null, Launcher.this,
- future -> {
- Bundle result;
- try {
- result = future.getResult();
- } catch (AuthenticatorException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new RuntimeException(e);
- } catch (OperationCanceledException e) {
- finish();
- return;
- }
- startActivity(new Intent(Launcher.this, ProfileActivity.class));
- }, null);
- return;
- }
- profileService.getProfile(Constants.getAuthHeader(token)).enqueue(
- new AuthInvalidatorOnAuthFail<>(
- this, accountManager,
- (freshToken) -> startActivity(new Intent(this, ProfileActivity.class)),
- this::finish) {
- @Override
- public void onResponse(Call call, Response response) {
- super.onResponse(call, response);
- if (response.code() == HttpCodes.OK) {
- startActivity(new Intent(Launcher.this, ProfileActivity.class));
- }
- }
- });
- }
-
@Override
protected void onResume() {
super.onResume();
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/CreateNewEventAttempt.java b/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/CreateNewEventAttempt.java
index f08b2de..3264daf 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/CreateNewEventAttempt.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/CreateNewEventAttempt.java
@@ -7,32 +7,48 @@
public class CreateNewEventAttempt implements NetworkEvent {
- private String name;
- private String description;
- private OffsetDateTime starting;
- private OffsetDateTime ending;
- private Float latitude;
- private Float longitude;
+ private final String name;
+ private final String description;
+ private final OffsetDateTime starting;
+ private final OffsetDateTime ending;
+ private final Float latitude;
+ private final Float longitude;
- public CreateNewEventAttempt(
- String name, String description, OffsetDateTime starting, OffsetDateTime ending,
- Float latitude, Float longitude) {
- this.name = name;
- this.description = description;
- this.starting = starting;
- this.ending = ending;
- this.latitude = latitude;
- this.longitude = longitude;
- }
+ public CreateNewEventAttempt(
+ String name, String description, OffsetDateTime starting,
+ OffsetDateTime ending, Float latitude, Float longitude) {
+ this.name = name;
+ this.description = description;
+ this.starting = starting;
+ this.ending = ending;
+ this.latitude = latitude;
+ this.longitude = longitude;
+ }
- @Override
- public JSONObject toJson() throws JSONException {
- return new JSONObject()
- .put("name", name)
- .put("description", description)
- .put("starting", starting)
- .put("ending", ending)
- .put("latitude", latitude)
- .put("longitude", longitude);
- }
+ @Override
+ public JSONObject toJson() {
+ try {
+ return new JSONObject()
+ .put("name", name)
+ .put("description", description)
+ .put("starting", starting)
+ .put("ending", ending)
+ .put("latitude", latitude)
+ .put("longitude", longitude);
+ } catch (JSONException e) {
+ throw new RuntimeException("Unable to call CreateNewEventAttempt.toJson(): ", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "CreateNewEventAttempt{" +
+ "name='" + name +
+ ", description='" + description +
+ ", starting=" + starting +
+ ", ending=" + ending +
+ ", latitude=" + latitude +
+ ", longitude=" + longitude +
+ '}';
+ }
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/NetworkEvent.java b/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/NetworkEvent.java
index 12858de..a03f979 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/NetworkEvent.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/NetworkEvent.java
@@ -1,9 +1,7 @@
package com.tom.meeter.context.network.domain;
-import org.json.JSONException;
import org.json.JSONObject;
public interface NetworkEvent {
-
- JSONObject toJson() throws JSONException;
+ JSONObject toJson();
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/SearchForEvents.java b/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/SearchForEvents.java
index 87e97d5..3422494 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/SearchForEvents.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/network/domain/SearchForEvents.java
@@ -1,5 +1,7 @@
package com.tom.meeter.context.network.domain;
+import androidx.annotation.NonNull;
+
import org.json.JSONException;
import org.json.JSONObject;
@@ -7,46 +9,14 @@
* Created by Tom on 14.01.2017.
*/
-public class SearchForEvents implements NetworkEvent {
+public record SearchForEvents(float latitude, float longitude, int distance)
+ implements NetworkEvent {
private static final String LATITUDE_KEY = "latitude";
private static final String LONGITUDE_KEY = "longitude";
private static final String DISTANCE_KEY = "distance";
- private float latitude;
- private float longitude;
- private int distance;
-
- public SearchForEvents(float latitude, float longitude, int distance) {
- this.latitude = latitude;
- this.longitude = longitude;
- this.distance = distance;
- }
-
- public float getLongitude() {
- return longitude;
- }
-
- public void setLongitude(float longitude) {
- this.longitude = longitude;
- }
-
- public int getDistance() {
- return distance;
- }
-
- public void setDistance(int distance) {
- this.distance = distance;
- }
-
- public float getLatitude() {
- return latitude;
- }
-
- public void setLatitude(float latitude) {
- this.latitude = latitude;
- }
-
+ @NonNull
@Override
public String toString() {
return "SearchForEvents{" +
@@ -57,10 +27,14 @@ public String toString() {
}
@Override
- public JSONObject toJson() throws JSONException {
- return new JSONObject()
- .put(LATITUDE_KEY, latitude)
- .put(LONGITUDE_KEY, longitude)
- .put(DISTANCE_KEY, distance);
+ public JSONObject toJson() {
+ try {
+ return new JSONObject()
+ .put(LATITUDE_KEY, latitude)
+ .put(LONGITUDE_KEY, longitude)
+ .put(DISTANCE_KEY, distance);
+ } catch (JSONException e) {
+ throw new RuntimeException("Unable to call SearchForEvents.toJson(): ", e);
+ }
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/network/dto/EventDTO.java b/AndroidClient/src/main/java/com/tom/meeter/context/network/dto/EventDTO.java
index ee53fe5..0813221 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/network/dto/EventDTO.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/network/dto/EventDTO.java
@@ -1,8 +1,12 @@
package com.tom.meeter.context.network.dto;
+import com.google.gson.annotations.SerializedName;
+
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.Objects;
+
/**
* created by Tom on 10.02.2017.
*/
@@ -24,7 +28,8 @@ public class EventDTO {
private String description;
private double latitude;
private double longitude;
- private String creator_id;
+ @SerializedName(value = CREATOR_ID_KEY)
+ private String creatorId;
private String created;
private String starting;
private String ending;
@@ -32,17 +37,21 @@ public class EventDTO {
public EventDTO() {
}
- public static EventDTO encode(JSONObject json) throws JSONException {
+ public static EventDTO encode(JSONObject json) {
EventDTO result = new EventDTO();
- result.id = json.getString(EVENT_ID_KEY);
- result.name = json.getString(NAME_KEY);
- result.description = json.getString(DESCRIPTION_KEY);
- result.creator_id = json.getString(CREATOR_ID_KEY);
- result.latitude = json.getDouble(LATITUDE_KEY);
- result.longitude = json.getDouble(LONGITUDE_KEY);
- result.created = json.getString(CREATED_KEY);
- result.starting = json.getString(STARTING_KEY);
- result.ending = json.getString(ENDING_KEY);
+ try {
+ result.id = json.getString(EVENT_ID_KEY);
+ result.name = json.getString(NAME_KEY);
+ result.description = json.getString(DESCRIPTION_KEY);
+ result.creatorId = json.getString(CREATOR_ID_KEY);
+ result.latitude = json.getDouble(LATITUDE_KEY);
+ result.longitude = json.getDouble(LONGITUDE_KEY);
+ result.created = json.getString(CREATED_KEY);
+ result.starting = json.getString(STARTING_KEY);
+ result.ending = json.getString(ENDING_KEY);
+ } catch (JSONException e) {
+ throw new RuntimeException("Unable to encode EventDTO from jsonObject, ", e);
+ }
return result;
}
@@ -86,12 +95,12 @@ public void setLongitude(double longitude) {
this.longitude = longitude;
}
- public String getCreator_id() {
- return creator_id;
+ public String getCreatorId() {
+ return creatorId;
}
- public void setCreator_id(String creator_id) {
- this.creator_id = creator_id;
+ public void setCreatorId(String creatorId) {
+ this.creatorId = creatorId;
}
public String getCreated() {
@@ -117,4 +126,26 @@ public String getEnding() {
public void setEnding(String ending) {
this.ending = ending;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof EventDTO eventDTO)) {
+ return false;
+ }
+ return Double.compare(latitude, eventDTO.latitude) == 0
+ && Double.compare(longitude, eventDTO.longitude) == 0
+ && Objects.equals(id, eventDTO.id)
+ && Objects.equals(name, eventDTO.name)
+ && Objects.equals(description, eventDTO.description)
+ && Objects.equals(creatorId, eventDTO.creatorId)
+ && Objects.equals(created, eventDTO.created)
+ && Objects.equals(starting, eventDTO.starting)
+ && Objects.equals(ending, eventDTO.ending);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name, description, latitude, longitude,
+ creatorId, created, starting, ending);
+ }
}
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 74032ea..847ec05 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,8 +1,8 @@
package com.tom.meeter.context.network.service;
import static com.tom.meeter.context.auth.infrastructure.AuthHelper.peekToken;
-import static com.tom.meeter.infrastructure.common.Constants.AUTH_HEADER;
-import static com.tom.meeter.infrastructure.common.Constants.initSocketIOPath;
+import static com.tom.meeter.infrastructure.common.Globals.AUTH_HEADER;
+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;
import static io.socket.client.Socket.EVENT_CONNECT_ERROR;
@@ -17,7 +17,7 @@
import com.tom.meeter.context.network.domain.CreateNewEventAttempt;
import com.tom.meeter.context.network.domain.SearchForEvents;
-import com.tom.meeter.infrastructure.common.Constants;
+import com.tom.meeter.infrastructure.common.Globals;
import com.tom.meeter.infrastructure.common.JsonHelper;
import com.tom.meeter.infrastructure.eventbus.events.FailureEventCreation;
import com.tom.meeter.infrastructure.eventbus.events.IncomeEvents;
@@ -26,7 +26,6 @@
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;
@@ -134,7 +133,7 @@ private void initializeSocketClient(
Log.d(TAG, "SocketIOService is not going to initialize, since it is already initialized.");
return;
}
- String uri = initSocketIOPath(getBaseContext());
+ String uri = getSocketIOPath(getBaseContext());
Log.d(TAG, "Configuring SocketIOClient for server: " + uri);
socketClient = IO.socket(uri, setupOptions(authToken));
@@ -212,21 +211,13 @@ private void disconnect() {
@Subscribe
public void onMessageEvent(SearchForEvents event) {
Log.d(TAG, "onMessageEvent:SearchForEvents: " + event.toString());
- try {
- socketClient.emit(EVENTS_SEARCH_CHANNEL, event.toJson());
- } catch (JSONException e) {
- Log.e(TAG, e.getMessage(), e);
- }
+ socketClient.emit(EVENTS_SEARCH_CHANNEL, event.toJson());
}
@Subscribe
public void onMessageEvent(CreateNewEventAttempt event) {
Log.d(TAG, "onMessageEvent:CreateNewEventAttempt: " + event.toString());
- try {
- socketClient.emit(EVENTS_CREATE_CHANNEL, event.toJson());
- } catch (JSONException e) {
- Log.e(TAG, e.getMessage(), e);
- }
+ socketClient.emit(EVENTS_CREATE_CHANNEL, event.toJson());
}
private static String readFlags(int flags) {
@@ -248,7 +239,7 @@ private static IO.Options setupOptions(String authToken) {
private static Map> setupAuthenticationHeader(String authToken) {
Map> result = new HashMap<>();
- result.put(AUTH_HEADER, Collections.singletonList(Constants.getAuthHeader(authToken)));
+ result.put(AUTH_HEADER, Collections.singletonList(Globals.getAuthHeader(authToken)));
return result;
}
@@ -259,7 +250,7 @@ private static void greetingsHandler(Object... args) {
private static void eventsSearchHandler(Object... args) {
JSONArray response = getSimpleResponse(JSONArray.class, args);
Log.d(TAG, EVENTS_SEARCH_CHANNEL + " : " + response);
- EventBus.getDefault().post(new IncomeEvents(response));
+ EventBus.getDefault().post(IncomeEvents.fromJsonArray(response));
}
private static T getSimpleResponse(Class aClass, Object[] args) {
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/activity/ProfileActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/activity/ProfileActivity.java
index ed02797..4a78c3b 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/activity/ProfileActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/activity/ProfileActivity.java
@@ -1,13 +1,12 @@
package com.tom.meeter.context.profile.activity;
import static androidx.preference.PreferenceManager.getDefaultSharedPreferences;
-import static com.tom.meeter.context.auth.infrastructure.AccountAuthenticator.AUTH_TYPE;
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.checkToken;
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.invalidateToken;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
@@ -50,23 +49,20 @@
import com.tom.meeter.App;
import com.tom.meeter.R;
import com.tom.meeter.context.auth.infrastructure.AccountAuthenticator;
-import com.tom.meeter.context.auth.infrastructure.AuthHelper;
+import com.tom.meeter.context.token.service.TokenService;
import com.tom.meeter.context.network.service.SocketIOService;
import com.tom.meeter.context.profile.fragment.CreateNewEventFragment;
import com.tom.meeter.context.profile.fragment.EventsFragment;
import com.tom.meeter.context.profile.fragment.ProfileFragment;
import com.tom.meeter.context.profile.fragment.UserEventsFragment;
+import com.tom.meeter.context.profile.service.ProfileService;
import com.tom.meeter.context.profile.settings.message.SettingsResponse;
import com.tom.meeter.context.profile.settings.service.SettingsService;
-import com.tom.meeter.context.profile.user.domain.User;
-import com.tom.meeter.context.profile.user.service.UserService;
import com.tom.meeter.databinding.ProfileActivityBinding;
-import com.tom.meeter.infrastructure.common.Constants;
-import com.tom.meeter.infrastructure.http.AuthInvalidatorOnAuthFail;
+import com.tom.meeter.infrastructure.common.Globals;
import com.tom.meeter.infrastructure.http.DisconnectLogger;
import com.tom.meeter.infrastructure.http.HttpCodes;
-import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@@ -135,8 +131,9 @@ private enum IconPackEnum {
@Inject
SettingsService settingsService;
@Inject
- UserService profileService;
-
+ ProfileService profileService;
+ @Inject
+ TokenService tokenService;
private ServiceConnection socketServiceConnection;
private SocketIOService socketIOService;
@@ -168,48 +165,9 @@ public void onServiceDisconnected(ComponentName name) {
};
//setToken(accountManager, Launcher.EXPIRED);
- checkExistingToken(savedInstanceState != null);
- }
-
- private void checkExistingToken(boolean isSavedInstanceStateExist) {
- Account[] accounts = accountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
- if (accounts.length != 1) {
- throw AuthHelper.freshNotImplementedError();
- }
- Account account = accounts[0];
- String token = accountManager.peekAuthToken(account, AUTH_TYPE);
- if (token == null) {
- accountManager.getAuthToken(
- account, AUTH_TYPE, null, ProfileActivity.this,
- future -> {
- Bundle result;
- try {
- result = future.getResult();
- } catch (AuthenticatorException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new RuntimeException(e);
- } catch (OperationCanceledException e) {
- finish();
- return;
- }
- onInit(result.getString(AccountManager.KEY_AUTHTOKEN), isSavedInstanceStateExist);
- }, null);
- return;
- }
- profileService.getProfile(Constants.getAuthHeader(token)).enqueue(
- new AuthInvalidatorOnAuthFail<>(
- this, accountManager,
- (freshToken) -> onInit(freshToken, isSavedInstanceStateExist),
- this::finish) {
- @Override
- public void onResponse(Call call, Response response) {
- super.onResponse(call, response);
- if (response.code() == HttpCodes.OK) {
- onInit(token, isSavedInstanceStateExist);
- }
- }
- });
+ checkToken(
+ (token) -> onInit(token, savedInstanceState != null),
+ this::finish, accountManager, this, tokenService);
}
private void onInit(String token, boolean isSavedInstanceStateExist) {
@@ -240,14 +198,15 @@ private void onInit(String token, boolean isSavedInstanceStateExist) {
}
private void setupPreferences(String token) {
- Call settings = settingsService.getSettings(Constants.getAuthHeader(token));
+ Call settings = settingsService.getSettings(Globals.getAuthHeader(token));
settings.enqueue(
- new AuthInvalidatorOnAuthFail<>(this, accountManager,
- this::setupPreferencesRetry,
- this::finish) {
+ new DisconnectLogger<>(this) {
@Override
public void onResponse(Call call, Response res) {
- super.onResponse(call, res);
+ if (res.code() == HttpCodes.NOT_AUTHENTICATED) {
+ invalidateToken(accountManager, ProfileActivity.this,
+ fresh -> setupPreferencesRetry(fresh), () -> finishAndRemoveTask());
+ }
if (res.code() == HttpCodes.NOT_FOUND) {
// As no settings on the server ...
return;
@@ -262,7 +221,7 @@ public void onResponse(Call call, Response r
}
private void setupPreferencesRetry(String freshToken) {
- settingsService.getSettings(Constants.getAuthHeader(freshToken))
+ settingsService.getSettings(Globals.getAuthHeader(freshToken))
.enqueue(new DisconnectLogger<>(this) {
@Override
public void onResponse(Call call, Response res) {
@@ -435,7 +394,7 @@ private void handleLogout() {
accs[0], this, future -> {
Log.d(TAG, "Account '" + accs[0].name + "' removed.");
unbindSocketService();
- finish();
+ finishAndRemoveTask();
}, null);
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/activity/SettingsActivity.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/activity/SettingsActivity.java
index 31be347..54420e1 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/activity/SettingsActivity.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/activity/SettingsActivity.java
@@ -1,5 +1,6 @@
package com.tom.meeter.context.profile.activity;
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.invalidateToken;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import android.accounts.AccountManager;
@@ -23,9 +24,8 @@
import com.tom.meeter.context.profile.settings.message.SettingsResponse;
import com.tom.meeter.context.profile.settings.service.SettingsService;
import com.tom.meeter.databinding.SettingsActivityBinding;
-import com.tom.meeter.infrastructure.common.Constants;
+import com.tom.meeter.infrastructure.common.Globals;
import com.tom.meeter.infrastructure.common.PreferencesHelper;
-import com.tom.meeter.infrastructure.http.AuthInvalidatorOnAuthFail;
import com.tom.meeter.infrastructure.http.DisconnectLogger;
import com.tom.meeter.infrastructure.http.HttpCodes;
@@ -111,16 +111,19 @@ public void onBackPressed() {
private void sendSavePrefs(int searchArea, boolean trackUser) {
settingsService.createOrUpdateSettings(
new SettingsCreateOrUpdate(searchArea, trackUser),
- Constants.getAuthHeader(AuthHelper.peekToken(accountManager)))
- .enqueue(new AuthInvalidatorOnAuthFail<>(this, accountManager,
- freshToken -> sendSavePrefsRetry(freshToken, searchArea, trackUser),
- () -> {
- Log.d(TAG, "SettingsActivity: canceled auth. ");
- startActivity(new Intent(this, Launcher.class));
- }) {
+ Globals.getAuthHeader(AuthHelper.peekToken(accountManager)))
+ .enqueue(new DisconnectLogger<>(this) {
@Override
public void onResponse(Call call, Response res) {
- super.onResponse(call, res);
+ if (res.code() == HttpCodes.NOT_AUTHENTICATED) {
+ invalidateToken(
+ accountManager, SettingsActivity.this,
+ (freshToken) -> sendSavePrefsRetry(freshToken, searchArea, trackUser),
+ () -> {
+ Log.d(TAG, "SettingsActivity: canceled auth.");
+ startActivity(new Intent(SettingsActivity.this, Launcher.class));
+ });
+ }
if (res.code() == HttpCodes.OK || res.code() == HttpCodes.CREATED) {
Log.d(TAG, "SettingsActivity: created/updated server settings.");
}
@@ -131,7 +134,7 @@ public void onResponse(Call call, Response r
private void sendSavePrefsRetry(String token, int searchArea, boolean trackUser) {
settingsService.createOrUpdateSettings(
new SettingsCreateOrUpdate(searchArea, trackUser),
- Constants.getAuthHeader(token))
+ Globals.getAuthHeader(token))
.enqueue(new DisconnectLogger<>(this) {
@Override
public void onResponse(Call call, Response res) {
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/EventViewHolder.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/EventViewHolder.java
index 6e429d2..0d62b6c 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/EventViewHolder.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/EventViewHolder.java
@@ -1,5 +1,8 @@
package com.tom.meeter.context.profile.adapter;
+import android.graphics.Bitmap;
+import android.view.View;
+
import androidx.recyclerview.widget.RecyclerView;
import com.tom.meeter.databinding.EventViewBinding;
@@ -12,8 +15,10 @@ public EventViewHolder(EventViewBinding binding) {
this.binding = binding;
}
- public void bind(String name, String description) {
+ public void bind(String name, String description, Bitmap photo, View.OnClickListener clickListener) {
binding.eventNameCardView.setText(name);
binding.eventDescriptionCardView.setText(description);
+ binding.eventPhotoCardView.setImageBitmap(photo);
+ binding.eventCardView.setOnClickListener(clickListener);
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/RecycleViewActiveEventsAdapter.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/RecycleViewActiveEventsAdapter.java
index 6374a52..8da7a35 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/RecycleViewActiveEventsAdapter.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/RecycleViewActiveEventsAdapter.java
@@ -1,10 +1,18 @@
package com.tom.meeter.context.profile.adapter;
+import static com.tom.meeter.infrastructure.Image.ImagesHelper.getCircleBitmap;
+import static com.tom.meeter.infrastructure.Image.ImagesHelper.randomPicResource;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
+import com.tom.meeter.context.event.activity.EventActivity;
import com.tom.meeter.context.network.dto.EventDTO;
import com.tom.meeter.databinding.EventViewBinding;
@@ -15,11 +23,18 @@
* created by Tom on 10.02.2017.
*/
public class RecycleViewActiveEventsAdapter extends RecyclerView.Adapter {
+ private static final String TAG = RecycleViewUserEventsAdapter.class.getCanonicalName();
private final List events = new ArrayList<>();
+ private Context ctx;
public RecycleViewActiveEventsAdapter() {
}
+ //TODO remove me when image can be downloaded from the server
+ public RecycleViewActiveEventsAdapter(Context ctx) {
+ this.ctx = ctx;
+ }
+
public List getEvents() {
return events;
}
@@ -47,7 +62,15 @@ public EventViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
@Override
public void onBindViewHolder(EventViewHolder holder, int position) {
EventDTO event = events.get(position);
- holder.bind(event.getName(), event.getDescription());
+
+ Bitmap src = BitmapFactory.decodeResource(ctx.getResources(), randomPicResource());
+ Bitmap scaled = Bitmap.createScaledBitmap(src, 150, 150, true);
+ Bitmap circled = getCircleBitmap(scaled);
+
+ holder.bind(event.getName(), event.getDescription(), circled,
+ v -> ctx.startActivity(
+ new Intent(ctx, EventActivity.class)
+ .putExtra(EventActivity.EVENT_ID_KEY, event.getId())));
}
@Override
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/RecycleViewUserEventsAdapter.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/RecycleViewUserEventsAdapter.java
index a5aa751..c0b3f8c 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/RecycleViewUserEventsAdapter.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/adapter/RecycleViewUserEventsAdapter.java
@@ -1,12 +1,20 @@
package com.tom.meeter.context.profile.adapter;
+import static com.tom.meeter.infrastructure.Image.ImagesHelper.getCircleBitmap;
+import static com.tom.meeter.infrastructure.Image.ImagesHelper.randomPicResource;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
-import com.tom.meeter.context.profile.event.domain.Event;
+import com.tom.meeter.context.event.activity.EventActivity;
+import com.tom.meeter.context.network.dto.EventDTO;
import com.tom.meeter.databinding.EventViewBinding;
import java.util.ArrayList;
@@ -17,12 +25,18 @@
*/
public class RecycleViewUserEventsAdapter extends RecyclerView.Adapter {
- private final List events = new ArrayList<>();
+ private final List events = new ArrayList<>();
+
+ //TODO remove me when ...
+ private Context ctx;
+ public RecycleViewUserEventsAdapter(Context ctx) {
+ this.ctx = ctx;
+ }
public RecycleViewUserEventsAdapter() {
}
- public void setData(List events) {
+ public void setData(List events) {
EventDiffCallback eventDiffCallback = new EventDiffCallback(this.events, events);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(eventDiffCallback);
this.events.clear();
@@ -41,8 +55,16 @@ public EventViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
@Override
public void onBindViewHolder(EventViewHolder holder, int position) {
- Event event = events.get(position);
- holder.bind(event.getName(), event.getDescription());
+ EventDTO event = events.get(position);
+
+ Bitmap src = BitmapFactory.decodeResource(ctx.getResources(), randomPicResource());
+ Bitmap scaled = Bitmap.createScaledBitmap(src, 150, 150, true);
+ Bitmap circled = getCircleBitmap(scaled);
+
+ holder.bind(event.getName(), event.getDescription(), circled,
+ v -> ctx.startActivity(
+ new Intent(ctx, EventActivity.class)
+ .putExtra(EventActivity.EVENT_ID_KEY, event.getId())));
/*
btnDelete.setOnClickListener(v -> {
if (onDeleteButtonClickListener != null)
@@ -62,9 +84,9 @@ public void onAttachedToRecyclerView(RecyclerView recyclerView) {
private static class EventDiffCallback extends DiffUtil.Callback {
- private final List oldPosts, newPosts;
+ private final List oldPosts, newPosts;
- EventDiffCallback(List oldPosts, List newPosts) {
+ EventDiffCallback(List oldPosts, List newPosts) {
this.oldPosts = oldPosts;
this.newPosts = newPosts;
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/domain/GMapEvent.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/domain/GMapEvent.java
new file mode 100644
index 0000000..071d9b2
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/domain/GMapEvent.java
@@ -0,0 +1,101 @@
+package com.tom.meeter.context.profile.domain;
+
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Marker;
+import com.tom.meeter.context.network.dto.EventDTO;
+
+import java.util.Objects;
+
+public class GMapEvent {
+
+ private EventDTO event;
+ private Marker marker;
+
+ public GMapEvent(EventDTO event, Marker marker) {
+ validate(event, marker);
+ this.event = event;
+ this.marker = marker;
+ }
+
+ public void removeMarker() {
+ marker.remove();
+ }
+
+ public String getName() {
+ return event.getName();
+ }
+
+ public boolean isInfoWindowShown() {
+ return marker.isInfoWindowShown();
+ }
+
+ public String getCreatorId() {
+ return event.getCreatorId();
+ }
+
+ public String getId() {
+ return event.getId();
+ }
+
+ public double getLatitude() {
+ return event.getLatitude();
+ }
+
+ public double getLongitude() {
+ return event.getLongitude();
+ }
+
+ public String getMarkerId() {
+ return marker.getId();
+ }
+
+ public void updateName(String name) {
+ event.setName(name);
+ marker.setTitle(name);
+ }
+
+ public void updatePosition(double latitude, double longitude) {
+ event.setLatitude(latitude);
+ event.setLongitude(longitude);
+ marker.setPosition(new LatLng(latitude, longitude));
+ }
+
+ public void replaceMarker(Marker marker) {
+ validate(event, marker);
+ this.marker = marker;
+ }
+
+ private static void validate(EventDTO event, Marker marker) {
+ String name = event.getName();
+ String title = marker.getTitle();
+ if (!name.equals(title)) {
+ throw new IllegalArgumentException("Names are not equals " + name + ":" + title);
+ }
+ LatLng position = marker.getPosition();
+ double latitude = event.getLatitude();
+ if (latitude != position.latitude) {
+ throw new IllegalArgumentException(
+ "Latitudes are not equals " + latitude + ":" + position.latitude);
+ }
+ double longitude = event.getLongitude();
+ if (longitude != position.longitude) {
+ throw new IllegalArgumentException(
+ "Longitude are not equals " + longitude + ":" + position.longitude);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GMapEvent gMapEvent = (GMapEvent) o;
+ return Objects.equals(event, gMapEvent.event)
+ && Objects.equals(marker, gMapEvent.marker);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(event, marker);
+ }
+}
\ No newline at end of file
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/event/repository/EventRepository.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/event/repository/EventRepository.java
index 8b2a605..ff0b100 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/event/repository/EventRepository.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/event/repository/EventRepository.java
@@ -4,6 +4,7 @@
import androidx.lifecycle.LiveData;
+import com.tom.meeter.AppScope;
import com.tom.meeter.context.network.dto.EventDTO;
import com.tom.meeter.context.profile.event.database.EventDao;
import com.tom.meeter.context.profile.event.domain.Event;
@@ -15,11 +16,10 @@
import java.util.concurrent.Executor;
import javax.inject.Inject;
-import javax.inject.Singleton;
import retrofit2.Response;
-@Singleton
+@AppScope
public class EventRepository {
private static final String TAG = EventRepository.class.getCanonicalName();
@@ -42,29 +42,29 @@ public LiveData> getUserEventsLiveData(String userId) {
private void refreshUserEvents(String userId) {
executor.execute(
- () -> {
- Response> execute = null;
- try {
- execute = eventService.getEventsByCreatorId(userId).execute();
- } catch (IOException e) {
- Log.e(TAG, e.getMessage(), e);
- }
- if (execute == null) {
- return;
- }
- List body = execute.body();
- if (body == null) {
- return;
- }
- List result = new ArrayList<>();
- body.stream()
- .forEach(i -> result.add(
- new Event(i.getId(), i.getName(), i.getDescription(), i.getLatitude(),
- i.getLongitude(), i.getCreator_id(), i.getCreated(), i.getStarting(),
- i.getEnding())
- ));
- eventDao.deleteByUserId(userId);
- eventDao.saveAll(result);
- });
+ () -> {
+ Response> execute = null;
+ try {
+ execute = eventService.getEventsByCreatorId(userId).execute();
+ } catch (IOException e) {
+ Log.e(TAG, e.getMessage(), e);
+ }
+ if (execute == null) {
+ return;
+ }
+ List body = execute.body();
+ if (body == null) {
+ return;
+ }
+ List result = new ArrayList<>();
+ body.stream()
+ .forEach(i -> result.add(
+ new Event(i.getId(), i.getName(), i.getDescription(), i.getLatitude(),
+ i.getLongitude(), i.getCreatorId(), i.getCreated(), i.getStarting(),
+ i.getEnding())
+ ));
+ eventDao.deleteByUserId(userId);
+ eventDao.saveAll(result);
+ });
}
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/event/service/EventService.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/event/service/EventService.java
index d5c5fdf..04c7b6c 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/event/service/EventService.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/event/service/EventService.java
@@ -8,6 +8,7 @@
import retrofit2.http.GET;
import retrofit2.http.Path;
+@Deprecated
public interface EventService {
/**
* @GET declares an HTTP GET request
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/ActiveEventsFragment.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/ActiveEventsFragment.java
index 29076b6..56fc0c1 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/ActiveEventsFragment.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/ActiveEventsFragment.java
@@ -66,7 +66,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
binding.activeEventsFragmentRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// specify an adapter (see also next example)
- recycleViewActiveEventsAdapter = new RecycleViewActiveEventsAdapter();
+ recycleViewActiveEventsAdapter = new RecycleViewActiveEventsAdapter(getContext());
binding.activeEventsFragmentRecyclerView.setAdapter(recycleViewActiveEventsAdapter);
binding.activeEventsFragmentRecyclerView.invalidate();
}
@@ -74,8 +74,8 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(IncomeEvents eventsSearch) {
recycleViewActiveEventsAdapter.cleanEvents();
- if (!eventsSearch.getEvents().isEmpty()) {
- recycleViewActiveEventsAdapter.addEvents(eventsSearch.getEvents());
+ if (!eventsSearch.events().isEmpty()) {
+ recycleViewActiveEventsAdapter.addEvents(eventsSearch.events());
}
binding.activeEventsFragmentRecyclerView.requestLayout();
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/GoogleMapsFragment.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/GoogleMapsFragment.java
index 3dc73b0..a04d448 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/GoogleMapsFragment.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/GoogleMapsFragment.java
@@ -1,6 +1,8 @@
package com.tom.meeter.context.profile.fragment;
import static android.content.Context.BIND_AUTO_CREATE;
+import static com.tom.meeter.infrastructure.Image.ImagesHelper.getCircleBitmap;
+import static com.tom.meeter.infrastructure.Image.ImagesHelper.randomPicResource;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import android.content.ComponentName;
@@ -8,9 +10,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
+import android.graphics.BitmapFactory;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
@@ -20,12 +20,14 @@
import android.view.ViewGroup;
import android.widget.Toast;
+import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMapOptions;
+import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
@@ -37,12 +39,13 @@
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.common.collect.Sets;
-import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import com.tom.meeter.R;
+import com.tom.meeter.context.event.activity.EventActivity;
import com.tom.meeter.context.gps.domain.LocationTrackerListener;
import com.tom.meeter.context.gps.service.LocationTrackerService;
import com.tom.meeter.context.network.domain.SearchForEvents;
import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.profile.domain.GMapEvent;
import com.tom.meeter.infrastructure.common.PreferencesHelper;
import com.tom.meeter.infrastructure.eventbus.events.IncomeEvents;
@@ -63,7 +66,6 @@ public class GoogleMapsFragment extends Fragment
implements OnMapReadyCallback, LocationTrackerListener {
private static final String TAG = GoogleMapsFragment.class.getCanonicalName();
- private static final FontAwesome FONT_AWESOME = new FontAwesome();
private static final float ZOOM_VALUE = 17;
private static final LatLng DEFAULT = new LatLng(0.0, 0.0);
@@ -80,6 +82,9 @@ public class GoogleMapsFragment extends Fragment
private GoogleMap gmap = null;
private CameraPosition camPosition = null;
private final Map events = new HashMap<>();
+ private BitmapDescriptor userIcon;
+
+ private GMapEvent lastClickedEvent;
public GoogleMapsFragment() {
logMethod(TAG, this);
@@ -97,6 +102,14 @@ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
logMethod(TAG, this);
readPreferences();
+
+ MapsInitializer.initialize(getContext());
+ userIcon = BitmapDescriptorFactory.fromBitmap(
+ Bitmap.createScaledBitmap(
+ BitmapFactory.decodeResource(
+ getResources(), R.drawable.user_map_marker_256_256), 150, 150, true));
+
+
EventBus.getDefault().register(this);
Log.d(TAG, "GoogleMapsFragment registered event bus");
@@ -166,7 +179,7 @@ public void onMapReady(GoogleMap googleMap) {
if (lastKnownUserLocation != null) {
// Zoom out to zoom level 10, animating with a duration of 2 seconds.
//gmap.animateCamera(CameraUpdateFactory.zoomTo(10), 5000, null);
- userMarker = gmap.addMarker(getMarkerOptions(lastKnownUserLocation, getContext(), meString));
+ userMarker = gmap.addMarker(createUserMarkerOptions(lastKnownUserLocation));
searchCircle = gmap.addCircle(getCircleOptions(lastKnownUserLocation, searchArea));
} else if (camPosition != null) {
searchCircle = gmap.addCircle(getCircleOptions(camPosition.target, searchArea));
@@ -176,6 +189,7 @@ public void onMapReady(GoogleMap googleMap) {
gmap.setOnMapClickListener((latLng) -> Log.d(TAG, "onMapClickListener() " + latLng));
gmap.setOnCameraIdleListener(this::idleListener);
gmap.setOnMarkerClickListener(this::markerClickListener);
+ gmap.setOnInfoWindowClickListener(this::infoWindowClickListener);
firstOpening = false;
}
@@ -191,7 +205,7 @@ public void onLocationChanged(Location location) {
}
} else {
if (userMarker == null) {
- userMarker = gmap.addMarker(getMarkerOptions(mapToLatTng(location), getContext(), meString));
+ userMarker = gmap.addMarker(createUserMarkerOptions(mapToLatTng(location)));
} else {
userMarker.setPosition(mapToLatTng(location));
}
@@ -220,26 +234,50 @@ private void idleListener() {
}
private boolean markerClickListener(Marker marker) {
- Log.d(TAG, "OnMarkerClickListener() " + marker.getId());
- GMapEvent search = null;
- for (GMapEvent event : events.values()) {
- if (marker.getId().equals(event.getMarkerId())) {
- search = event;
- break;
+ GMapEvent target = searchForEvent(marker);
+ if (target == null) {
+ Log.d(TAG, "OnMarkerClickListener() didn't find the event...");
+ return false;
+ }
+ if (target.equals(lastClickedEvent)) {
+ Log.d(TAG, "Double Click on: " + target.getName());
+ startEventActivityFor(target.getId());
+ return false;
+ }
+ lastClickedEvent = target;
+ Log.d(TAG, "OnMarkerClickListener() find event: " + target.getName()
+ + ", isInfoWindowShown? " + target.isInfoWindowShown());
+ return false;
+ }
+
+ @Nullable
+ private GMapEvent searchForEvent(Marker marker) {
+ for (GMapEvent e : events.values()) {
+ if (marker.getId().equals(e.getMarkerId())) {
+ return e;
}
}
- if (search != null) {
- //start event description activity etc...
- Log.d(TAG, "OnMarkerClickListener() find event " + search.getName());
+ return null;
+ }
+
+ private void infoWindowClickListener(Marker marker) {
+ Log.d(TAG, "infoWindowClickListener() " + marker.getId() + ", is info shown ? " + marker.isInfoWindowShown());
+ GMapEvent gMapEvent = searchForEvent(marker);
+ if (gMapEvent != null) {
+ startEventActivityFor(gMapEvent.getId());
}
- return false;
+ }
+
+ private void startEventActivityFor(String eventId) {
+ startActivity(new Intent(this.getContext(), EventActivity.class)
+ .putExtra(EventActivity.EVENT_ID_KEY, eventId));
}
private void putExistingMarkersOnMap() {
for (GMapEvent e : events.values()) {
e.replaceMarker(
gmap.addMarker(
- createFreshOpts(e.getName(), e.getLatitude(), e.getLongitude())));
+ createEventMarkerOptions(e.getName(), e.getLatitude(), e.getLongitude())));
}
}
@@ -258,7 +296,7 @@ public void onDestroy() {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(IncomeEvents msg) {
Map incomeEvents = new HashMap<>();
- for (EventDTO e : msg.getEvents()) {
+ for (EventDTO e : msg.events()) {
incomeEvents.put(e.getId(), e);
}
@@ -281,7 +319,7 @@ public void onMessageEvent(IncomeEvents msg) {
eId,
new GMapEvent(
ev, gmap.addMarker(
- createFreshOpts(ev.getName(), ev.getLatitude(), ev.getLongitude()))));
+ createEventMarkerOptions(ev.getName(), ev.getLatitude(), ev.getLongitude()))));
}
// Intersection - need to apply events update, if any
@@ -318,43 +356,27 @@ private static void updateWith(GMapEvent me, EventDTO update) {
}
}
- private static MarkerOptions createFreshOpts(String name, double latitude, double longitude) {
+ private MarkerOptions createUserMarkerOptions(LatLng latLng) {
return new MarkerOptions()
+ .icon(userIcon)
+ .title(meString)
+ .position(latLng);
+ }
+
+ private MarkerOptions createEventMarkerOptions(String name, double latitude, double longitude) {
+ //TODO Download event photo
+ Bitmap src = BitmapFactory.decodeResource(getContext().getResources(), randomPicResource());
+ return new MarkerOptions()
+ .position(new LatLng(latitude, longitude))
.title(name)
- .position(new LatLng(latitude, longitude));
+ .icon(BitmapDescriptorFactory.fromBitmap(
+ getCircleBitmap(Bitmap.createScaledBitmap(src, 150, 150, true))));
}
private static LatLng mapToLatTng(Location location) {
return new LatLng(location.getLatitude(), location.getLongitude());
}
- private static BitmapDescriptor getUserIconBitmap(Context context) {
- Bitmap myBitmap = Bitmap.createBitmap(125, 175, Bitmap.Config.ARGB_8888);
- Canvas myCanvas = new Canvas(myBitmap);
- Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setSubpixelText(true);
- paint.setTypeface(FONT_AWESOME.getTypeface(context));
- paint.setStyle(Paint.Style.FILL);
- paint.setColor(Color.BLUE);
- paint.setTextSize(120);
- myCanvas.drawText(
- String.valueOf(FontAwesome.Icon.faw_child.getCharacter()), 20, 90, paint);
-
- //BitmapDescriptorFactory.fromResource(R.drawable.userlocation);
- //BitmapDescriptorFactory.fromAsset(myBitmap);
- //BitmapDescriptorFactory.fromFile(myBitmap);
- //BitmapDescriptorFactory.fromPath(myBitmap);
- return BitmapDescriptorFactory.fromBitmap(myBitmap);
- }
-
- private static MarkerOptions getMarkerOptions(LatLng latLng, Context context, String title) {
- return new MarkerOptions()
- .icon(getUserIconBitmap(context))
- .title(title)
- .position(latLng);
- }
-
private static CircleOptions getCircleOptions(LatLng center, int searchArea) {
return new CircleOptions()
.center(center)
@@ -372,73 +394,6 @@ private static void searchForEvents(double latitude, double longitude, int searc
}
}
- static class GMapEvent {
-
- private EventDTO event;
- private Marker marker;
-
- public GMapEvent(EventDTO event, Marker marker) {
- validate(event, marker);
- this.event = event;
- this.marker = marker;
- }
-
- public void removeMarker() {
- marker.remove();
- }
-
- public String getName() {
- return event.getName();
- }
-
- public double getLatitude() {
- return event.getLatitude();
- }
-
- public double getLongitude() {
- return event.getLongitude();
- }
-
- public String getMarkerId() {
- return marker.getId();
- }
-
- public void updateName(String name) {
- event.setName(name);
- marker.setTitle(name);
- }
-
- public void updatePosition(double latitude, double longitude) {
- event.setLatitude(latitude);
- event.setLongitude(longitude);
- marker.setPosition(new LatLng(latitude, longitude));
- }
-
- public void replaceMarker(Marker marker) {
- validate(event, marker);
- this.marker = marker;
- }
-
- private static void validate(EventDTO event, Marker marker) {
- String name = event.getName();
- String title = marker.getTitle();
- if (!name.equals(title)) {
- throw new IllegalArgumentException("Names are not equals " + name + ":" + title);
- }
- LatLng position = marker.getPosition();
- double latitude = event.getLatitude();
- if (latitude != position.latitude) {
- throw new IllegalArgumentException(
- "Latitudes are not equals " + latitude + ":" + position.latitude);
- }
- double longitude = event.getLongitude();
- if (longitude != position.longitude) {
- throw new IllegalArgumentException(
- "Longitude are not equals " + longitude + ":" + position.longitude);
- }
- }
- }
-
static class EventKey {
private String id;
@@ -489,4 +444,4 @@ public int hashCode() {
return Objects.hash(id, latitude, longitude);
}
}
-}
\ No newline at end of file
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/ProfileFragment.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/ProfileFragment.java
index 831bc7b..6de7f25 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/ProfileFragment.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/ProfileFragment.java
@@ -1,11 +1,13 @@
package com.tom.meeter.context.profile.fragment;
import static com.tom.meeter.context.auth.infrastructure.AuthHelper.peekToken;
+import static com.tom.meeter.infrastructure.common.CommonHelper.genderResolver;
+import static com.tom.meeter.infrastructure.common.DateHelper.getAgeFromDate;
import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
import android.accounts.AccountManager;
+import android.content.Intent;
import android.os.Bundle;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -17,14 +19,12 @@
import com.tom.meeter.App;
import com.tom.meeter.R;
+import com.tom.meeter.context.event.activity.EventActivity;
import com.tom.meeter.context.profile.viewmodel.ProfileViewModel;
+import com.tom.meeter.context.user.GridViewAdapter;
import com.tom.meeter.databinding.FragmentProfileBinding;
import com.tom.meeter.infrastructure.injection.viewmodel.ViewModelFactory;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-
import javax.inject.Inject;
/**
@@ -63,14 +63,6 @@ public View onCreateView(
return binding.getRoot();
}
- private String genderResolver(String gender) {
- return switch (gender.toLowerCase()) {
- case "female" -> getString(R.string.female_gender);
- case "male" -> getString(R.string.male_gender);
- default -> throw new IllegalArgumentException("#args " + gender);
- };
- }
-
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@@ -78,16 +70,28 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
profileViewModel = ViewModelProviders.of(this, viewModelFactory)
.get(ProfileViewModel.class);
profileViewModel.getProfile(peekToken(accountManager), this);
- profileViewModel.getUserLiveData()
- .observe(getViewLifecycleOwner(), user -> {
+ profileViewModel.getProfileLiveData().observe(
+ getViewLifecycleOwner(),
+ user -> {
if (user != null) {
- binding.userId.setText(getString(R.string.profile_user_id, user.getId()));
- binding.userName.setText(getString(R.string.profile_user_name, user.getName(), user.getSurname()));
- binding.userGender.setText(getString(R.string.profile_gender, genderResolver(user.getGender())));
- binding.userAge.setText(getString(R.string.profile_age, getAgeFromDate(user.getBirthday())));
- binding.userInfo.setText(getString(R.string.profile_info, user.getInfo()));
+ binding.profileId.setText(getString(R.string.profile_user_id_format, user.getId()));
+ binding.profileName.setText(getString(R.string.profile_user_name_format, user.getName(), user.getSurname()));
+ binding.profileGender.setText(getString(R.string.profile_gender_format, genderResolver(getContext(), user.getGender())));
+ binding.profileAge.setText(getString(R.string.profile_age_format, getAgeFromDate(user.getBirthday())));
+ binding.profileInfo.setText(getString(R.string.profile_info_format, user.getInfo()));
}
});
+ profileViewModel.getProfileEventsLiveData().observe(
+ getViewLifecycleOwner(),
+ events -> {
+ binding.profileEventsGrid.setAdapter(new GridViewAdapter(getContext(), events));
+ binding.profileEventsGrid.setExpanded(true);
+ binding.profileEventsGrid.setOnItemClickListener(
+ (parent, view1, position, id) ->
+ startActivity(new Intent(getActivity(), EventActivity.class)
+ .putExtra(EventActivity.EVENT_ID_KEY, events.get(position).getId())));
+ }
+ );
}
@Override
@@ -113,27 +117,4 @@ public void onDestroy() {
super.onDestroy();
logMethod(TAG, this);
}
-
- private static String getAgeFromDate(String date) {
- if (date == null) {
- return "";
- }
-
- Calendar dob = Calendar.getInstance();
- Calendar today = Calendar.getInstance();
-
- try {
- dob.setTime(new SimpleDateFormat("yyyy-MM-dd").parse(date));
- } catch (ParseException e) {
- Log.e(TAG, e.getLocalizedMessage(), e);
- }
-
- int age = today.get(Calendar.YEAR) - dob.get(Calendar.YEAR);
-
- if (today.get(Calendar.DAY_OF_YEAR) < dob.get(Calendar.DAY_OF_YEAR)) {
- age--;
- }
-
- return String.valueOf(age);
- }
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/UserEventsFragment.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/UserEventsFragment.java
index 84fe538..4718c19 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/UserEventsFragment.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/fragment/UserEventsFragment.java
@@ -67,7 +67,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
profileEventsViewModel.getProfileEvents(peekToken(accountManager), this);
- adapter = new RecycleViewUserEventsAdapter();
+ adapter = new RecycleViewUserEventsAdapter(getContext());
profileEventsViewModel.getProfileEventsLiveData()
.observe(getViewLifecycleOwner(), ev -> adapter.setData(ev));
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
new file mode 100644
index 0000000..b0f1e1a
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/service/ProfileService.java
@@ -0,0 +1,20 @@
+package com.tom.meeter.context.profile.service;
+
+import static com.tom.meeter.infrastructure.common.Globals.AUTH_HEADER;
+
+import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.profile.user.domain.User;
+
+import java.util.List;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+
+public interface ProfileService {
+ @GET("/profile")
+ Call getProfile(@Header(AUTH_HEADER) String authHeader);
+
+ @GET("/profile/events")
+ Call> getProfileEvents(@Header(AUTH_HEADER) String authHeader);
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/settings/service/SettingsService.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/settings/service/SettingsService.java
index 087d748..a4ea675 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/settings/service/SettingsService.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/settings/service/SettingsService.java
@@ -1,6 +1,6 @@
package com.tom.meeter.context.profile.settings.service;
-import static com.tom.meeter.infrastructure.common.Constants.AUTH_HEADER;
+import static com.tom.meeter.infrastructure.common.Globals.AUTH_HEADER;
import com.tom.meeter.context.profile.settings.message.SettingsCreateOrUpdate;
import com.tom.meeter.context.profile.settings.message.SettingsResponse;
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/user/repository/UserRepository.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/user/repository/UserRepository.java
index 3dc3fb6..4907453 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/user/repository/UserRepository.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/user/repository/UserRepository.java
@@ -1,26 +1,23 @@
package com.tom.meeter.context.profile.user.repository;
-import static com.tom.meeter.infrastructure.common.Constants.getAuthHeader;
-
import android.util.Log;
import androidx.lifecycle.LiveData;
+import com.tom.meeter.AppScope;
import com.tom.meeter.context.profile.user.database.UserDao;
import com.tom.meeter.context.profile.user.domain.User;
-import com.tom.meeter.context.profile.user.service.UserService;
+import com.tom.meeter.context.user.service.UserService;
-import java.io.IOException;
import java.util.concurrent.Executor;
import javax.inject.Inject;
-import javax.inject.Singleton;
import io.reactivex.Completable;
import io.reactivex.Maybe;
import retrofit2.Response;
-@Singleton
+@AppScope
public class UserRepository {
private static final String TAG = UserRepository.class.getCanonicalName();
@@ -56,19 +53,4 @@ private void refreshUser(String id) {
.doOnError(e -> Log.e(TAG, e.getMessage(), e))
.subscribe());
}
-
- private void refreshUserWithHeader(String token) {
- executor.execute(
- () -> {
- Response response = null;
- try {
- response = userService.getProfile(getAuthHeader(token))
- .execute();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- userDao.save(response.body());
- });
- }
-
-}
\ No newline at end of file
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/user/service/UserService.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/user/service/UserService.java
deleted file mode 100644
index 137f8a4..0000000
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/user/service/UserService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.tom.meeter.context.profile.user.service;
-
-import static com.tom.meeter.infrastructure.common.Constants.AUTH_HEADER;
-
-import com.tom.meeter.context.profile.event.domain.Event;
-import com.tom.meeter.context.profile.user.domain.User;
-
-import java.util.List;
-
-import retrofit2.Call;
-import retrofit2.http.GET;
-import retrofit2.http.Header;
-import retrofit2.http.Path;
-
-public interface UserService {
- /**
- * @GET declares an HTTP GET request
- * @Path("user") annotation on the userId parameter marks it as a
- * replacement for the {user} placeholder in the @GET path
- */
- @GET("/user/{id}")
- Call getUser(@Path("id") String userId);
-
- @GET("/profile")
- Call getProfile(@Header(AUTH_HEADER) String authHeader);
-
- @GET("/profile/events")
- Call> getProfileEvents(@Header(AUTH_HEADER) String authHeader);
-}
\ No newline at end of file
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/viewmodel/ProfileEventsViewModel.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/viewmodel/ProfileEventsViewModel.java
index dc18e16..fe1bf13 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/viewmodel/ProfileEventsViewModel.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/viewmodel/ProfileEventsViewModel.java
@@ -9,9 +9,9 @@
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
-import com.tom.meeter.context.profile.event.domain.Event;
-import com.tom.meeter.context.profile.user.service.UserService;
-import com.tom.meeter.infrastructure.common.Constants;
+import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.profile.service.ProfileService;
+import com.tom.meeter.infrastructure.common.Globals;
import com.tom.meeter.infrastructure.http.ActivityRestarterOnAuthFailure;
import com.tom.meeter.infrastructure.http.HttpCodes;
@@ -26,21 +26,21 @@ public class ProfileEventsViewModel extends ViewModel {
private static final String TAG = ProfileEventsViewModel.class.getCanonicalName();
- private final MutableLiveData> profileEventsLiveData = new MutableLiveData<>();
+ private final MutableLiveData> profileEventsLiveData = new MutableLiveData<>();
- private final UserService userService;
+ private final ProfileService profileService;
@Inject
- public ProfileEventsViewModel(UserService userService) {
+ public ProfileEventsViewModel(ProfileService profileService) {
logMethod(TAG, this);
- this.userService = userService;
+ this.profileService = profileService;
}
public void getProfileEvents(String token, Fragment fragment) {
- userService.getProfileEvents(Constants.getAuthHeader(token)).enqueue(
+ profileService.getProfileEvents(Globals.getAuthHeader(token)).enqueue(
new ActivityRestarterOnAuthFailure<>(fragment) {
@Override
- public void onResponse(Call> call, Response> response) {
+ public void onResponse(Call> call, Response> response) {
super.onResponse(call, response);
if (response.code() == HttpCodes.OK && response.body() != null) {
profileEventsLiveData.setValue(response.body());
@@ -58,7 +58,7 @@ protected void onCleared() {
super.onCleared();
}
- public LiveData> getProfileEventsLiveData() {
+ public LiveData> getProfileEventsLiveData() {
return profileEventsLiveData;
}
-}
\ No newline at end of file
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/profile/viewmodel/ProfileViewModel.java b/AndroidClient/src/main/java/com/tom/meeter/context/profile/viewmodel/ProfileViewModel.java
index 1c63e41..ebaf70e 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/context/profile/viewmodel/ProfileViewModel.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/profile/viewmodel/ProfileViewModel.java
@@ -9,12 +9,15 @@
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
+import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.profile.service.ProfileService;
import com.tom.meeter.context.profile.user.domain.User;
-import com.tom.meeter.context.profile.user.service.UserService;
-import com.tom.meeter.infrastructure.common.Constants;
+import com.tom.meeter.infrastructure.common.Globals;
import com.tom.meeter.infrastructure.http.ActivityRestarterOnAuthFailure;
import com.tom.meeter.infrastructure.http.HttpCodes;
+import java.util.List;
+
import javax.inject.Inject;
import retrofit2.Call;
@@ -24,30 +27,44 @@ public class ProfileViewModel extends ViewModel {
private static final String TAG = ProfileViewModel.class.getCanonicalName();
- private final MutableLiveData userLiveData = new MutableLiveData<>();
+ private final MutableLiveData profileLiveData = new MutableLiveData<>();
+ private final MutableLiveData> profileEventsLiveData = new MutableLiveData<>();
- private final UserService userService;
+ private final ProfileService profileService;
@Inject
- public ProfileViewModel(UserService userService) {
+ public ProfileViewModel(ProfileService profileService) {
logMethod(TAG, this);
- this.userService = userService;
+ this.profileService = profileService;
}
public void getProfile(String token, Fragment fragment) {
- userService.getProfile(Constants.getAuthHeader(token)).enqueue(
+ profileService.getProfile(Globals.getAuthHeader(token)).enqueue(
new ActivityRestarterOnAuthFailure<>(fragment) {
@Override
public void onResponse(Call call, Response response) {
super.onResponse(call, response);
if (response.code() == HttpCodes.OK && response.body() != null) {
- userLiveData.setValue(response.body());
+ profileLiveData.setValue(response.body());
return;
}
Log.i(TAG, "/profile: " + response.code() + " : " + response.body());
}
}
);
+ profileService.getProfileEvents(Globals.getAuthHeader(token)).enqueue(
+ new ActivityRestarterOnAuthFailure<>(fragment) {
+ @Override
+ public void onResponse(Call> call, Response> response) {
+ super.onResponse(call, response);
+ if (response.code() == HttpCodes.OK && response.body() != null) {
+ profileEventsLiveData.setValue(response.body());
+ return;
+ }
+ Log.i(TAG, "/profile/events: " + response.code() + " : " + response.body());
+ }
+ }
+ );
}
@Override
@@ -56,8 +73,11 @@ protected void onCleared() {
super.onCleared();
}
- public LiveData getUserLiveData() {
- return userLiveData;
+ public LiveData getProfileLiveData() {
+ return profileLiveData;
}
-}
+ public LiveData> getProfileEventsLiveData() {
+ return profileEventsLiveData;
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/token/TokenComponent.java b/AndroidClient/src/main/java/com/tom/meeter/context/token/TokenComponent.java
new file mode 100644
index 0000000..46f0161
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/token/TokenComponent.java
@@ -0,0 +1,29 @@
+package com.tom.meeter.context.token;
+
+import android.app.Application;
+
+import com.tom.meeter.context.launcher.Launcher;
+import com.tom.meeter.context.token.service.TokenService;
+
+import javax.inject.Singleton;
+
+import dagger.BindsInstance;
+import dagger.Component;
+
+@Singleton
+@Component(modules = {TokenModule.class})
+public interface TokenComponent {
+
+ TokenService providesTokenService();
+
+ @Component.Builder
+ interface Builder {
+ @BindsInstance
+ Builder application(Application application);
+
+ TokenComponent build();
+ }
+
+
+ void inject(Launcher launcher);
+}
\ No newline at end of file
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/token/TokenModule.java b/AndroidClient/src/main/java/com/tom/meeter/context/token/TokenModule.java
new file mode 100644
index 0000000..e3372ba
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/token/TokenModule.java
@@ -0,0 +1,39 @@
+package com.tom.meeter.context.token;
+
+import static com.tom.meeter.infrastructure.common.Globals.getServerPath;
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
+
+import android.app.Application;
+
+import androidx.annotation.NonNull;
+
+import com.tom.meeter.context.token.service.TokenService;
+
+import javax.inject.Singleton;
+
+import dagger.Module;
+import dagger.Provides;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+@Module
+public class TokenModule {
+
+ private static final String TAG = TokenModule.class.getCanonicalName();
+
+ public TokenModule() {
+ logMethod(TAG, this);
+ }
+
+ @Singleton
+ @NonNull
+ @Provides
+ public TokenService providesTokenService(Application app) {
+ return new Retrofit.Builder()
+ .baseUrl(getServerPath(app))
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ .create(TokenService.class);
+ }
+
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/token/service/TokenService.java b/AndroidClient/src/main/java/com/tom/meeter/context/token/service/TokenService.java
new file mode 100644
index 0000000..1d4ac03
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/token/service/TokenService.java
@@ -0,0 +1,16 @@
+package com.tom.meeter.context.token.service;
+
+import static com.tom.meeter.infrastructure.common.Globals.AUTH_HEADER;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+
+/**
+ * Purpose is to check the token and fail auth in case of failed authorization.
+ */
+public interface TokenService {
+ //TODO change GET path to '/check-token' when backend will be done
+ @GET("/profile")
+ Call checkToken(@Header(AUTH_HEADER) String authHeader);
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/user/GridAdapter.java b/AndroidClient/src/main/java/com/tom/meeter/context/user/GridAdapter.java
new file mode 100644
index 0000000..8231a2e
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/GridAdapter.java
@@ -0,0 +1,48 @@
+package com.tom.meeter.context.user;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.ImageView;
+
+public class GridAdapter extends BaseAdapter {
+ private Context mContext;
+ private String[] mThumbIds = {
+ // your image resource IDs here
+ };
+
+ public GridAdapter(Context c) {
+ mContext = c;
+ }
+
+ public int getCount() {
+ return mThumbIds.length;
+ }
+
+ public Object getItem(int position) {
+ return null;
+ }
+
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ // create a new ImageView for each item referenced by the Adapter
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ImageView imageView;
+ if (convertView == null) {
+ // if it's not recycled, initialize some attributes
+ imageView = new ImageView(mContext);
+ imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
+ imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ imageView.setPadding(8, 8, 8, 8);
+ } else {
+ imageView = (ImageView) convertView;
+ }
+
+ imageView.setImageResource(Integer.parseInt(mThumbIds[position])); // Replace with your image loading logic
+ return imageView;
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/user/GridViewAdapter.java b/AndroidClient/src/main/java/com/tom/meeter/context/user/GridViewAdapter.java
new file mode 100644
index 0000000..9e87a37
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/GridViewAdapter.java
@@ -0,0 +1,56 @@
+package com.tom.meeter.context.user;
+
+import static com.tom.meeter.infrastructure.Image.ImagesHelper.getCircleBitmap;
+import static com.tom.meeter.infrastructure.Image.ImagesHelper.randomPicResource;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.tom.meeter.R;
+import com.tom.meeter.context.network.dto.EventDTO;
+
+import java.util.List;
+
+public class GridViewAdapter extends ArrayAdapter {
+
+ private final Context ctx;
+
+ public GridViewAdapter(Context context, List list) {
+ super(context, 0, list);
+ ctx = context;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+
+ View itemView = convertView;
+ if (itemView == null) {
+ itemView = LayoutInflater.from(getContext())
+ .inflate(R.layout.card_item, parent, false);
+ }
+
+ EventDTO event = getItem(position);
+
+ TextView textView = itemView.findViewById(R.id.text_view);
+ ImageView imageView = itemView.findViewById(R.id.image_view);
+
+ if (event != null) {
+ textView.setText(event.getName());
+
+ Bitmap src = BitmapFactory.decodeResource(ctx.getResources(), randomPicResource());
+ Bitmap scaled = Bitmap.createScaledBitmap(src, 150, 150, true);
+ Bitmap circled = getCircleBitmap(scaled);
+
+ imageView.setImageBitmap(circled);
+ }
+
+ return itemView;
+ }
+}
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
new file mode 100644
index 0000000..b790775
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/activity/UserActivity.java
@@ -0,0 +1,111 @@
+package com.tom.meeter.context.user.activity;
+
+import static com.tom.meeter.context.auth.infrastructure.AuthHelper.checkToken;
+import static com.tom.meeter.infrastructure.common.CommonHelper.genderResolver;
+import static com.tom.meeter.infrastructure.common.DateHelper.getAgeFromDate;
+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;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.lifecycle.ViewModelProviders;
+
+import com.tom.meeter.App;
+import com.tom.meeter.R;
+import com.tom.meeter.context.event.activity.EventActivity;
+import com.tom.meeter.context.token.service.TokenService;
+import com.tom.meeter.context.user.GridViewAdapter;
+import com.tom.meeter.context.user.viewmodel.UserViewModel;
+import com.tom.meeter.databinding.UserLayoutBinding;
+import com.tom.meeter.infrastructure.injection.viewmodel.ViewModelFactory;
+
+import javax.inject.Inject;
+
+public class UserActivity extends AppCompatActivity {
+ private static final String TAG = UserActivity.class.getCanonicalName();
+ public static final String USER_ID_KEY = "user_id";
+ UserLayoutBinding binding;
+ @Inject
+ TokenService tokenService;
+ @Inject
+ ViewModelFactory viewModelFactory;
+ private UserViewModel userViewModel;
+ private String userId;
+ private AccountManager accountManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(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(USER_ID_KEY);
+ if (userId == null) {
+ Log.d(TAG, "Unable to create user activity without 'user_id' provided.");
+ finish();
+ return;
+ }
+
+ ((App) getApplication()).getComponent().inject(this);
+ accountManager = AccountManager.get(this);
+
+ //setToken(accountManager, Launcher.EXPIRED);
+ checkToken(this::onInit, this::finish, accountManager, this, tokenService);
+ }
+
+ private void onInit(String token) {
+ binding = UserLayoutBinding.inflate(getLayoutInflater());
+ View view = binding.getRoot();
+ setContentView(view);
+
+ userViewModel = ViewModelProviders.of(this, viewModelFactory)
+ .get(UserViewModel.class);
+ userViewModel.fetchUserInformation(token, userId, this);
+ userViewModel.getUserLiveData()
+ .observe(this, user -> {
+ if (user != null) {
+ binding.userFormat.setText(getString(
+ R.string.user_format, user.getName(), user.getSurname(),
+ getAgeFromDate(user.getBirthday()),
+ genderResolver(this, user.getGender())));
+ binding.userInfo.setText(user.getInfo());
+ }
+ });
+ userViewModel.getUserEventsLiveData()
+ .observe(this, events -> {
+ if (events != null && !events.isEmpty()) {
+ //GridAdapter adapter = new GridAdapter(this);
+ //binding.userEventsGrid.setAdapter(adapter);
+
+ GridViewAdapter adapter = new GridViewAdapter(this, events);
+ binding.userEventsGrid.setAdapter(adapter);
+ binding.userEventsGrid.setExpanded(true);
+ binding.userEventsGrid.setOnItemClickListener(
+ (parent, view1, position, id) ->
+ startActivity(new Intent(UserActivity.this, EventActivity.class).putExtra(EventActivity.EVENT_ID_KEY, events.get(position).getId())));
+ }
+ });
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(
+ @Nullable View parent, @NonNull String name, @NonNull Context ctx,
+ @NonNull AttributeSet attrs) {
+ return super.onCreateView(parent, name, ctx, attrs);
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/context/user/service/UserService.java b/AndroidClient/src/main/java/com/tom/meeter/context/user/service/UserService.java
new file mode 100644
index 0000000..9d68982
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/service/UserService.java
@@ -0,0 +1,26 @@
+package com.tom.meeter.context.user.service;
+
+import static com.tom.meeter.infrastructure.common.Globals.AUTH_HEADER;
+
+import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.profile.user.domain.User;
+
+import java.util.List;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Header;
+import retrofit2.http.Path;
+
+public interface UserService {
+ //This will not even work, since server needs an auth for this requests.
+ @GET("/user/{id}")
+ @Deprecated
+ Call getUser(@Path("id") String userId);
+
+ @GET("/user/{id}")
+ Call getUser(@Header(AUTH_HEADER) String authHeader, @Path("id") String userId);
+
+ @GET("/user/{id}/events")
+ Call> getUserEvents(@Header(AUTH_HEADER) String authHeader, @Path("id") String userId);
+}
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
new file mode 100644
index 0000000..bf4279c
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/context/user/viewmodel/UserViewModel.java
@@ -0,0 +1,89 @@
+package com.tom.meeter.context.user.viewmodel;
+
+import static com.tom.meeter.infrastructure.common.InfrastructureHelper.logMethod;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+import com.tom.meeter.context.network.dto.EventDTO;
+import com.tom.meeter.context.profile.user.domain.User;
+import com.tom.meeter.context.user.service.UserService;
+import com.tom.meeter.infrastructure.common.Globals;
+import com.tom.meeter.infrastructure.http.DisconnectLogger;
+import com.tom.meeter.infrastructure.http.HttpCodes;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import retrofit2.Call;
+import retrofit2.Response;
+
+public class UserViewModel extends ViewModel {
+
+ private static final String TAG = UserViewModel.class.getCanonicalName();
+
+ private final MutableLiveData userLiveData = new MutableLiveData<>();
+ private final MutableLiveData> userEventsLiveData = new MutableLiveData<>();
+
+ private final UserService userService;
+
+ @Inject
+ public UserViewModel(UserService userService) {
+ logMethod(TAG, this);
+ this.userService = userService;
+ }
+
+ public void fetchUserInformation(String token, String userId, Activity activity) {
+ userService.getUser(Globals.getAuthHeader(token), userId).enqueue(
+ new DisconnectLogger<>(activity) {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.code() == HttpCodes.OK && response.body() != null) {
+ userLiveData.setValue(response.body());
+ return;
+ }
+ if (response.code() == HttpCodes.NOT_AUTHENTICATED) {
+ activity.recreate();
+ }
+ Log.i(TAG, "/user/{id}: " + response.code() + " : " + response.body());
+ }
+ }
+ );
+
+ userService.getUserEvents(Globals.getAuthHeader(token), userId).enqueue(
+ new DisconnectLogger<>(activity) {
+ @Override
+ public void onResponse(Call> call, Response> response) {
+ if (response.code() == HttpCodes.OK && response.body() != null) {
+ userEventsLiveData.setValue(response.body());
+ return;
+ }
+ if (response.code() == HttpCodes.NOT_AUTHENTICATED) {
+ activity.recreate();
+ }
+ Log.i(TAG, "/user/{id}/events: " + response.code() + " : " + response.body());
+ }
+ }
+ );
+ }
+
+ @Override
+ protected void onCleared() {
+ logMethod(TAG, this);
+ super.onCleared();
+ }
+
+ public LiveData getUserLiveData() {
+ return userLiveData;
+ }
+
+ public LiveData> getUserEventsLiveData() {
+ return userEventsLiveData;
+ }
+}
+
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/Image/ImagesHelper.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/Image/ImagesHelper.java
new file mode 100644
index 0000000..0328a4b
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/Image/ImagesHelper.java
@@ -0,0 +1,131 @@
+package com.tom.meeter.infrastructure.Image;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.widget.ImageView;
+
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.model.AdvancedMarkerOptions;
+import com.google.android.gms.maps.model.BitmapDescriptor;
+import com.google.android.gms.maps.model.BitmapDescriptorFactory;
+import com.google.android.gms.maps.model.LatLng;
+import com.mikepenz.fontawesome_typeface_library.FontAwesome;
+import com.tom.meeter.R;
+
+import java.util.Random;
+
+public class ImagesHelper {
+
+ private static final FontAwesome FONT_AWESOME = new FontAwesome();
+
+ public static Bitmap getCircleBitmap(Bitmap bitmap) {
+ final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
+ bitmap.getHeight(), Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(output);
+
+ final int color = 0xff424242;
+ final Paint paint = new Paint();
+ final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ final RectF rectF = new RectF(rect);
+
+ paint.setAntiAlias(true);
+ canvas.drawARGB(0, 0, 0, 0);
+ paint.setColor(color);
+ canvas.drawOval(rectF, paint);
+
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+ canvas.drawBitmap(bitmap, rect, rect, paint);
+
+ bitmap.recycle();
+
+ return output;
+ }
+
+ public static int randomPicResource() {
+ int min = 1; // Minimum value of the range
+ int max = 12; // Maximum value of the range
+
+ Random random = new Random();
+ int randomNumber = random.nextInt(max - min + 1) + min;
+ return getImageIndexBased(randomNumber);
+ }
+
+ private static int getImageIndexBased(int index) {
+ return switch (index) {
+ case 1 -> R.drawable.random_1;
+ case 2 -> R.drawable.random_2;
+ case 3 -> R.drawable.random_3;
+ case 4 -> R.drawable.random_4;
+ case 5 -> R.drawable.random_5;
+ case 6 -> R.drawable.random_6;
+ case 7 -> R.drawable.random_7;
+ case 8 -> R.drawable.random_8;
+ case 9 -> R.drawable.random_9;
+ case 10 -> R.drawable.random_10;
+ case 11 -> R.drawable.random_11;
+ case 12 -> R.drawable.random_12;
+ default -> R.drawable.random_1;
+ };
+ }
+
+ public static BitmapDescriptor getUserIconBitmap(Context context) {
+ Bitmap myBitmap = Bitmap.createBitmap(125, 175, Bitmap.Config.ARGB_8888);
+ Canvas myCanvas = new Canvas(myBitmap);
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setSubpixelText(true);
+ paint.setTypeface(FONT_AWESOME.getTypeface(context));
+ paint.setStyle(Paint.Style.FILL);
+ paint.setColor(Color.BLUE);
+ paint.setTextSize(120);
+ myCanvas.drawText(
+ String.valueOf(FontAwesome.Icon.faw_child.getCharacter()), 20, 90, paint);
+
+ //BitmapDescriptorFactory.fromResource(R.drawable.userlocation);
+ //BitmapDescriptorFactory.fromAsset(myBitmap);
+ //BitmapDescriptorFactory.fromFile(myBitmap);
+ //BitmapDescriptorFactory.fromPath(myBitmap);
+ return BitmapDescriptorFactory.fromBitmap(myBitmap);
+ }
+
+ private void bbb(Context ctx, int imageId) {
+ //PART 1
+ //Required: imageId, for example R.drawable.your_image
+ Bitmap bitmap = BitmapFactory.decodeResource(ctx.getResources(), imageId);
+ RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(ctx.getResources(), bitmap);
+ drawable.setCircular(true); // Make it a circle
+ Bitmap circularBitmap = drawable.getBitmap();
+ BitmapDescriptor icon = BitmapDescriptorFactory.fromBitmap(circularBitmap);
+ /*---------------------------------------------------------------------------------------*/
+ //PART 2
+ //Required:
+ GoogleMap map = null;
+ LatLng latLng = null;
+ Bitmap yourBitmap = null;
+
+ ImageView imageView = new ImageView(ctx);
+ imageView.setImageBitmap(yourBitmap);
+ // Or, set a rounded background using a Drawable
+ RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(
+ ctx.getResources(), yourBitmap);
+ roundedDrawable.setCircular(true);
+ imageView.setBackground(roundedDrawable);
+
+ AdvancedMarkerOptions markerOptions = new AdvancedMarkerOptions()
+ .position(latLng)
+ .iconView(imageView);
+ map.addMarker(markerOptions);
+ /*---------------------------------------------------------------------------------------*/
+ }
+}
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
new file mode 100644
index 0000000..103582c
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/CommonHelper.java
@@ -0,0 +1,18 @@
+package com.tom.meeter.infrastructure.common;
+
+import android.content.Context;
+
+import com.tom.meeter.R;
+
+public final class CommonHelper {
+ private CommonHelper() {
+ }
+
+ public static String genderResolver(Context ctx, String gender) {
+ return switch (gender.toLowerCase()) {
+ case "female" -> ctx.getString(R.string.female_gender);
+ case "male" -> ctx.getString(R.string.male_gender);
+ default -> throw new IllegalArgumentException("#args " + gender);
+ };
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/Constants.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/Constants.java
deleted file mode 100644
index 6b364fe..0000000
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/Constants.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.tom.meeter.infrastructure.common;
-
-import android.content.Context;
-
-import java.io.IOException;
-import java.util.Properties;
-
-/**
- * Some well knows application constants.
- */
-public class Constants {
-
- private Constants() {
- throw new UnsupportedOperationException("Prevent initialization");
- }
-
- public static final String APP_PROPERTIES = "app.properties";
-
- public static final String SERVER_IP_PROPERTY = "server.ip";
- public static final String SERVER_PORT_PROPERTY = "server.port";
- public static final String SERVER_IO_PORT_PROPERTY = "server.io_port";
-
- public static final String LOCATION_DISTANCE_PROPERTY = "location.distance";
- public static final String LOCATION_TIME_PROPERTY = "location.time";
- public static final String MAP_EVENTS_AREA_PROPERTY = "map.events_area";
- public static final String MAP_TRACK_USER_PROPERTY = "map.track_user";
-
- public static final String AUTH_HEADER = "Authorization";
- public static final String BEARER_FORMAT = "Bearer %s";
- public static final String TOKEN_KEY = "token";
-
-
- public static String initServerPath(Context context) throws IOException {
- Properties p = new Properties();
- p.load(context.getAssets().open(APP_PROPERTIES));
- return "http://"
- + p.getProperty(SERVER_IP_PROPERTY)
- + ":"
- + Integer.valueOf(p.getProperty(SERVER_PORT_PROPERTY));
- }
-
- public static String initSocketIOPath(Context context) throws IOException {
- Properties p = new Properties();
- p.load(context.getAssets().open(APP_PROPERTIES));
- return "ws://"
- + p.getProperty(SERVER_IP_PROPERTY)
- + ":"
- + Integer.valueOf(p.getProperty(SERVER_IO_PORT_PROPERTY));
- }
-
- public static String getAuthHeader(String token) {
- return String.format(BEARER_FORMAT, token);
- }
-}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/DateHelper.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/DateHelper.java
new file mode 100644
index 0000000..cbe066b
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/DateHelper.java
@@ -0,0 +1,39 @@
+package com.tom.meeter.infrastructure.common;
+
+import android.util.Log;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+public final class DateHelper {
+ private static final String TAG = DateHelper.class.getCanonicalName();
+ private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+
+ private DateHelper() {
+ }
+
+ public static String getAgeFromDate(String date) {
+ if (date == null) {
+ return "";
+ }
+
+ Calendar dob = Calendar.getInstance();
+ Calendar today = Calendar.getInstance();
+
+ try {
+ dob.setTime(FORMAT.parse(date));
+ } catch (ParseException e) {
+ Log.e(TAG, e.getLocalizedMessage(), e);
+ return null;
+ }
+
+ int age = today.get(Calendar.YEAR) - dob.get(Calendar.YEAR);
+
+ if (today.get(Calendar.DAY_OF_YEAR) < dob.get(Calendar.DAY_OF_YEAR)) {
+ age--;
+ }
+
+ return String.valueOf(age);
+ }
+}
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
new file mode 100644
index 0000000..158b117
--- /dev/null
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/Globals.java
@@ -0,0 +1,101 @@
+package com.tom.meeter.infrastructure.common;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * Some well knows application constants.
+ */
+public class Globals {
+
+ private static final String TAG = Globals.class.getCanonicalName();
+
+ private Globals() {
+ throw new UnsupportedOperationException("Prevent initialization");
+ }
+
+ public static final String APP_PROPERTIES = "app.properties";
+
+ public static final String SERVER_IP_PROPERTY = "server.ip";
+ public static final String SERVER_PORT_PROPERTY = "server.port";
+ public static final String SERVER_PROTO_PROPERTY = "server.proto";
+ public static final String SERVER_IO_PORT_PROPERTY = "server.io_port";
+ public static final String SERVER_IO_PROTO_PROPERTY = "server.io_proto";
+
+ public static final String LOCATION_DISTANCE_PROPERTY = "location.distance";
+ public static final String LOCATION_TIME_PROPERTY = "location.time";
+ public static final String MAP_EVENTS_AREA_PROPERTY = "map.events_area";
+ public static final String MAP_TRACK_USER_PROPERTY = "map.track_user";
+
+ public static final String AUTH_HEADER = "Authorization";
+ public static final String BEARER_FORMAT = "Bearer %s";
+ public static final String TOKEN_KEY = "token";
+
+ private static String serverPath;
+ private static String socketIOPath;
+ private static Boolean needTrackUserDefault;
+ private static Integer searchAreaDefault;
+
+
+ public static String getServerPath(Context ctx) {
+ if (serverPath != null) {
+ return serverPath;
+ }
+ Properties p = tryGetProps(ctx);
+ serverPath = p.getProperty(SERVER_PROTO_PROPERTY) + "://"
+ + p.getProperty(SERVER_IP_PROPERTY)
+ + ":"
+ + Integer.valueOf(p.getProperty(SERVER_PORT_PROPERTY));
+ Log.d(TAG, "Server URL is [" + serverPath + "].");
+ return serverPath;
+ }
+
+ public static String getSocketIOPath(Context ctx) {
+ if (socketIOPath != null) {
+ return socketIOPath;
+ }
+ Properties p = tryGetProps(ctx);
+ socketIOPath = p.getProperty(SERVER_IO_PROTO_PROPERTY) + "://"
+ + p.getProperty(SERVER_IP_PROPERTY)
+ + ":"
+ + Integer.valueOf(p.getProperty(SERVER_IO_PORT_PROPERTY));
+ Log.d(TAG, "SocketIO path is [" + socketIOPath + "].");
+ return socketIOPath;
+ }
+
+ public static String getAuthHeader(String token) {
+ return String.format(BEARER_FORMAT, token);
+ }
+
+ public static boolean getDefaultTrackUser(Context ctx) {
+ if (needTrackUserDefault != null) {
+ return needTrackUserDefault;
+ }
+ needTrackUserDefault = Boolean.parseBoolean(
+ tryGetProps(ctx).getProperty(MAP_TRACK_USER_PROPERTY));
+ return needTrackUserDefault;
+ }
+
+ public static int getDefaultSearchArea(Context ctx) {
+ if (searchAreaDefault != null) {
+ return searchAreaDefault;
+ }
+ searchAreaDefault = Integer.parseInt(
+ tryGetProps(ctx).getProperty(MAP_EVENTS_AREA_PROPERTY));
+ return searchAreaDefault;
+ }
+
+ private static Properties tryGetProps(Context ctx) {
+ Properties p = new Properties();
+ try {
+ p.load(ctx.getAssets().open(APP_PROPERTIES));
+ } catch (IOException e) {
+ Log.e(TAG, "tryGetProps failed with: ", e);
+ throw new RuntimeException("Unable to init get properties: " + e);
+ }
+ return p;
+ }
+}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/InfrastructureHelper.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/InfrastructureHelper.java
index 898f3ac..0f9b3b0 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/InfrastructureHelper.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/InfrastructureHelper.java
@@ -3,6 +3,7 @@
import android.app.Activity;
import android.content.Intent;
import android.os.Handler;
+import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
@@ -49,7 +50,7 @@ private static String getCurrentMethodName() {
}
public static void recreateActivityFromFragment(Fragment me) {
- new Handler().post(
+ new Handler(Looper.getMainLooper()).post(
() -> {
FragmentActivity activity = me.getActivity();
activity.getSupportFragmentManager()
@@ -61,7 +62,7 @@ public static void recreateActivityFromFragment(Fragment me) {
}
public static void restartActivityFromFragment(Fragment me) {
- new Handler().post(
+ new Handler(Looper.getMainLooper()).post(
() -> {
FragmentActivity activity = me.getActivity();
Intent intent = activity.getIntent();
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/PreferencesHelper.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/PreferencesHelper.java
index 329c3fa..e5657bd 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/PreferencesHelper.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/common/PreferencesHelper.java
@@ -1,68 +1,28 @@
package com.tom.meeter.infrastructure.common;
import static androidx.preference.PreferenceManager.getDefaultSharedPreferences;
-import static com.tom.meeter.infrastructure.common.Constants.APP_PROPERTIES;
-import static com.tom.meeter.infrastructure.common.Constants.MAP_EVENTS_AREA_PROPERTY;
-import static com.tom.meeter.infrastructure.common.Constants.MAP_TRACK_USER_PROPERTY;
+import static com.tom.meeter.infrastructure.common.Globals.getDefaultSearchArea;
+import static com.tom.meeter.infrastructure.common.Globals.getDefaultTrackUser;
import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
import com.tom.meeter.R;
-import java.io.IOException;
-import java.util.Properties;
-
public class PreferencesHelper {
- private static final String TAG = PreferencesHelper.class.getCanonicalName();
-
- private static Boolean needTrackUserDefault;
-
- private static Integer searchAreaDefault;
public static boolean isDefaulted(Context ctx) {
return (getNeedTrackUser(ctx) == getDefaultTrackUser(ctx))
&& (getSearchArea(ctx) == getDefaultSearchArea(ctx));
}
public static boolean getNeedTrackUser(Context ctx) {
- return getDefaultSharedPreferences(ctx).getBoolean(
- ctx.getString(R.string.prefs_need_track_user), getDefaultTrackUser(ctx));
+ return getDefaultSharedPreferences(ctx)
+ .getBoolean(ctx.getString(R.string.prefs_need_track_user), getDefaultTrackUser(ctx));
}
public static int getSearchArea(Context ctx) {
- SharedPreferences prefs = getDefaultSharedPreferences(ctx);
- return prefs.getInt(
- ctx.getString(R.string.prefs_search_area), getDefaultSearchArea(ctx));
- }
-
- private static boolean getDefaultTrackUser(Context ctx) {
- if (needTrackUserDefault != null) {
- return needTrackUserDefault;
- }
- needTrackUserDefault = Boolean.parseBoolean(
- tryGetProps(ctx).getProperty(MAP_TRACK_USER_PROPERTY));
- return needTrackUserDefault;
- }
-
- private static int getDefaultSearchArea(Context ctx) {
- if (searchAreaDefault != null) {
- return searchAreaDefault;
- }
- searchAreaDefault = Integer.parseInt(
- tryGetProps(ctx).getProperty(MAP_EVENTS_AREA_PROPERTY));
- return searchAreaDefault;
- }
-
- private static Properties tryGetProps(Context ctx) {
- Properties p = new Properties();
- try {
- p.load(ctx.getAssets().open(APP_PROPERTIES));
- } catch (IOException e) {
- Log.e(TAG, e.getLocalizedMessage(), e);
- }
- return p;
+ return getDefaultSharedPreferences(ctx)
+ .getInt(ctx.getString(R.string.prefs_search_area), getDefaultSearchArea(ctx));
}
private PreferencesHelper() {
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/eventbus/events/IncomeEvents.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/eventbus/events/IncomeEvents.java
index b7645cb..3046db8 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/eventbus/events/IncomeEvents.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/eventbus/events/IncomeEvents.java
@@ -1,9 +1,10 @@
package com.tom.meeter.infrastructure.eventbus.events;
+import androidx.annotation.NonNull;
+
import com.tom.meeter.context.network.dto.EventDTO;
import org.json.JSONArray;
-import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
@@ -12,26 +13,16 @@
/**
* Created by Tom on 14.01.2017.
*/
-
-public class IncomeEvents {
-
- private final List events = new ArrayList<>();
-
- public List getEvents() {
- return events;
- }
-
- public IncomeEvents(JSONArray jsonArray) {
- for (int i = 0; i < jsonArray.length(); i++) {
- try {
- events.add(EventDTO.encode((JSONObject) jsonArray.get(i)));
- } catch (JSONException e) {
- e.printStackTrace();
- }
+public record IncomeEvents(List events) {
+ public static IncomeEvents fromJsonArray(JSONArray msg) {
+ List events = new ArrayList<>();
+ for (int i = 0; i < msg.length(); i++) {
+ events.add(EventDTO.encode((JSONObject) msg.opt(i)));
}
+ return new IncomeEvents(events);
}
- @Override
+ @NonNull
public String toString() {
return events.toString();
}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/http/AuthInvalidatorOnAuthFail.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/http/AuthInvalidatorOnAuthFail.java
deleted file mode 100644
index 013e064..0000000
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/http/AuthInvalidatorOnAuthFail.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.tom.meeter.infrastructure.http;
-
-import static com.tom.meeter.context.auth.infrastructure.AccountAuthenticator.ACCOUNT_TYPE;
-import static com.tom.meeter.context.auth.infrastructure.AccountAuthenticator.AUTH_TYPE;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.tom.meeter.R;
-import com.tom.meeter.context.auth.infrastructure.AuthHelper;
-
-import java.io.IOException;
-import java.util.function.Consumer;
-
-import retrofit2.Call;
-import retrofit2.Response;
-
-public class AuthInvalidatorOnAuthFail extends DisconnectLogger {
- private static final String TAG = AuthInvalidatorOnAuthFail.class.getCanonicalName();
- private final AccountManager accountManager;
- private final Activity activity;
- private final Consumer afterTokenSetup;
- private final Runnable onCancelledAuth;
-
- public AuthInvalidatorOnAuthFail(
- Activity activity, AccountManager accountManager,
- Consumer afterTokenSetup, Runnable onCancelledAuth) {
- super(activity.getApplicationContext());
- this.activity = activity;
- this.accountManager = accountManager;
- this.afterTokenSetup = afterTokenSetup;
- this.onCancelledAuth = onCancelledAuth;
- }
-
- @Override
- public void onResponse(Call call, Response response) {
- if (response.code() == HttpCodes.NOT_AUTHENTICATED) {
- Account[] accounts = accountManager.getAccountsByType(ACCOUNT_TYPE);
- if (accounts.length != 1) {
- throw AuthHelper.freshNotImplementedError();
- }
- Account account = accounts[0];
- String token = accountManager.peekAuthToken(account, AUTH_TYPE);
- Toast.makeText(activity.getApplicationContext(),
- R.string.refreshing_the_token, Toast.LENGTH_SHORT)
- .show();
- Log.i(TAG, "AuthInvalidatorOnAuthFail for: " +
- activity.getComponentName() + " : "
- + activity.getResources().getString(R.string.refreshing_the_token));
- accountManager.invalidateAuthToken(ACCOUNT_TYPE, token);
- accountManager.getAuthToken(
- account, AUTH_TYPE, null, activity,
- future -> {
- Bundle result;
- try {
- result = future.getResult();
- } catch (AuthenticatorException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new RuntimeException(e);
- } catch (OperationCanceledException e) {
- onCancelledAuth.run();
- return;
- }
- afterTokenSetup.accept(result.getString(AccountManager.KEY_AUTHTOKEN));
- }, null);
- }
- }
-}
diff --git a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/injection/viewmodel/ViewModelModule.java b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/injection/viewmodel/ViewModelModule.java
index f86513e..3080e89 100644
--- a/AndroidClient/src/main/java/com/tom/meeter/infrastructure/injection/viewmodel/ViewModelModule.java
+++ b/AndroidClient/src/main/java/com/tom/meeter/infrastructure/injection/viewmodel/ViewModelModule.java
@@ -1,11 +1,15 @@
package com.tom.meeter.infrastructure.injection.viewmodel;
+import android.util.Log;
+
import androidx.lifecycle.ViewModel;
+import com.tom.meeter.context.event.viewmodel.EventViewModel;
import com.tom.meeter.context.profile.viewmodel.ProfileEventsViewModel;
import com.tom.meeter.context.profile.viewmodel.ProfileViewModel;
import com.tom.meeter.context.profile.viewmodel.UserEventsViewModel;
import com.tom.meeter.context.profile.viewmodel.UserProfileViewModel;
+import com.tom.meeter.context.user.viewmodel.UserViewModel;
import dagger.Binds;
import dagger.Module;
@@ -14,6 +18,12 @@
@Module
public abstract class ViewModelModule {
+ private static final String TAG = ViewModelModule.class.getCanonicalName();
+
+ public ViewModelModule() {
+ Log.d(TAG, "Configuring ViewModelModule...");
+ }
+
@Binds
@IntoMap
@ViewModelKey(UserProfileViewModel.class)
@@ -22,7 +32,7 @@ public abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(UserEventsViewModel.class)
- abstract ViewModel eventViewModel(UserEventsViewModel userEventsViewModel);
+ abstract ViewModel userEventViewModel(UserEventsViewModel userEventsViewModel);
@Binds
@IntoMap
@@ -34,4 +44,14 @@ public abstract class ViewModelModule {
@ViewModelKey(ProfileEventsViewModel.class)
abstract ViewModel profileEventsViewModel(ProfileEventsViewModel profileEventsViewModel);
+ @Binds
+ @IntoMap
+ @ViewModelKey(UserViewModel.class)
+ abstract ViewModel userViewModel(UserViewModel userViewModel);
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(EventViewModel.class)
+ abstract ViewModel eventViewModel(EventViewModel eventViewModel);
+
}
diff --git a/AndroidClient/src/main/res/drawable/event_512_512.png b/AndroidClient/src/main/res/drawable/event_512_512.png
new file mode 100644
index 0000000..858b705
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/event_512_512.png differ
diff --git a/AndroidClient/src/main/res/drawable/random_1.jpg b/AndroidClient/src/main/res/drawable/random_1.jpg
new file mode 100644
index 0000000..5013fb9
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_1.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/random_10.jpg b/AndroidClient/src/main/res/drawable/random_10.jpg
new file mode 100644
index 0000000..0de88a4
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_10.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/random_11.jpg b/AndroidClient/src/main/res/drawable/random_11.jpg
new file mode 100644
index 0000000..fe53f29
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_11.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/random_12.png b/AndroidClient/src/main/res/drawable/random_12.png
new file mode 100644
index 0000000..6c097c9
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_12.png differ
diff --git a/AndroidClient/src/main/res/drawable/random_2.jpg b/AndroidClient/src/main/res/drawable/random_2.jpg
new file mode 100644
index 0000000..479a629
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_2.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/random_3.jpg b/AndroidClient/src/main/res/drawable/random_3.jpg
new file mode 100644
index 0000000..996c67f
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_3.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/random_4.jpg b/AndroidClient/src/main/res/drawable/random_4.jpg
new file mode 100644
index 0000000..0aae7fc
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_4.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/random_5.jpg b/AndroidClient/src/main/res/drawable/random_5.jpg
new file mode 100644
index 0000000..0092b57
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_5.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/random_6.jpg b/AndroidClient/src/main/res/drawable/random_6.jpg
new file mode 100644
index 0000000..beadfc3
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_6.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/random_7.jpg b/AndroidClient/src/main/res/drawable/random_7.jpg
new file mode 100644
index 0000000..edfd497
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_7.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/random_8.jpg b/AndroidClient/src/main/res/drawable/random_8.jpg
new file mode 100644
index 0000000..6ffe654
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_8.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/random_9.jpg b/AndroidClient/src/main/res/drawable/random_9.jpg
new file mode 100644
index 0000000..fe242df
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/random_9.jpg differ
diff --git a/AndroidClient/src/main/res/drawable/user_map_marker_256_256.png b/AndroidClient/src/main/res/drawable/user_map_marker_256_256.png
new file mode 100644
index 0000000..9bbf9e3
Binary files /dev/null and b/AndroidClient/src/main/res/drawable/user_map_marker_256_256.png differ
diff --git a/AndroidClient/src/main/res/layout/card_item.xml b/AndroidClient/src/main/res/layout/card_item.xml
new file mode 100644
index 0000000..3fa147a
--- /dev/null
+++ b/AndroidClient/src/main/res/layout/card_item.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AndroidClient/src/main/res/layout/event_layout.xml b/AndroidClient/src/main/res/layout/event_layout.xml
new file mode 100644
index 0000000..bdf5edf
--- /dev/null
+++ b/AndroidClient/src/main/res/layout/event_layout.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+ />
+
+
+
+
+
+
+
+
diff --git a/AndroidClient/src/main/res/layout/event_view.xml b/AndroidClient/src/main/res/layout/event_view.xml
index 6d717fa..346ff62 100644
--- a/AndroidClient/src/main/res/layout/event_view.xml
+++ b/AndroidClient/src/main/res/layout/event_view.xml
@@ -15,7 +15,7 @@
android:padding="13dp">
@@ -36,7 +36,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/event_name_card_view"
- android:layout_toRightOf="@+id/person_photo" />
+ android:layout_toRightOf="@+id/event_photo_card_view" />
diff --git a/AndroidClient/src/main/res/layout/fragment_profile.xml b/AndroidClient/src/main/res/layout/fragment_profile.xml
index 23a3082..bddc852 100644
--- a/AndroidClient/src/main/res/layout/fragment_profile.xml
+++ b/AndroidClient/src/main/res/layout/fragment_profile.xml
@@ -2,6 +2,7 @@
+
+
diff --git a/AndroidClient/src/main/res/layout/user_layout.xml b/AndroidClient/src/main/res/layout/user_layout.xml
new file mode 100644
index 0000000..5e38cf4
--- /dev/null
+++ b/AndroidClient/src/main/res/layout/user_layout.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+ />
+
+
+
+
+
+
+
+
\ 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 ab274d6..c3708de 100644
--- a/AndroidClient/src/main/res/values-en/strings.xml
+++ b/AndroidClient/src/main/res/values-en/strings.xml
@@ -42,11 +42,19 @@
Today
Other
Current
- ID: %1$s
- User: %1$s %2$s
- Age: %1$s
- Gender: %1$s
- Information: %1$s
+ %1$s %2$s, %3$s, %4$s
+ About: %1$s
+ About:
+ ID:
+ User:
+ Age:
+ Gender:
+ Information:
+ ID: %1$s
+ User: %1$s %2$s
+ Age: %1$s
+ Gender: %1$s
+ Information: %1$s
Camera
Gallery
Male
@@ -152,6 +160,8 @@
title_copyable_preference
Settings
Refreshing the token.
+ Event information.
+ Creator
- 360p
diff --git a/AndroidClient/src/main/res/values-ru-rRU/strings.xml b/AndroidClient/src/main/res/values-ru-rRU/strings.xml
index fbc4a80..b617c75 100644
--- a/AndroidClient/src/main/res/values-ru-rRU/strings.xml
+++ b/AndroidClient/src/main/res/values-ru-rRU/strings.xml
@@ -42,11 +42,19 @@
Залогиниться
Имя
Ниж. нав бар
- Идентификатор: %1$s
- Пользователь: %1$s %2$s
- Возраст: %1$s
- Пол: %1$s
- О себе: %1$s
+ %1$s %2$s, %3$s, %4$s
+ О себе: %1$s
+ О себе:
+ Идентификатор:
+ Пользователь:
+ Возраст:
+ Пол:
+ О себе:
+ Идентификатор: %1$s
+ Пользователь: %1$s %2$s
+ Возраст: %1$s
+ Пол: %1$s
+ О себе: %1$s
Камера
Галерея
Мужчина
@@ -151,6 +159,8 @@
title_toggle_summary_preference
summary_copyable_preference
title_copyable_preference
+ Информация о событии.
+ Создатель
- 360p
diff --git a/AndroidClient/src/main/res/values/colors.xml b/AndroidClient/src/main/res/values/colors.xml
index 8cffac0..deadada 100644
--- a/AndroidClient/src/main/res/values/colors.xml
+++ b/AndroidClient/src/main/res/values/colors.xml
@@ -8,4 +8,5 @@
#cdd4d9
#c8e8ff
#b1c0ca
+ #C0DEEF
diff --git a/AndroidClient/src/main/res/values/strings.xml b/AndroidClient/src/main/res/values/strings.xml
index 02f4cd0..1ad63e6 100644
--- a/AndroidClient/src/main/res/values/strings.xml
+++ b/AndroidClient/src/main/res/values/strings.xml
@@ -1,4 +1,5 @@
+ Meeter
Settings
Meeter
Login
@@ -40,12 +41,19 @@
Other
Simple bot nav bar
Login
- Meeter
- ID: %1$s
- User: %1$s %2$s.
- Age: %1$s
- Gender: %1$s
- Information: %1$s
+ %1$s %2$s, %3$s, %4$s
+ About: %1$s
+ About:
+ ID:
+ User:
+ Age:
+ Gender:
+ Information:
+ ID: %1$s
+ User: %1$s %2$s.
+ Age: %1$s
+ Gender: %1$s
+ Information: %1$s
Camera
Gallery
Male
@@ -150,6 +158,8 @@
summary_copyable_preference
title_copyable_preference
Refreshing the token.
+ Event information.
+ Creator
- 360p