Merge branch 'main' into feature/updateupdate

This commit is contained in:
Fujimatsu 2024-07-06 02:11:09 +00:00
commit bb1196a26a
21 changed files with 474 additions and 156 deletions

View File

@ -35,6 +35,7 @@ dependencies {
implementation libs.material
implementation libs.activity
implementation libs.constraintlayout
implementation project(':model')
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core

View File

@ -14,11 +14,13 @@ import androidx.navigation.fragment.NavHostFragment;
import androidx.navigation.ui.NavigationUI;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
import one.nem.kidshift.data.UserSettings;
import one.nem.kidshift.utils.FabManager;
import one.nem.kidshift.utils.KSLogger;
import one.nem.kidshift.utils.factory.KSLoggerFactory;
@ -28,8 +30,13 @@ public class MainActivity extends AppCompatActivity {
@Inject
KSLoggerFactory loggerFactory;
@Inject
FabManager fabManager;
private KSLogger logger;
private FloatingActionButton fab;
@Inject
UserSettings userSettings;
@ -71,6 +78,9 @@ public class MainActivity extends AppCompatActivity {
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
}
fab = findViewById(R.id.mainFab);
fabManager.setFab(fab);
}
/**

View File

@ -27,4 +27,15 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/main_nav_menu" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/mainFab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:layout_marginBottom="24dp"
android:clickable="true"
app:layout_constraintBottom_toTopOf="@id/bottom_nav"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/add_24px" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -31,7 +31,7 @@ public interface ChildData {
* 子ユーザー追加
* @param child 子ユーザー情報
*/
void addChild(ChildModel child);
CompletableFuture<ChildModel> addChild(ChildModel child);
/**
* 子ユーザー削除

View File

@ -27,19 +27,19 @@ public interface TaskData {
* タスクを追加する
* @param task タスク
*/
void addTask(TaskItemModel task);
CompletableFuture<TaskItemModel> addTask(TaskItemModel task);
/**
* タスクを削除する
* @param taskId タスクID
*/
void removeTask(String taskId);
CompletableFuture<Void> removeTask(String taskId);
/**
* タスクを更新する
* @param task タスク
*/
void updateTask(TaskItemModel task);
CompletableFuture<Void> updateTask(TaskItemModel task);
// 子側
@ -55,5 +55,5 @@ public interface TaskData {
* @param taskId タスクID
* @param childId 子ID
*/
void recordTaskCompletion(String taskId, String childId);
CompletableFuture<Void> recordTaskCompletion(String taskId, String childId);
}

View File

@ -1,17 +1,16 @@
package one.nem.kidshift.data.impl;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import javax.inject.Inject;
import one.nem.kidshift.data.ChildData;
import one.nem.kidshift.data.KSActions;
import one.nem.kidshift.data.retrofit.KidShiftApiService;
import one.nem.kidshift.data.retrofit.model.child.ChildListResponse;
import one.nem.kidshift.data.retrofit.model.child.ChildLoginCodeResponse;
import one.nem.kidshift.data.retrofit.model.child.ChildResponse;
import one.nem.kidshift.data.retrofit.model.converter.ChildModelConverter;
import one.nem.kidshift.data.room.utils.CacheWrapper;
import one.nem.kidshift.model.ChildModel;
@ -22,13 +21,14 @@ import retrofit2.Call;
import retrofit2.Response;
public class ChildDataImpl implements ChildData {
private final KidShiftApiService kidShiftApiService;
private final KSActions ksActions;
private final CacheWrapper cacheWrapper;
private final KSLogger logger;
@Inject
public ChildDataImpl(KSActions ksActions, CacheWrapper cacheWrapper, KSLoggerFactory loggerFactory) {
public ChildDataImpl(KidShiftApiService kidShiftApiService, KSActions ksActions, CacheWrapper cacheWrapper, KSLoggerFactory loggerFactory) {
this.kidShiftApiService = kidShiftApiService;
this.ksActions = ksActions;
this.cacheWrapper = cacheWrapper;
this.logger = loggerFactory.create("ChildDataImpl");
@ -44,33 +44,31 @@ public class ChildDataImpl implements ChildData {
return CompletableFuture.supplyAsync(() -> {
logger.debug("子供リスト取得開始");
AtomicReference<List<ChildModel>> childListTmp = new AtomicReference<>();
Thread thread = new Thread(() -> {
ksActions.syncChildList().thenAccept(childList -> {
if (childListTmp.get() == null || childListTmp.get().isEmpty()) {
logger.debug("子供リスト取得完了: キャッシュよりはやく取得完了 or キャッシュ無し");
if (childList == null || childList.isEmpty()) {
callback.onUnchanged();
} else {
callback.onUpdated(childList);
}
Thread thread = new Thread(() -> ksActions.syncChildList().thenAccept(childList -> {
if (childListTmp.get() == null || childListTmp.get().isEmpty()) {
logger.debug("子供リスト取得完了: キャッシュよりはやく取得完了 or キャッシュ無し");
if (childList == null || childList.isEmpty()) {
callback.onUnchanged();
} else {
boolean isChanged =
childList.size() != childListTmp.get().size() ||
childList.stream().anyMatch(child -> childListTmp.get().stream().noneMatch(childTmp -> child.getId().equals(childTmp.getId())));
if (isChanged) {
logger.debug("子供リスト取得完了: キャッシュと比較して変更あり");
callback.onUpdated(childList);
} else {
logger.debug("子供リスト取得完了: キャッシュと比較して変更なし");
callback.onUnchanged();
}
callback.onUpdated(childList);
}
}).exceptionally(e -> {
logger.error("子供リスト取得失敗: " + e.getMessage());
callback.onFailed(e.getMessage());
return null;
});
});
} else {
boolean isChanged =
childList.size() != childListTmp.get().size() ||
childList.stream().anyMatch(child -> childListTmp.get().stream().noneMatch(childTmp -> child.getId().equals(childTmp.getId())));
if (isChanged) {
logger.debug("子供リスト取得完了: キャッシュと比較して変更あり");
callback.onUpdated(childList);
} else {
logger.debug("子供リスト取得完了: キャッシュと比較して変更なし");
callback.onUnchanged();
}
}
}).exceptionally(e -> {
logger.error("子供リスト取得失敗: " + e.getMessage());
callback.onFailed(e.getMessage());
return null;
}));
thread.start();
return cacheWrapper.getChildList().thenApply(childList -> {
if (childList == null || childList.isEmpty()) {
@ -96,8 +94,22 @@ public class ChildDataImpl implements ChildData {
}
@Override
public void addChild(ChildModel child) {
public CompletableFuture<ChildModel> addChild(ChildModel child) {
return CompletableFuture.supplyAsync(() -> {
Call<ChildResponse> call = kidShiftApiService.addChild(ChildModelConverter.childModelToChildAddRequest(child));
try {
Response<ChildResponse> response = call.execute();
if (response.isSuccessful()) {
assert response.body() != null;
logger.info("子供追加成功(childId: " + response.body().getId() + ")");
return ChildModelConverter.childResponseToChildModel(response.body());
} else {
throw new RuntimeException("HTTP Status: " + response.code());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
@Override
@ -107,6 +119,19 @@ public class ChildDataImpl implements ChildData {
@Override
public CompletableFuture<Integer> issueLoginCode(String childId) {
return null;
return CompletableFuture.supplyAsync(() -> {
Call<ChildLoginCodeResponse> call = kidShiftApiService.issueLoginCode(childId);
try {
Response<ChildLoginCodeResponse> response = call.execute();
if (response.isSuccessful()) {
assert response.body() != null;
return response.body().getCode();
} else {
throw new RuntimeException("HTTP Status: " + response.code());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
}

View File

@ -8,21 +8,28 @@ import javax.inject.Inject;
import one.nem.kidshift.data.KSActions;
import one.nem.kidshift.data.TaskData;
import one.nem.kidshift.data.retrofit.KidShiftApiService;
import one.nem.kidshift.data.retrofit.model.converter.TaskModelConverter;
import one.nem.kidshift.data.retrofit.model.task.TaskResponse;
import one.nem.kidshift.data.room.utils.CacheWrapper;
import one.nem.kidshift.model.callback.TaskItemModelCallback;
import one.nem.kidshift.model.tasks.TaskItemModel;
import one.nem.kidshift.utils.KSLogger;
import one.nem.kidshift.utils.factory.KSLoggerFactory;
import retrofit2.Call;
import retrofit2.Response;
public class TaskDataImpl implements TaskData {
private final KSActions ksActions;
private final KidShiftApiService kidShiftApiService;
private final CacheWrapper cacheWrapper;
private final KSLogger logger;
@Inject
public TaskDataImpl(KSActions ksActions, CacheWrapper cacheWrapper, KSLoggerFactory loggerFactory) {
public TaskDataImpl(KSActions ksActions, KidShiftApiService kidShiftApiService, CacheWrapper cacheWrapper, KSLoggerFactory loggerFactory) {
this.ksActions = ksActions;
this.kidShiftApiService = kidShiftApiService;
this.cacheWrapper = cacheWrapper;
this.logger = loggerFactory.create("TaskDataImpl");
}
@ -32,34 +39,32 @@ public class TaskDataImpl implements TaskData {
return CompletableFuture.supplyAsync(() -> {
logger.debug("タスク取得開始");
AtomicReference<List<TaskItemModel>> taskListTmp = new AtomicReference<>();
Thread thread = new Thread(() -> {
ksActions.syncTasks().thenAccept(taskList -> {
if (taskListTmp.get() == null || taskListTmp.get().isEmpty()) {
logger.debug("タスク取得完了: キャッシュよりはやく取得完了 or キャッシュ無し");
if (taskList == null || taskList.isEmpty()) {
callback.onUnchanged();
} else {
callback.onUpdated(taskList);
}
Thread thread = new Thread(() -> ksActions.syncTasks().thenAccept(taskList -> {
if (taskListTmp.get() == null || taskListTmp.get().isEmpty()) {
logger.debug("タスク取得完了: キャッシュよりはやく取得完了 or キャッシュ無し");
if (taskList == null || taskList.isEmpty()) {
callback.onUnchanged();
} else {
// キャッシュと比較して変更の有無を確認
boolean isChanged =
taskList.size() != taskListTmp.get().size() ||
taskList.stream().anyMatch(task -> taskListTmp.get().stream().noneMatch(taskTmp -> task.getId().equals(taskTmp.getId())));
if (isChanged) {
logger.debug("タスク取得完了: キャッシュと比較して変更あり");
callback.onUpdated(taskList);
} else {
logger.debug("タスク取得完了: キャッシュと比較して変更なし");
callback.onUnchanged();
}
callback.onUpdated(taskList);
}
}).exceptionally(e -> {
logger.error("タスク取得失敗: " + e.getMessage());
callback.onFailed(e.getMessage());
return null;
});
});
} else {
// キャッシュと比較して変更の有無を確認
boolean isChanged =
taskList.size() != taskListTmp.get().size() ||
taskList.stream().anyMatch(task -> taskListTmp.get().stream().noneMatch(taskTmp -> task.getId().equals(taskTmp.getId())));
if (isChanged) {
logger.debug("タスク取得完了: キャッシュと比較して変更あり");
callback.onUpdated(taskList);
} else {
logger.debug("タスク取得完了: キャッシュと比較して変更なし");
callback.onUnchanged();
}
}
}).exceptionally(e -> {
logger.error("タスク取得失敗: " + e.getMessage());
callback.onFailed(e.getMessage());
return null;
}));
thread.start();
return cacheWrapper.getTaskList().thenApply(taskList -> {
if (taskList == null || taskList.isEmpty()) {
@ -85,18 +90,62 @@ public class TaskDataImpl implements TaskData {
}
@Override
public void addTask(TaskItemModel task) {
public CompletableFuture<TaskItemModel> addTask(TaskItemModel task) {
return CompletableFuture.supplyAsync(() -> {
Call<TaskResponse> call = kidShiftApiService.addTask(TaskModelConverter.taskItemModelToTaskAddRequest(task));
try {
Response<TaskResponse> response = call.execute();
if (response.isSuccessful()) {
assert response.body() != null;
logger.info("タスク追加成功(taskId: " + response.body().getId() + ")");
return TaskModelConverter.taskResponseToTaskItemModel(response.body());
} else {
logger.error("タスク追加失敗: HTTP Status: " + response.code());
throw new RuntimeException("HTTP Status: " + response.code());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
@Override
public void removeTask(String taskId) {
public CompletableFuture<Void> removeTask(String taskId) {
return CompletableFuture.supplyAsync(() -> {
Call<Void> call = kidShiftApiService.removeTask(taskId);
try {
Response<Void> response = call.execute();
if (response.isSuccessful()) {
logger.info("タスク削除成功(taskId: " + taskId + ")");
return null;
} else {
logger.error("タスク削除失敗: HTTP Status: " + response.code());
throw new RuntimeException("HTTP Status: " + response.code());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
@Override
public void updateTask(TaskItemModel task) {
public CompletableFuture<Void> updateTask(TaskItemModel task) {
return CompletableFuture.supplyAsync(() -> {
Call<TaskResponse> call = kidShiftApiService.updateTask(TaskModelConverter.taskItemModelToTaskAddRequest(task), task.getId());
try {
Response<TaskResponse> response = call.execute();
if (response.isSuccessful()) {
logger.info("タスク更新成功(taskId: " + task.getId() + ")");
// return response.body();
return null;
} else {
logger.error("タスク更新失敗: HTTP Status: " + response.code());
throw new RuntimeException("HTTP Status: " + response.code());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
@Override
@ -105,7 +154,21 @@ public class TaskDataImpl implements TaskData {
}
@Override
public void recordTaskCompletion(String taskId, String childId) {
public CompletableFuture<Void> recordTaskCompletion(String taskId, String childId) {
return CompletableFuture.supplyAsync(() -> {
Call<Void> call = kidShiftApiService.completeTask(taskId, childId);
try {
Response<Void> response = call.execute();
if (response.isSuccessful()) {
logger.info("タスク完了処理成功(taskId: " + taskId + ", childId: " + childId + ")");
return null;
} else {
logger.error("タスク完了処理失敗: HTTP Status: " + response.code());
throw new RuntimeException("HTTP Status: " + response.code());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
}

View File

@ -3,6 +3,7 @@ package one.nem.kidshift.data.retrofit;
import one.nem.kidshift.data.retrofit.interceptor.AuthorizationInterceptor;
import one.nem.kidshift.data.retrofit.model.child.ChildAddRequest;
import one.nem.kidshift.data.retrofit.model.child.ChildListResponse;
import one.nem.kidshift.data.retrofit.model.child.ChildLoginCodeResponse;
import one.nem.kidshift.data.retrofit.model.child.ChildResponse;
import one.nem.kidshift.data.retrofit.model.parent.ParentInfoResponse;
import one.nem.kidshift.data.retrofit.model.parent.auth.ParentLoginRequest;
@ -19,6 +20,7 @@ import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface KidShiftApiService {
@ -95,7 +97,7 @@ public interface KidShiftApiService {
*/
@POST("/parent/task/{id}/complete")
@Headers(AuthorizationInterceptor.HEADER_PLACEHOLDER)
Call<Void> completeTask(@Path("id") String id); // TODO-rca: OK responseをパース
Call<Void> completeTask(@Path("id") String id, @Query("childId") String childId);
// Child APIs
@ -116,4 +118,13 @@ public interface KidShiftApiService {
@Headers(AuthorizationInterceptor.HEADER_PLACEHOLDER)
Call<ChildResponse> addChild(@Body ChildAddRequest request);
/**
* 子供ログインコード発行
* @param id 子供ID
* @return ChildLoginCodeResponse
*/
@GET("/parent/child/{id}/login")
@Headers(AuthorizationInterceptor.HEADER_PLACEHOLDER)
Call<ChildLoginCodeResponse> issueLoginCode(@Path("id") String id);
}

View File

@ -0,0 +1,20 @@
package one.nem.kidshift.data.retrofit.model.child;
public class ChildLoginCodeResponse {
private int code;
public ChildLoginCodeResponse(int code) {
this.code = code;
}
public ChildLoginCodeResponse() {
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}

View File

@ -3,6 +3,7 @@ package one.nem.kidshift.data.retrofit.model.converter;
import java.util.List;
import java.util.stream.Collectors;
import one.nem.kidshift.data.retrofit.model.task.TaskAddRequest;
import one.nem.kidshift.data.retrofit.model.task.TaskListResponse;
import one.nem.kidshift.data.retrofit.model.task.TaskResponse;
import one.nem.kidshift.model.tasks.TaskItemModel;
@ -47,4 +48,13 @@ public class TaskModelConverter {
public static List<TaskItemModel> taskListResponseToTaskItemModelList(TaskListResponse taskListResponse) {
return taskListResponse.getList().stream().map(TaskModelConverter::taskResponseToTaskItemModel).collect(Collectors.toList());
}
public static TaskAddRequest taskItemModelToTaskAddRequest(TaskItemModel taskItemModel) {
TaskAddRequest request = new TaskAddRequest();
request.setName(taskItemModel.getName());
request.setReward(taskItemModel.getReward());
request.setBgColor(taskItemModel.getBgColor());
request.setIconEmoji(taskItemModel.getIconEmoji());
return request;
}
}

View File

@ -121,19 +121,7 @@ public class DebugCommandProcessor {
commandArray = shiftArray(commandArray);
switch (commandArray[0]) {
case "get":
commandArray = shiftArray(commandArray);
switch (commandArray[0]) {
case "all":
List<LogModel> logs = ksLogger.getHistory();
StringBuilder logString = new StringBuilder();
for (LogModel log : logs) {
logString.append(log.getMessage());
logString.append("\n");
}
return logString.toString();
default:
return "TODO";
}
return "Removed for performance reasons";
case "insert":
commandArray = shiftArray(commandArray);
String[] logArray = Arrays.copyOfRange(commandArray, 1, commandArray.length);

View File

@ -4,6 +4,7 @@ import android.inputmethodservice.Keyboard;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -15,8 +16,14 @@ import one.nem.kidshift.model.ChildModel;
public class SettingAdapter extends RecyclerView.Adapter<SettingAdapter.MainViewHolder> {
public interface LoginButtonCallback {
void onLoginButtonClicked(String childId);
}
private List<ChildModel> childDataList;
private LoginButtonCallback loginButtonCallback;
SettingAdapter() {
}
@ -25,13 +32,19 @@ public class SettingAdapter extends RecyclerView.Adapter<SettingAdapter.MainView
this.childDataList = childDataList;
}
public void setLoginButtonCallback(LoginButtonCallback loginButtonCallback) {
this.loginButtonCallback = loginButtonCallback;
}
static class MainViewHolder extends RecyclerView.ViewHolder{
TextView childname;
Button loginButton;
MainViewHolder(@NonNull View itemView) {
super(itemView);
childname = itemView.findViewById(R.id.childname);
loginButton = itemView.findViewById(R.id.loginButton);
}
}
@ -46,6 +59,11 @@ public class SettingAdapter extends RecyclerView.Adapter<SettingAdapter.MainView
public void onBindViewHolder(@NonNull MainViewHolder holder, int position){
ChildModel childData = this.childDataList.get(position);
holder.childname.setText(childData.getName());
holder.loginButton.setOnClickListener(v -> {
if (this.loginButtonCallback != null) {
this.loginButtonCallback.onLoginButtonClicked(childData.getId());
}
});
}
@Override

View File

@ -3,7 +3,6 @@ package one.nem.kidshift.feature.setting;
import android.annotation.SuppressLint;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -14,11 +13,12 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import javax.inject.Inject;
@ -30,8 +30,10 @@ import one.nem.kidshift.model.ChildModel;
import one.nem.kidshift.model.ParentModel;
import one.nem.kidshift.model.callback.ChildModelCallback;
import one.nem.kidshift.model.callback.ParentModelCallback;
import one.nem.kidshift.utils.FabManager;
import one.nem.kidshift.utils.KSLogger;
import one.nem.kidshift.utils.factory.KSLoggerFactory;
import one.nem.kidshift.utils.models.FabEventCallback;
@AndroidEntryPoint
public class SettingMainFragment extends Fragment {
@ -45,11 +47,14 @@ public class SettingMainFragment extends Fragment {
@Inject
KSLoggerFactory ksLoggerFactory;
@Inject
FabManager fabManager;
private KSLogger logger;
TextView username;
TextView useradress;
TextView userMailAddress;
SettingAdapter mainAdapter;
SwipeRefreshLayout swipeRefreshLayout;
@ -65,7 +70,12 @@ public class SettingMainFragment extends Fragment {
logger = ksLoggerFactory.create("SettingMainFragment");
}
private CompletableFuture<Void> updateParentInfo(){
/**
* 親情報を更新する
*
* @return CompletableFuture<Void>
*/
private CompletableFuture<Void> updateParentInfo() {
return parentData.getParent(new ParentModelCallback() {
@Override
public void onUnchanged() {
@ -83,13 +93,18 @@ public class SettingMainFragment extends Fragment {
}
}).thenAccept(parentModel -> {
username.setText(parentModel.getName() != null ? parentModel.getName() : "親の名前");
useradress.setText(parentModel.getEmail() != null ? parentModel.getEmail() : "親のアドレス");
userMailAddress.setText(parentModel.getEmail() != null ? parentModel.getEmail() : "親のアドレス");
});
}
/**
* 子供情報を更新する
*
* @return CompletableFuture<Void>
*/
@SuppressLint("NotifyDataSetChanged")
private CompletableFuture<Void> updateChildInfo(){
private CompletableFuture<Void> updateChildInfo() {
return childData.getChildList(new ChildModelCallback() {
@Override
public void onUnchanged() {
@ -115,6 +130,9 @@ public class SettingMainFragment extends Fragment {
});
}
/**
* ユーザー情報を更新するラッパー
*/
private void updateInfo() {
CompletableFuture<Void> updateParent = updateParentInfo();
CompletableFuture<Void> updateChildList = updateChildInfo();
@ -127,6 +145,10 @@ public class SettingMainFragment extends Fragment {
updateParent.thenCombine(updateChildList, (res1, res2) -> null).thenRun(() -> {
logger.debug("アップデート完了");
swipeRefreshLayout.setRefreshing(false);
}).exceptionally(e -> {
logger.error("アップデート失敗: " + e.getMessage());
swipeRefreshLayout.setRefreshing(false);
return null;
});
}
@ -137,61 +159,116 @@ public class SettingMainFragment extends Fragment {
View view = inflater.inflate(R.layout.fragment_setting_main, container, false);
// ビューの取得
username = view.findViewById(R.id.username);
useradress = view.findViewById(R.id.useradress);
userMailAddress = view.findViewById(R.id.useradress);
swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_layout);
RecyclerView recyclerView = view.findViewById(R.id.childrecyclerview);
// RecyclerViewの設定
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
mainAdapter = new SettingAdapter();
recyclerView.setAdapter(mainAdapter);
// Pull-to-refreshスワイプで更新
swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_layout);
try {
/*
TODO:
- コールバックの処理を実装
- 結果に応じてRecyclerViewを更新する
- キャッシュ受け取りの時にjoinでUIスレッドをブロックしないように
- Placeholderの表示?
- エラーハンドリング try catch文
- onFailed時にそれを通知
*/
// ユーザー情報の更新(初回)
updateInfo();
swipeRefreshLayout.setOnRefreshListener(() ->{
updateInfo();
// スワイプリフレッシュのリスナー
swipeRefreshLayout.setOnRefreshListener(() -> {
updateInfo(); // ユーザー情報の更新
});
} catch (Exception e) {
//
}
// ダイアログの設定
LayoutInflater dialogInflater = requireActivity().getLayoutInflater();
LayoutInflater inflater1 = requireActivity().getLayoutInflater();
View view1 = inflater1.inflate(R.layout.add_child_list_dialog,null);
View addChildDialogView = dialogInflater.inflate(R.layout.fragment_login_dialog_view, null);
//子供の名前追加のダイアログ
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext());
builder.setTitle("お子様の名前を入力してください。")
.setView(view1)
.setPositiveButton("追加",null)
.setNeutralButton("閉じる",null);
builder.create();
View childListItemView = inflater.inflate(R.layout.list_item_child_name_list, container, false);
view.findViewById(R.id.addchildname).setOnClickListener(v -> {
builder.show();
mainAdapter.setLoginButtonCallback(new SettingAdapter.LoginButtonCallback() {
@Override
public void onLoginButtonClicked(String childId) {
// Toast.makeText(getContext(), "ボタンがクリックされました(" + childId + ")", Toast.LENGTH_LONG).show();
int loginCode = childData.issueLoginCode(childId).join();
TextView loginCodeTextView = addChildDialogView.findViewById(R.id.loginCode);
new StringBuilder(Integer.toString(loginCode)).insert(3, "-");
loginCodeTextView.setText(
new StringBuilder(Integer.toString(loginCode)).insert(3, "-")
);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext());
builder.setTitle("ログインコード")
.setView(addChildDialogView)
.setNeutralButton("閉じる", null);
builder.create();
// childListItemView.findViewById(R.id.loginButton).setOnClickListener(v -> {
builder.show();
// });
}
});
// int loginCode = childData.issueLoginCode("543256").join();
// TextView loginCodeTextView = addChildDialogView.findViewById(R.id.loginCode);
// new StringBuilder(Integer.toString(loginCode)).insert(3,"-");
//
// loginCodeTextView.setText(
// new StringBuilder(Integer.toString(loginCode)).insert(3,"-"));
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext());
builder.setTitle("ログインコード")
.setView(addChildDialogView)
.setNeutralButton("閉じる", null);
builder.create();
//
// childListItemView.findViewById(R.id.loginButton).setOnClickListener(v -> {
// builder.show();
// });
// ダイアログの表示
if (!fabManager.isShown()) fabManager.show();
fabManager.setFabEventCallback(new FabEventCallback() {
@Override
public void onClicked() {
//子供の名前追加のダイアログ
View dialogView = dialogInflater.inflate(R.layout.add_child_list_dialog, null);
new MaterialAlertDialogBuilder(requireContext())
.setTitle("お子様の名前を入力してください。")
.setView(dialogView)
.setPositiveButton("追加", (dialog, which) -> {
ChildModel childModel = new ChildModel();
childModel.setName(Objects.requireNonNull(((TextView) dialogView.findViewById(R.id.childNameEditText)).getText()).toString());
childData.addChild(childModel).thenAccept(childModel1 -> { // Debug
logger.debug("子供を追加しました: " + childModel1.getName());
}).thenRun(() -> {
updateChildInfo();
});
})
.setNeutralButton("閉じる", (dialog, which) -> {
dialog.cancel();
}).show();
}
@Override
public void onLongClicked() {
// Do nothing
}
});
return view;
}
@Override
public void onResume() {
super.onResume();
// TODO: 更新する?
}
}

View File

@ -6,7 +6,7 @@
android:layout_height="match_parent">
<EditText
android:id="@+id/editTextText"
android:id="@+id/childNameEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:id="@+id/loginCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="30dp"
android:paddingBottom="25dp"
android:textAppearance="@style/TextAppearance.AppCompat.Display3" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -8,7 +8,7 @@
android:id="@+id/swipe_refresh_layout">
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

View File

@ -0,0 +1,55 @@
package one.nem.kidshift.utils;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import javax.inject.Inject;
import javax.inject.Singleton;
import one.nem.kidshift.utils.factory.KSLoggerFactory;
import one.nem.kidshift.utils.models.FabEventCallback;
@Singleton
public class FabManager {
private FloatingActionButton fab;
private final KSLogger logger;
@Inject
public FabManager(KSLoggerFactory loggerFactory) {
this.logger = loggerFactory.create("FabManager");
}
public void setFab(FloatingActionButton fab) {
this.fab = fab;
}
private void checkFab() {
if (fab == null) {
logger.error("Fab is not set");
throw new IllegalStateException("Fab is not set");
}
}
public void show() {
checkFab();
fab.show();
}
public void hide() {
checkFab();
fab.hide();
}
public boolean isShown() {
checkFab();
return fab.isShown();
}
public void setFabEventCallback(FabEventCallback callback) {
checkFab();
fab.setOnClickListener(v -> callback.onClicked());
fab.setOnLongClickListener(v -> {
callback.onLongClicked();
return true;
});
}
}

View File

@ -6,7 +6,6 @@ import one.nem.kidshift.utils.models.LogModel;
public interface KSLogger {
KSLogger addTag(String tag);
List<LogModel> getHistory();
void info(String message);
void warn(String message);
void error(String message);

View File

@ -1,32 +1,19 @@
package one.nem.kidshift.utils.impl;
import static one.nem.kidshift.utils.enums.LogLevelEnum.INFO;
import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import dagger.assisted.Assisted;
import dagger.assisted.AssistedInject;
import one.nem.kidshift.utils.KSLogger;
import one.nem.kidshift.utils.SharedPrefUtils;
import one.nem.kidshift.utils.enums.LogLevelEnum;
import one.nem.kidshift.utils.factory.SharedPrefUtilsFactory;
import one.nem.kidshift.utils.models.LogModel;
public class KSLoggerImpl implements KSLogger {
private ArrayList<String> tags = new ArrayList<String>();
private SharedPrefUtils sharedPrefUtils;
@AssistedInject
public KSLoggerImpl(SharedPrefUtilsFactory sharedPrefUtilsFactory, @Assisted String name) {
sharedPrefUtils = sharedPrefUtilsFactory.create("KSLogger");
public KSLoggerImpl(@Assisted String name) {
tags.clear();
tags.add(name);
}
@ -37,11 +24,6 @@ public class KSLoggerImpl implements KSLogger {
return this;
}
@Override
public List<LogModel> getHistory() {
return sharedPrefUtils.getObjects(LogModel.class);
}
@Override
public void info(String message) {
log(new LogModel(LogLevelEnum.INFO, tags.toArray(new String[0]), message));
@ -73,14 +55,9 @@ public class KSLoggerImpl implements KSLogger {
}
private void log(LogModel log) {
addLog(log);
outputLog(log);
}
private void addLog(LogModel log) {
sharedPrefUtils.saveObject(log);
}
private void outputLog(LogModel log) {
// ,区切りで出力
String tags = log.getTags().length > 0 ? String.join(",", log.getTags()) : "UNTAGGED";

View File

@ -0,0 +1,6 @@
package one.nem.kidshift.utils.models;
public interface FabEventCallback {
void onClicked();
void onLongClicked();
}

View File

@ -0,0 +1,21 @@
package one.nem.kidshift.utils.modules;
import dagger.Module;
import dagger.Provides;
import dagger.hilt.InstallIn;
import dagger.hilt.components.SingletonComponent;
import one.nem.kidshift.utils.FabManager;
import one.nem.kidshift.utils.factory.KSLoggerFactory;
import javax.inject.Singleton;
@Module
@InstallIn(SingletonComponent.class)
public class FabManagerModule {
@Provides
@Singleton
public FabManager provideFabManager(KSLoggerFactory loggerFactory) {
return new FabManager(loggerFactory);
}
}