improve/all #162
|
@ -4,6 +4,8 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
@ -23,6 +25,7 @@ import androidx.navigation.fragment.NavHostFragment;
|
||||||
import androidx.navigation.ui.NavigationUI;
|
import androidx.navigation.ui.NavigationUI;
|
||||||
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
|
import com.google.android.material.chip.Chip;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.android.material.divider.MaterialDivider;
|
import com.google.android.material.divider.MaterialDivider;
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
@ -31,8 +34,12 @@ import com.google.android.material.navigation.NavigationView;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint;
|
import dagger.hilt.android.AndroidEntryPoint;
|
||||||
|
import one.nem.kidshift.data.ChildData;
|
||||||
|
import one.nem.kidshift.data.ParentData;
|
||||||
import one.nem.kidshift.data.UserSettings;
|
import one.nem.kidshift.data.UserSettings;
|
||||||
import one.nem.kidshift.feature.child.ChildManageMainActivity;
|
import one.nem.kidshift.feature.child.ChildManageMainActivity;
|
||||||
|
import one.nem.kidshift.model.ParentModel;
|
||||||
|
import one.nem.kidshift.model.callback.ParentModelCallback;
|
||||||
import one.nem.kidshift.utils.FabManager;
|
import one.nem.kidshift.utils.FabManager;
|
||||||
import one.nem.kidshift.utils.FeatureFlag;
|
import one.nem.kidshift.utils.FeatureFlag;
|
||||||
import one.nem.kidshift.utils.KSLogger;
|
import one.nem.kidshift.utils.KSLogger;
|
||||||
|
@ -52,6 +59,11 @@ public class MainActivity extends AppCompatActivity {
|
||||||
FeatureFlag featureFlag;
|
FeatureFlag featureFlag;
|
||||||
@Inject
|
@Inject
|
||||||
UserSettings userSettings;
|
UserSettings userSettings;
|
||||||
|
@Inject
|
||||||
|
ParentData parentData;
|
||||||
|
@Inject
|
||||||
|
ChildData childData;
|
||||||
|
|
||||||
|
|
||||||
private KSLogger logger;
|
private KSLogger logger;
|
||||||
private FloatingActionButton fab;
|
private FloatingActionButton fab;
|
||||||
|
@ -101,6 +113,9 @@ public class MainActivity extends AppCompatActivity {
|
||||||
} else if (item.getItemId() == R.id.show_debug_dialog) {
|
} else if (item.getItemId() == R.id.show_debug_dialog) {
|
||||||
showDebugDialog();
|
showDebugDialog();
|
||||||
return true;
|
return true;
|
||||||
|
} else if (item.getItemId() == R.id.show_account_dialog) {
|
||||||
|
showAccountDialog();
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
logger.warn("不明なアイテム: " + item.getItemId());
|
logger.warn("不明なアイテム: " + item.getItemId());
|
||||||
}
|
}
|
||||||
|
@ -158,6 +173,61 @@ public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showAccountDialog() {
|
||||||
|
boolean isEditMode = false;
|
||||||
|
View view = getLayoutInflater().inflate(R.layout.user_info_dialog_layout, null);
|
||||||
|
if (userSettings.getAppCommonSetting().isChildMode()) {
|
||||||
|
((TextView) view.findViewById(R.id.userNameTextView)).setText(
|
||||||
|
childData.getChild(userSettings.getAppCommonSetting().getChildId()).join().getName());
|
||||||
|
((TextView) view.findViewById(R.id.emailTextView)).setText("子供モードはメールアドレスを設定できません");
|
||||||
|
((Chip) view.findViewById(R.id.chip)).setText("子供/Child");
|
||||||
|
} else {
|
||||||
|
parentData.getParentDirect().thenAccept(parentModel -> {
|
||||||
|
((TextView) view.findViewById(R.id.userNameTextView)).setText(parentModel.getName());
|
||||||
|
logger.debug("ParentModel: " + parentModel.getName() + ", " + parentModel.getEmail());
|
||||||
|
((TextView) view.findViewById(R.id.emailTextView)).setText(parentModel.getEmail());
|
||||||
|
((Chip) view.findViewById(R.id.chip)).setText("保護者/Parent");
|
||||||
|
}).join();
|
||||||
|
}
|
||||||
|
|
||||||
|
view.findViewById(R.id.userNameEditButton).setOnClickListener(v -> {
|
||||||
|
EditText editText = new EditText(this);
|
||||||
|
editText.setText(((TextView) view.findViewById(R.id.userNameTextView)).getText());
|
||||||
|
editText.setHint("ユーザー名");
|
||||||
|
new MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle("ユーザー名の変更")
|
||||||
|
.setView(editText)
|
||||||
|
.setPositiveButton("OK", (dialog, which) -> {
|
||||||
|
((TextView) view.findViewById(R.id.userNameTextView)).setText(editText.getText());
|
||||||
|
if (userSettings.getAppCommonSetting().isChildMode()) {
|
||||||
|
// 子供モード
|
||||||
|
childData.getChild(userSettings.getAppCommonSetting().getChildId()).thenAccept(childModel -> {
|
||||||
|
childModel.setName(editText.getText().toString());
|
||||||
|
childData.updateChild(childModel);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 保護者モード
|
||||||
|
parentData.getParentDirect().thenAccept(parentModel -> {
|
||||||
|
parentModel.setName(editText.getText().toString());
|
||||||
|
parentData.updateParent(parentModel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton("キャンセル", (dialog, which) -> {
|
||||||
|
// Do nothing
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
new MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle("アカウント情報")
|
||||||
|
.setView(view)
|
||||||
|
.setPositiveButton("OK", (dialog, which) -> {
|
||||||
|
// Do nothing
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
private void showDebugDialog() {
|
private void showDebugDialog() {
|
||||||
|
|
||||||
ScrollView scrollView = new ScrollView(this);
|
ScrollView scrollView = new ScrollView(this);
|
||||||
|
|
|
@ -2,19 +2,15 @@
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/colorSecondary"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="16dp"
|
android:padding="16dp">
|
||||||
android:background="?attr/colorPrimaryDark">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@drawable/ic_launcher_foreground" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Header Title"
|
android:layout_marginTop="48dp"
|
||||||
|
android:text="KidShift"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="20sp" />
|
android:textSize="34sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
52
app/src/main/res/layout/user_info_dialog_layout.xml
Normal file
52
app/src/main/res/layout/user_info_dialog_layout.xml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_margin="32dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/userNameTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="UNAME_PHOLDER"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/userNameEditButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:padding="24px"
|
||||||
|
app:srcCompat="@drawable/edit_24px" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/emailTextView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="huga@example.com" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="保護者" />
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,5 +1,10 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/show_account_dialog"
|
||||||
|
android:icon="@drawable/account_box_24px"
|
||||||
|
android:title="ユーザー情報" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/manage_child_account"
|
android:id="@+id/manage_child_account"
|
||||||
android:icon="@drawable/manage_accounts_24px"
|
android:icon="@drawable/manage_accounts_24px"
|
||||||
|
|
|
@ -14,10 +14,22 @@ public interface ParentData {
|
||||||
*/
|
*/
|
||||||
CompletableFuture<ParentModel> getParent(ParentModelCallback callback);
|
CompletableFuture<ParentModel> getParent(ParentModelCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 親ユーザー情報取得
|
||||||
|
* @return 親ユーザー情報
|
||||||
|
*/
|
||||||
|
CompletableFuture<ParentModel> getParentDirect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 親ユーザー情報取得
|
||||||
|
* @return 親ユーザー情報
|
||||||
|
*/
|
||||||
|
CompletableFuture<ParentModel> getParentCache();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 親ユーザー情報更新
|
* 親ユーザー情報更新
|
||||||
* @param parent 親ユーザー情報
|
* @param parent 親ユーザー情報
|
||||||
*/
|
*/
|
||||||
void updateParent(ParentModel parent);
|
CompletableFuture<Void> updateParent(ParentModel parent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,21 +8,26 @@ import one.nem.kidshift.data.KSActions;
|
||||||
import one.nem.kidshift.data.ParentData;
|
import one.nem.kidshift.data.ParentData;
|
||||||
import one.nem.kidshift.data.UserSettings;
|
import one.nem.kidshift.data.UserSettings;
|
||||||
import one.nem.kidshift.data.retrofit.KidShiftApiService;
|
import one.nem.kidshift.data.retrofit.KidShiftApiService;
|
||||||
|
import one.nem.kidshift.data.retrofit.model.parent.ParentInfoResponse;
|
||||||
|
import one.nem.kidshift.data.retrofit.model.parent.ParentRenameRequest;
|
||||||
import one.nem.kidshift.model.ParentModel;
|
import one.nem.kidshift.model.ParentModel;
|
||||||
import one.nem.kidshift.model.callback.ParentModelCallback;
|
import one.nem.kidshift.model.callback.ParentModelCallback;
|
||||||
import one.nem.kidshift.utils.KSLogger;
|
import one.nem.kidshift.utils.KSLogger;
|
||||||
import one.nem.kidshift.utils.factory.KSLoggerFactory;
|
import one.nem.kidshift.utils.factory.KSLoggerFactory;
|
||||||
|
import retrofit2.Call;
|
||||||
|
|
||||||
public class ParentDataImpl implements ParentData {
|
public class ParentDataImpl implements ParentData {
|
||||||
|
|
||||||
private final UserSettings userSettings;
|
private final UserSettings userSettings;
|
||||||
|
private final KidShiftApiService kidShiftApiService;
|
||||||
|
|
||||||
private final KSLogger logger;
|
private final KSLogger logger;
|
||||||
|
|
||||||
private final KSActions ksActions;
|
private final KSActions ksActions;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ParentDataImpl(KidShiftApiService kidshiftApiService, UserSettings userSettings, KSLoggerFactory ksLoggerFactory, KSActions ksActions) {
|
public ParentDataImpl(KidShiftApiService kidShiftApiService, UserSettings userSettings, KSLoggerFactory ksLoggerFactory, KSActions ksActions) {
|
||||||
|
this.kidShiftApiService = kidShiftApiService;
|
||||||
this.userSettings = userSettings;
|
this.userSettings = userSettings;
|
||||||
this.logger = ksLoggerFactory.create("ParentDataImpl");
|
this.logger = ksLoggerFactory.create("ParentDataImpl");
|
||||||
this.ksActions = ksActions;
|
this.ksActions = ksActions;
|
||||||
|
@ -46,8 +51,27 @@ public class ParentDataImpl implements ParentData {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateParent(ParentModel parent) {
|
public CompletableFuture<ParentModel> getParentDirect() {
|
||||||
|
return ksActions.syncParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<ParentModel> getParentCache() {
|
||||||
|
return CompletableFuture.supplyAsync(() -> userSettings.getCache().getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Void> updateParent(ParentModel parent) {
|
||||||
|
Call<ParentInfoResponse> call = kidShiftApiService.renameParent(new ParentRenameRequest(parent.getName()));
|
||||||
|
try {
|
||||||
|
ParentInfoResponse response = call.execute().body();
|
||||||
|
if (response == null) {
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@ import dagger.Binds;
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.hilt.InstallIn;
|
import dagger.hilt.InstallIn;
|
||||||
import dagger.hilt.android.components.FragmentComponent;
|
import dagger.hilt.android.components.FragmentComponent;
|
||||||
|
import dagger.hilt.components.SingletonComponent;
|
||||||
import one.nem.kidshift.data.ParentData;
|
import one.nem.kidshift.data.ParentData;
|
||||||
import one.nem.kidshift.data.impl.ParentDataImpl;
|
import one.nem.kidshift.data.impl.ParentDataImpl;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(FragmentComponent.class)
|
@InstallIn(SingletonComponent.class)
|
||||||
public abstract class ParentDataModule {
|
public abstract class ParentDataModule {
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
|
|
|
@ -8,6 +8,7 @@ import one.nem.kidshift.data.retrofit.model.child.ChildResponse;
|
||||||
import one.nem.kidshift.data.retrofit.model.child.auth.ChildAuthRequest;
|
import one.nem.kidshift.data.retrofit.model.child.auth.ChildAuthRequest;
|
||||||
import one.nem.kidshift.data.retrofit.model.child.auth.ChildAuthResponse;
|
import one.nem.kidshift.data.retrofit.model.child.auth.ChildAuthResponse;
|
||||||
import one.nem.kidshift.data.retrofit.model.parent.ParentInfoResponse;
|
import one.nem.kidshift.data.retrofit.model.parent.ParentInfoResponse;
|
||||||
|
import one.nem.kidshift.data.retrofit.model.parent.ParentRenameRequest;
|
||||||
import one.nem.kidshift.data.retrofit.model.parent.auth.ParentAuthRequest;
|
import one.nem.kidshift.data.retrofit.model.parent.auth.ParentAuthRequest;
|
||||||
import one.nem.kidshift.data.retrofit.model.parent.auth.ParentAuthResponse;
|
import one.nem.kidshift.data.retrofit.model.parent.auth.ParentAuthResponse;
|
||||||
import one.nem.kidshift.data.retrofit.model.task.HistoryListResponse;
|
import one.nem.kidshift.data.retrofit.model.task.HistoryListResponse;
|
||||||
|
@ -45,6 +46,15 @@ public interface KidShiftApiService {
|
||||||
@POST("/parent/auth/register")
|
@POST("/parent/auth/register")
|
||||||
Call<ParentAuthResponse> parentRegister(@Body ParentAuthRequest request);
|
Call<ParentAuthResponse> parentRegister(@Body ParentAuthRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保護者情報更新処理
|
||||||
|
* @param request ParentRenameRequest
|
||||||
|
* @return ParentInfoResponse
|
||||||
|
*/
|
||||||
|
@PUT("/parent/account")
|
||||||
|
@Headers(AuthorizationInterceptor.HEADER_PLACEHOLDER)
|
||||||
|
Call<ParentInfoResponse> renameParent(@Body ParentRenameRequest request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 子供ログイン処理
|
* 子供ログイン処理
|
||||||
* @param request ChildAuthRequest
|
* @param request ChildAuthRequest
|
||||||
|
|
|
@ -11,7 +11,7 @@ public class ParentModelConverter {
|
||||||
* @return ParentModel
|
* @return ParentModel
|
||||||
*/
|
*/
|
||||||
public static ParentModel parentInfoResponseToParentModel(ParentInfoResponse parentInfoResponse) {
|
public static ParentModel parentInfoResponseToParentModel(ParentInfoResponse parentInfoResponse) {
|
||||||
return new ParentModel(parentInfoResponse.getId(), parentInfoResponse.getDisplayName(), parentInfoResponse.getEmail());
|
return new ParentModel(parentInfoResponse.getId(), parentInfoResponse.getDisplay_name(), parentInfoResponse.getEmail());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,18 +4,18 @@ public class ParentInfoResponse {
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private String email;
|
private String email;
|
||||||
private String displayName;
|
private String display_name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* コンストラクタ (全プロパティ)
|
* コンストラクタ (全プロパティ)
|
||||||
* @param id 親ID
|
* @param id 親ID
|
||||||
* @param email メールアドレス
|
* @param email メールアドレス
|
||||||
* @param displayName 表示名
|
* @param display_name 表示名
|
||||||
*/
|
*/
|
||||||
public ParentInfoResponse(String id, String email, String displayName) {
|
public ParentInfoResponse(String id, String email, String display_name) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.displayName = displayName;
|
this.display_name = display_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
|
@ -26,8 +26,8 @@ public class ParentInfoResponse {
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDisplayName() {
|
public String getDisplay_name() {
|
||||||
return displayName;
|
return display_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(String id) {
|
public void setId(String id) {
|
||||||
|
@ -38,7 +38,7 @@ public class ParentInfoResponse {
|
||||||
this.email = email;
|
this.email = email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisplayName(String displayName) {
|
public void setDisplay_name(String display_name) {
|
||||||
this.displayName = displayName;
|
this.display_name = display_name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package one.nem.kidshift.data.retrofit.model.parent;
|
||||||
|
|
||||||
|
public class ParentRenameRequest {
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* コンストラクタ (全プロパティ)
|
||||||
|
* @param displayName 表示名
|
||||||
|
*/
|
||||||
|
public ParentRenameRequest(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.core.view.MenuHost;
|
import androidx.core.view.MenuHost;
|
||||||
import androidx.core.view.MenuProvider;
|
import androidx.core.view.MenuProvider;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.lifecycle.Lifecycle;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
|
@ -21,6 +22,7 @@ import android.view.ViewGroup;
|
||||||
import android.view.animation.Animation;
|
import android.view.animation.Animation;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
@ -79,6 +81,7 @@ public class CommonHomeFragment extends Fragment {
|
||||||
private KSLogger logger;
|
private KSLogger logger;
|
||||||
|
|
||||||
CompactCalendarView compactCalendarView;
|
CompactCalendarView compactCalendarView;
|
||||||
|
View calendarContainer;
|
||||||
SwipeRefreshLayout swipeRefreshLayout;
|
SwipeRefreshLayout swipeRefreshLayout;
|
||||||
TaskListItemAdapter taskListItemAdapter;
|
TaskListItemAdapter taskListItemAdapter;
|
||||||
TextView calendarTitleTextView;
|
TextView calendarTitleTextView;
|
||||||
|
@ -139,6 +142,7 @@ public class CommonHomeFragment extends Fragment {
|
||||||
RecyclerView taskListRecyclerView = view.findViewById(R.id.taskListRecyclerView);
|
RecyclerView taskListRecyclerView = view.findViewById(R.id.taskListRecyclerView);
|
||||||
taskListRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
taskListRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
taskListRecyclerView.setAdapter(taskListItemAdapter);
|
taskListRecyclerView.setAdapter(taskListItemAdapter);
|
||||||
|
taskListRecyclerView.setItemViewCacheSize(10);
|
||||||
recyclerViewAnimUtils.setSlideUpAnimation(taskListRecyclerView);
|
recyclerViewAnimUtils.setSlideUpAnimation(taskListRecyclerView);
|
||||||
|
|
||||||
swipeRefreshLayout = view.findViewById(R.id.swipeRefreshLayout);
|
swipeRefreshLayout = view.findViewById(R.id.swipeRefreshLayout);
|
||||||
|
@ -147,63 +151,7 @@ public class CommonHomeFragment extends Fragment {
|
||||||
calendarTitleTextView = view.findViewById(R.id.calendarTitleTextView);
|
calendarTitleTextView = view.findViewById(R.id.calendarTitleTextView);
|
||||||
calendarPrevButton = view.findViewById(R.id.calendarPrevButton);
|
calendarPrevButton = view.findViewById(R.id.calendarPrevButton);
|
||||||
calendarNextButton = view.findViewById(R.id.calendarNextButton);
|
calendarNextButton = view.findViewById(R.id.calendarNextButton);
|
||||||
|
calendarContainer = view.findViewById(R.id.calendarContainer);
|
||||||
initCalender();
|
|
||||||
|
|
||||||
MenuHost menuHost = requireActivity();
|
|
||||||
menuHost.addMenuProvider(new MenuProvider() {
|
|
||||||
@Override
|
|
||||||
public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {
|
|
||||||
menu.clear();
|
|
||||||
menuInflater.inflate(R.menu.common_home_toolbar_menu, menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemSelected(@NonNull MenuItem menuItem) {
|
|
||||||
if (menuItem.getItemId() == R.id.toggle_calendar) {
|
|
||||||
View calendarContainer = view.findViewById(R.id.calendarContainer);
|
|
||||||
if (calendarContainer.getVisibility() == View.VISIBLE) {
|
|
||||||
Animation slideUp = AnimationUtils.loadAnimation(getContext(), one.nem.kidshift.shared.R.anim.slide_up);
|
|
||||||
calendarContainer.startAnimation(slideUp);
|
|
||||||
slideUp.setAnimationListener(new Animation.AnimationListener() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationStart(Animation animation) {
|
|
||||||
recyclerViewRefresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animation animation) {
|
|
||||||
calendarContainer.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationRepeat(Animation animation) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Animation slideDown = AnimationUtils.loadAnimation(getContext(), one.nem.kidshift.shared.R.anim.slide_down);
|
|
||||||
calendarContainer.startAnimation(slideDown);
|
|
||||||
slideDown.setAnimationListener(new Animation.AnimationListener() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationStart(Animation animation) {
|
|
||||||
calendarContainer.setVisibility(View.VISIBLE);
|
|
||||||
recyclerViewRefresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animation animation) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationRepeat(Animation animation) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
initCalender();
|
initCalender();
|
||||||
updateData();
|
updateData();
|
||||||
|
@ -261,10 +209,68 @@ public class CommonHomeFragment extends Fragment {
|
||||||
|
|
||||||
private void setupToolBar() {
|
private void setupToolBar() {
|
||||||
if (isChildMode) {
|
if (isChildMode) {
|
||||||
toolBarManager.setTitle("タスク一覧");
|
toolBarManager.setTitle("ホーム");
|
||||||
|
toolBarManager.setSubtitle("子供ビュー");
|
||||||
} else {
|
} else {
|
||||||
toolBarManager.setTitle("ホーム");
|
toolBarManager.setTitle("ホーム");
|
||||||
|
toolBarManager.setSubtitle("保護者ビュー");
|
||||||
}
|
}
|
||||||
|
MenuHost menuHost = requireActivity();
|
||||||
|
|
||||||
|
menuHost.invalidateMenu();
|
||||||
|
menuHost.addMenuProvider(new MenuProvider() {
|
||||||
|
@Override
|
||||||
|
public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {
|
||||||
|
logger.debug("onCreateMenu, インフレート");
|
||||||
|
menu.clear();
|
||||||
|
menuInflater.inflate(R.menu.common_home_toolbar_menu, menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemSelected(@NonNull MenuItem menuItem) {
|
||||||
|
if (menuItem.getItemId() == R.id.toggle_calendar) {
|
||||||
|
if (calendarContainer.getVisibility() == View.VISIBLE) {
|
||||||
|
Animation slideUp = AnimationUtils.loadAnimation(getContext(), one.nem.kidshift.shared.R.anim.slide_up);
|
||||||
|
calendarContainer.startAnimation(slideUp);
|
||||||
|
slideUp.setAnimationListener(new Animation.AnimationListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animation animation) {
|
||||||
|
recyclerViewRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animation animation) {
|
||||||
|
calendarContainer.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animation animation) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Animation slideDown = AnimationUtils.loadAnimation(getContext(), one.nem.kidshift.shared.R.anim.slide_down);
|
||||||
|
calendarContainer.startAnimation(slideDown);
|
||||||
|
slideDown.setAnimationListener(new Animation.AnimationListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animation animation) {
|
||||||
|
calendarContainer.setVisibility(View.VISIBLE);
|
||||||
|
recyclerViewRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animation animation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animation animation) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}, this.getViewLifecycleOwner(), Lifecycle.State.RESUMED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -344,9 +350,11 @@ public class CommonHomeFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}).thenAccept(taskItemModel -> {
|
}).thenAccept(taskItemModel -> {
|
||||||
requireActivity().runOnUiThread(() -> {
|
requireActivity().runOnUiThread(() -> {
|
||||||
taskListItemAdapter.notifyItemRangeRemoved(0, taskListItemAdapter.getItemCount());
|
// taskListItemAdapter.notifyItemRangeRemoved(0, taskListItemAdapter.getItemCount());
|
||||||
|
// taskListItemAdapter.setTaskItemModelList(taskItemModel);
|
||||||
|
// taskListItemAdapter.notifyItemRangeInserted(0, taskItemModel.size());
|
||||||
taskListItemAdapter.setTaskItemModelList(taskItemModel);
|
taskListItemAdapter.setTaskItemModelList(taskItemModel);
|
||||||
taskListItemAdapter.notifyItemRangeInserted(0, taskItemModel.size());
|
taskListItemAdapter.notifyItemRangeChanged(0, taskItemModel.size());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -399,9 +407,13 @@ public class CommonHomeFragment extends Fragment {
|
||||||
* データを更新 (updateTaskInfoとupdateCalenderを並列実行)
|
* データを更新 (updateTaskInfoとupdateCalenderを並列実行)
|
||||||
*/
|
*/
|
||||||
private void updateData() {
|
private void updateData() {
|
||||||
swipeRefreshLayout.setRefreshing(true);
|
requireActivity().runOnUiThread(() -> {
|
||||||
|
swipeRefreshLayout.setRefreshing(true);
|
||||||
|
});
|
||||||
CompletableFuture.allOf(updateTaskInfo(), updateCalender()).thenRun(() -> {
|
CompletableFuture.allOf(updateTaskInfo(), updateCalender()).thenRun(() -> {
|
||||||
swipeRefreshLayout.setRefreshing(false);
|
requireActivity().runOnUiThread(() -> {
|
||||||
|
swipeRefreshLayout.setRefreshing(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,10 +421,21 @@ public class CommonHomeFragment extends Fragment {
|
||||||
* タスク追加ダイアログを表示
|
* タスク追加ダイアログを表示
|
||||||
*/
|
*/
|
||||||
private void showAddTaskDialog() {
|
private void showAddTaskDialog() {
|
||||||
|
View view = getLayoutInflater().inflate(R.layout.common_task_add_dialog_layout, null);
|
||||||
|
view.setPadding(48, 24, 48, 24);
|
||||||
new MaterialAlertDialogBuilder(requireContext())
|
new MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle("Placeholder")
|
.setTitle("タスクを追加")
|
||||||
.setMessage("Placeholder")
|
.setView(view)
|
||||||
.setPositiveButton("OK", (dialog, which) -> dialog.dismiss())
|
.setPositiveButton("追加", (dialog, which) -> {
|
||||||
|
EditText taskNameEditText = view.findViewById(R.id.addTaskNameEditText);
|
||||||
|
EditText taskRewardEditText = view.findViewById(R.id.addTaskRewardEditText);
|
||||||
|
TaskItemModel taskItemModel = new TaskItemModel();
|
||||||
|
taskItemModel.setName(taskNameEditText.getText().toString());
|
||||||
|
taskItemModel.setReward(Integer.parseInt(taskRewardEditText.getText().toString()));
|
||||||
|
taskData.addTask(taskItemModel).thenRun(this::updateData);
|
||||||
|
})
|
||||||
|
.setNegativeButton("キャンセル", (dialog, which) -> dialog.dismiss())
|
||||||
.show();
|
.show();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import one.nem.kidshift.feature.common.adapter.SelectShowChildListItemAdapter;
|
||||||
import one.nem.kidshift.utils.FabManager;
|
import one.nem.kidshift.utils.FabManager;
|
||||||
import one.nem.kidshift.utils.KSLogger;
|
import one.nem.kidshift.utils.KSLogger;
|
||||||
import one.nem.kidshift.utils.RecyclerViewAnimUtils;
|
import one.nem.kidshift.utils.RecyclerViewAnimUtils;
|
||||||
|
import one.nem.kidshift.utils.ToolBarManager;
|
||||||
import one.nem.kidshift.utils.factory.KSLoggerFactory;
|
import one.nem.kidshift.utils.factory.KSLoggerFactory;
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
|
@ -34,6 +35,8 @@ public class CommonSelectChildFragment extends Fragment {
|
||||||
@Inject
|
@Inject
|
||||||
FabManager fabManager;
|
FabManager fabManager;
|
||||||
@Inject
|
@Inject
|
||||||
|
ToolBarManager toolBarManager;
|
||||||
|
@Inject
|
||||||
RecyclerViewAnimUtils recyclerViewAnimUtils;
|
RecyclerViewAnimUtils recyclerViewAnimUtils;
|
||||||
private KSLogger logger;
|
private KSLogger logger;
|
||||||
|
|
||||||
|
@ -80,6 +83,8 @@ public class CommonSelectChildFragment extends Fragment {
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
fabManager.hide();
|
fabManager.hide();
|
||||||
|
toolBarManager.setTitle("子供選択");
|
||||||
|
toolBarManager.setSubtitle(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="0dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/addTaskNameTextInputLayout"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="タスク名"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/addTaskNameEditText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/addTaskRewardTextInputLayout"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:hint="金額"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/addTaskNameTextInputLayout">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/addTaskRewardEditText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="number" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -21,6 +21,10 @@
|
||||||
<argument
|
<argument
|
||||||
android:name="childId"
|
android:name="childId"
|
||||||
app:argType="string" />
|
app:argType="string" />
|
||||||
|
<argument
|
||||||
|
android:name="isChildMode"
|
||||||
|
app:argType="boolean"
|
||||||
|
android:defaultValue="true" />
|
||||||
</action>
|
</action>
|
||||||
</fragment>
|
</fragment>
|
||||||
</navigation>
|
</navigation>
|
|
@ -14,6 +14,7 @@ import one.nem.kidshift.data.RewardData;
|
||||||
import one.nem.kidshift.data.UserSettings;
|
import one.nem.kidshift.data.UserSettings;
|
||||||
import one.nem.kidshift.utils.FabManager;
|
import one.nem.kidshift.utils.FabManager;
|
||||||
import one.nem.kidshift.utils.KSLogger;
|
import one.nem.kidshift.utils.KSLogger;
|
||||||
|
import one.nem.kidshift.utils.ToolBarManager;
|
||||||
import one.nem.kidshift.utils.factory.KSLoggerFactory;
|
import one.nem.kidshift.utils.factory.KSLoggerFactory;
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
|
@ -27,6 +28,8 @@ public class WalletContentFragment extends Fragment {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
FabManager fabManager;
|
FabManager fabManager;
|
||||||
|
@Inject
|
||||||
|
ToolBarManager toolBarManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
UserSettings userSettings;
|
UserSettings userSettings;
|
||||||
|
@ -100,5 +103,7 @@ public class WalletContentFragment extends Fragment {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
updateTotalReward();
|
updateTotalReward();
|
||||||
fabManager.hide();
|
fabManager.hide();
|
||||||
|
toolBarManager.setTitle("ウォレット");
|
||||||
|
toolBarManager.setSubtitle(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,9 @@ import dagger.hilt.android.AndroidEntryPoint;
|
||||||
import one.nem.kidshift.data.ChildData;
|
import one.nem.kidshift.data.ChildData;
|
||||||
import one.nem.kidshift.data.RewardData;
|
import one.nem.kidshift.data.RewardData;
|
||||||
import one.nem.kidshift.model.ChildModel;
|
import one.nem.kidshift.model.ChildModel;
|
||||||
|
import one.nem.kidshift.utils.FabManager;
|
||||||
import one.nem.kidshift.utils.KSLogger;
|
import one.nem.kidshift.utils.KSLogger;
|
||||||
|
import one.nem.kidshift.utils.ToolBarManager;
|
||||||
import one.nem.kidshift.utils.factory.KSLoggerFactory;
|
import one.nem.kidshift.utils.factory.KSLoggerFactory;
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
|
@ -42,6 +44,10 @@ public class WalletParentWrapperFragment extends Fragment {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
RewardData rewardData;
|
RewardData rewardData;
|
||||||
|
@Inject
|
||||||
|
FabManager fabManager;
|
||||||
|
@Inject
|
||||||
|
ToolBarManager toolBarManager;
|
||||||
|
|
||||||
private TabLayout tabLayout;
|
private TabLayout tabLayout;
|
||||||
private ViewPager2 viewPager;
|
private ViewPager2 viewPager;
|
||||||
|
@ -104,4 +110,12 @@ public class WalletParentWrapperFragment extends Fragment {
|
||||||
return childList == null ? 0 : childList.size();
|
return childList == null ? 0 : childList.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
fabManager.hide();
|
||||||
|
toolBarManager.setTitle("ウォレット");
|
||||||
|
toolBarManager.setSubtitle(null);
|
||||||
|
}
|
||||||
}
|
}
|
10
shared/src/main/res/drawable/edit_24px.xml
Normal file
10
shared/src/main/res/drawable/edit_24px.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M200,760L257,760L648,369L591,312L200,703L200,760ZM120,840L120,670L648,143Q660,132 674.5,126Q689,120 705,120Q721,120 736,126Q751,132 762,144L817,200Q829,211 834.5,226Q840,241 840,256Q840,272 834.5,286.5Q829,301 817,313L290,840L120,840ZM760,256L760,256L704,200L704,200L760,256ZM619,341L591,312L591,312L648,369L648,369L619,341Z"/>
|
||||||
|
</vector>
|
Loading…
Reference in New Issue
Block a user