diff --git a/component/common/src/main/java/one/nem/lacerta/component/common/picker/LacertaDirPickerDialog.java b/component/common/src/main/java/one/nem/lacerta/component/common/picker/LacertaDirPickerDialog.java new file mode 100644 index 00000000..aec649c2 --- /dev/null +++ b/component/common/src/main/java/one/nem/lacerta/component/common/picker/LacertaDirPickerDialog.java @@ -0,0 +1,115 @@ +package one.nem.lacerta.component.common.picker; + +import android.app.Dialog; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +import javax.inject.Inject; + +import dagger.hilt.android.AndroidEntryPoint; +import one.nem.lacerta.component.common.R; +import one.nem.lacerta.component.common.picker.base.LacertaFilePickerAdapterBase; +import one.nem.lacerta.component.common.picker.base.LacertaFilePickerDialogBase; +import one.nem.lacerta.data.LacertaLibrary; +import one.nem.lacerta.model.ListItemType; +import one.nem.lacerta.model.PublicPath; + +@AndroidEntryPoint +public class LacertaDirPickerDialog extends LacertaFilePickerDialogBase { + + @Inject + LacertaLibrary lacertaLibrary; + + // Listener + public interface LacertaDirPickerDialogListener { + void onDirSelected(String name, String dirId); + } + + // Variables + LacertaDirPickerDialogListener listener; + + // Setter + public LacertaDirPickerDialog setListener(LacertaDirPickerDialogListener listener) { + this.listener = listener; + return this; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + super.onCreateDialog(savedInstanceState); + + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()); + + View view = LayoutInflater.from(getActivity()).inflate(R.layout.lacerta_dialog_select_dir, null); + + // 高さを画面の40%にする + int height = (int) (getResources().getDisplayMetrics().heightPixels * 0.4); + view.setMinimumHeight(height); + + RecyclerView recyclerView = view.findViewById(R.id.select_dir_recycler_view); + TextView currentDirTextView = view.findViewById(R.id.current_dir_text_view); + + LacertaFilePickerAdapterBase adapter = new LacertaFilePickerAdapterBase(); + adapter.setListener(new LacertaFilePickerAdapterBase.LacertaFilePickerAdapterListener() { + @Override + public void onItemSelected(String dirId) { + updateList(adapter, dirId); + updatePublicPath(currentDirTextView, dirId); + } + + @Override + public void onBackSelected(String dirId) { + updateList(adapter, dirId); + updatePublicPath(currentDirTextView, dirId); + } + }); + + recyclerView.setAdapter(adapter); + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + + this.updateList(adapter, null); // ルートディレクトリのリストを表示 + + // Init dialog + builder.setTitle(this.title == null ? "フォルダを選択" : this.title); + builder.setMessage(this.message == null ? "フォルダを選択してください" : this.message); + builder.setView(view); + builder.setPositiveButton(this.positiveButtonText == null ? "OK" : this.positiveButtonText, (dialog, which) -> { + if (listener != null) { + listener.onDirSelected( + adapter.getCurrentPageTitle(), + adapter.getCurrentId()); + } + }); + builder.setNegativeButton(this.negativeButtonText == null ? "キャンセル" : this.negativeButtonText, (dialog, which) -> { + if (listener != null) { + dismiss(); + } + }); + + return builder.create(); + } + + private void updatePublicPath(TextView currentDirTextView, String folderId) { + lacertaLibrary.getPublicPath(folderId, ListItemType.ITEM_TYPE_FOLDER).thenAccept(publicPath -> { + this.updatePathTextView(currentDirTextView, publicPath, ListItemType.ITEM_TYPE_FOLDER); + }); + } + + private void updateList(LacertaFilePickerAdapterBase adapter, String folderId) { + lacertaLibrary.getFolderList(folderId).thenAccept(libraryItemPage -> { + int currentCount = adapter.getItemCount(); + String currentId = adapter.getCurrentId(); +// adapter.setListItems(libraryItemPage); + getActivity().runOnUiThread(() -> { + this.updateListView(adapter, libraryItemPage, currentCount, currentId); + }); + }); + } +} diff --git a/component/common/src/main/java/one/nem/lacerta/component/common/picker/LacertaFilePickerAdapter.java b/component/common/src/main/java/one/nem/lacerta/component/common/picker/LacertaFilePickerAdapter.java new file mode 100644 index 00000000..fa0163d2 --- /dev/null +++ b/component/common/src/main/java/one/nem/lacerta/component/common/picker/LacertaFilePickerAdapter.java @@ -0,0 +1,33 @@ +package one.nem.lacerta.component.common.picker; + +import one.nem.lacerta.component.common.picker.base.LacertaFilePickerAdapterBase; +import one.nem.lacerta.model.ListItem; +import one.nem.lacerta.model.ListItemType; + +public class LacertaFilePickerAdapter extends LacertaFilePickerAdapterBase { + + // Listener + public interface LacertaFilePickerAdapterListener extends LacertaFilePickerAdapterBase.LacertaFilePickerAdapterListener { + void onDocumentSelected(String documentId); + } + + // Variables + LacertaFilePickerAdapterListener listener; + + // Setter + public LacertaFilePickerAdapter setListener(LacertaFilePickerAdapterListener listener) { + this.listener = listener; + return this; + } + + @Override + public void onBindViewHolder(LacertaFilePickerViewHolder holder, int position) { + super.onBindViewHolder(holder, position); + if (libraryItemPage.getListItems().get(position).getItemType() == ListItemType.ITEM_TYPE_DOCUMENT) { + holder.itemView.setOnClickListener(v -> { + ListItem listItem = libraryItemPage.getListItems().get(position); + listener.onDocumentSelected(listItem.getItemId()); + }); + } + } +} diff --git a/component/common/src/main/java/one/nem/lacerta/component/common/picker/LacertaFilePickerDialog.java b/component/common/src/main/java/one/nem/lacerta/component/common/picker/LacertaFilePickerDialog.java new file mode 100644 index 00000000..5a082b74 --- /dev/null +++ b/component/common/src/main/java/one/nem/lacerta/component/common/picker/LacertaFilePickerDialog.java @@ -0,0 +1,114 @@ +package one.nem.lacerta.component.common.picker; + +import android.app.Dialog; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +import javax.inject.Inject; + +import dagger.hilt.android.AndroidEntryPoint; +import one.nem.lacerta.component.common.R; +import one.nem.lacerta.component.common.picker.base.LacertaFilePickerAdapterBase; +import one.nem.lacerta.component.common.picker.base.LacertaFilePickerDialogBase; +import one.nem.lacerta.data.LacertaLibrary; +import one.nem.lacerta.model.ListItemType; + +@AndroidEntryPoint +public class LacertaFilePickerDialog extends LacertaFilePickerDialogBase { + + @Inject + LacertaLibrary lacertaLibrary; + + // Listener + public interface LacertaFilePickerDialogListener { + void onFileSelected(String name, String fileId); + } + + // Variables + LacertaFilePickerDialogListener listener; + + // Setter + public LacertaFilePickerDialog setListener(LacertaFilePickerDialogListener listener) { + this.listener = listener; + return this; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + super.onCreateDialog(savedInstanceState); + + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()); + + View view = LayoutInflater.from(getActivity()).inflate(R.layout.lacerta_dialog_select_dir, null); + + // 高さを画面の40%にする + int height = (int) (getResources().getDisplayMetrics().heightPixels * 0.4); + view.setMinimumHeight(height); + + RecyclerView recyclerView = view.findViewById(R.id.select_dir_recycler_view); + TextView currentDirTextView = view.findViewById(R.id.current_dir_text_view); + + LacertaFilePickerAdapter adapter = new LacertaFilePickerAdapter(); + adapter.setListener(new LacertaFilePickerAdapter.LacertaFilePickerAdapterListener() { + @Override + public void onItemSelected(String dirId) { + updateList(adapter, dirId); + updatePublicPath(currentDirTextView, dirId); + } + + @Override + public void onBackSelected(String dirId) { + updateList(adapter, dirId); + updatePublicPath(currentDirTextView, dirId); + } + + @Override + public void onDocumentSelected(String documentId) { + if (listener != null) { + dismiss(); + listener.onFileSelected(documentId, documentId); + } + } + }); + + recyclerView.setAdapter(adapter); + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + + this.updateList(adapter, null); // ルートディレクトリのリストを表示 + + // Init dialog + builder.setTitle(this.title == null ? "ファイルを選択" : this.title); + builder.setMessage(this.message == null ? "ファイルを選択してください" : this.message); + builder.setView(view); + builder.setNegativeButton(this.negativeButtonText == null ? "キャンセル" : this.negativeButtonText, (dialog, which) -> { + dismiss(); + }); + + return builder.create(); + } + + private void updatePublicPath(TextView currentDirTextView, String folderId) { + lacertaLibrary.getPublicPath(folderId, ListItemType.ITEM_TYPE_FOLDER).thenAccept(publicPath -> { + this.updatePathTextView(currentDirTextView, publicPath, ListItemType.ITEM_TYPE_FOLDER); + }); + } + + private void updateList(LacertaFilePickerAdapterBase adapter, String folderId) { + lacertaLibrary.getLibraryPage(folderId, 100).thenAccept(libraryItemPage -> { // TODO-rca: 100 is a magic number + int currentCount = adapter.getItemCount(); + String currentId = adapter.getCurrentId(); +// adapter.setListItems(libraryItemPage); + getActivity().runOnUiThread(() -> { + this.updateListView(adapter, libraryItemPage, currentCount, currentId); + }); + }); + } + +} diff --git a/component/common/src/main/java/one/nem/lacerta/component/common/picker/base/LacertaFilePickerAdapterBase.java b/component/common/src/main/java/one/nem/lacerta/component/common/picker/base/LacertaFilePickerAdapterBase.java new file mode 100644 index 00000000..190a64cc --- /dev/null +++ b/component/common/src/main/java/one/nem/lacerta/component/common/picker/base/LacertaFilePickerAdapterBase.java @@ -0,0 +1,110 @@ +package one.nem.lacerta.component.common.picker.base; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import one.nem.lacerta.model.LibraryItemPage; +import one.nem.lacerta.model.ListItem; +import one.nem.lacerta.model.ListItemType; + +public class LacertaFilePickerAdapterBase extends RecyclerView.Adapter { + + // Listener + public interface LacertaFilePickerAdapterListener { + void onItemSelected(String dirId); + void onBackSelected(String dirId); + } + + protected LibraryItemPage libraryItemPage; + + protected LacertaFilePickerAdapterListener listener; + + // Empty constructor + public LacertaFilePickerAdapterBase() { + } + + public void setListItems(LibraryItemPage libraryItemPage) { + this.libraryItemPage = libraryItemPage; + if (this.libraryItemPage.getPageId() != null) { // ルートディレクトリの場合は戻るボタンを表示しない + this.libraryItemPage.getListItems().add(0, new ListItem("戻る", " ", ListItemType.ITEM_TYPE_ACTION_BACK, null)); + } + } + + public void setListener(LacertaFilePickerAdapterListener listener) { + this.listener = listener; + } + + @NonNull + @Override + public LacertaFilePickerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(one.nem.lacerta.shared.ui.R.layout.common_list_item, parent, false); + return new LacertaFilePickerViewHolder(view); + } + + @Override + public void onBindViewHolder(LacertaFilePickerViewHolder holder, int position) { + ListItem listItem = libraryItemPage.getListItems().get(position); + holder.title.setText(listItem.getTitle()); + holder.description.setText(listItem.getDescription()); + holder.icon.setImageResource(listItem.getItemType().getIconId()); + if(listItem.getItemType() == ListItemType.ITEM_TYPE_ACTION_BACK) { + holder.itemView.setOnClickListener(v -> listener.onBackSelected(this.libraryItemPage.getParentId())); + } else { + holder.itemView.setOnClickListener(v -> listener.onItemSelected(listItem.getItemId())); + } + } + + @Override + public int getItemCount() { + return this.libraryItemPage == null ? 0 : this.libraryItemPage.getListItems().size(); + } + + public String getCurrentId() { + if (this.libraryItemPage == null) { + return null; + } else { + if (this.libraryItemPage.getPageId() == null) { + return null; + } else { + return this.libraryItemPage.getPageId(); + } + } + } + + public String getCurrentPageTitle() { + if (this.libraryItemPage == null) { + return null; + } else { + if (this.libraryItemPage.getPageId() == null) { + return null; + } else { + return this.libraryItemPage.getPageTitle(); + } + } + } + + public static class LacertaFilePickerViewHolder extends RecyclerView.ViewHolder { + + TextView title; + TextView description; + + ImageView icon; + + + public LacertaFilePickerViewHolder(@NonNull View itemView) { + super(itemView); + + title = itemView.findViewById(one.nem.lacerta.shared.ui.R.id.item_title); + description = itemView.findViewById(one.nem.lacerta.shared.ui.R.id.item_description); + icon = itemView.findViewById(one.nem.lacerta.shared.ui.R.id.item_icon); + description.setVisibility(View.GONE); // 暫定 + + } + } +} diff --git a/component/common/src/main/java/one/nem/lacerta/component/common/picker/base/LacertaFilePickerDialogBase.java b/component/common/src/main/java/one/nem/lacerta/component/common/picker/base/LacertaFilePickerDialogBase.java new file mode 100644 index 00000000..e497f642 --- /dev/null +++ b/component/common/src/main/java/one/nem/lacerta/component/common/picker/base/LacertaFilePickerDialogBase.java @@ -0,0 +1,88 @@ +package one.nem.lacerta.component.common.picker.base; + +import android.widget.TextView; + +import androidx.fragment.app.DialogFragment; + +import javax.inject.Inject; + +import one.nem.lacerta.model.LibraryItemPage; +import one.nem.lacerta.model.ListItemType; +import one.nem.lacerta.model.PublicPath; +import one.nem.lacerta.utils.LacertaLogger; + +public class LacertaFilePickerDialogBase extends DialogFragment { + @Inject + LacertaLogger logger; + + // Variables + protected String title; + protected String message; + protected String positiveButtonText; + protected String negativeButtonText; + + // Setter + public LacertaFilePickerDialogBase setTitle(String title) { + this.title = title; + return this; + } + + public LacertaFilePickerDialogBase setMessage(String message) { + this.message = message; + return this; + } + + public LacertaFilePickerDialogBase setPositiveButtonText(String positiveButtonText) { + this.positiveButtonText = positiveButtonText; + return this; + } + + public LacertaFilePickerDialogBase setNegativeButtonText(String negativeButtonText) { + this.negativeButtonText = negativeButtonText; + return this; + } + + // Methods + + protected void updatePathTextView(TextView currentDirTextView, PublicPath publicPath, ListItemType listItemType) { + if (publicPath == null) { + currentDirTextView.setText("/"); + } else { + if (listItemType == ListItemType.ITEM_TYPE_FOLDER) { + currentDirTextView.setText("/" + publicPath.getStringPath()); // TODO-rca: PublicPath側の実装を治すべき + } else { + currentDirTextView.setText("/" + publicPath.parent().getStringPath()); // TODO-rca: PublicPath側の実装を治すべき + } + } + } + + protected void updateListView(LacertaFilePickerAdapterBase adapter, LibraryItemPage libraryItemPage, int currentCount, String currentDirId) { + if (currentCount == 0) { + // 初回表示 + adapter.setListItems(libraryItemPage); + adapter.notifyItemRangeInserted(0, libraryItemPage.getListItems().size()); + } else if (currentDirId == null) { + // Rootが関わる推移 (Rootからの推移) + adapter.setListItems(libraryItemPage); + adapter.notifyItemRangeRemoved(0, currentCount); + adapter.notifyItemRangeInserted(0, libraryItemPage.getListItems().size()); + } else if (libraryItemPage.getPageId() == null) { + // Rootが関わる推移 (Rootへの推移) + adapter.setListItems(libraryItemPage); + adapter.notifyItemRangeRemoved(0, currentCount); + adapter.notifyItemRangeInserted(0, libraryItemPage.getListItems().size()); + } else if (libraryItemPage.getPageId() != null) { + // Rootが関わらない推移 + adapter.setListItems(libraryItemPage); + adapter.notifyItemRangeRemoved(1, currentCount); + adapter.notifyItemRangeInserted(1, libraryItemPage.getListItems().size()); + } else { + // その他の遷移(安全側に倒すため全アイテム更新) + logger.warn("FilePickerDialogBase", "Unknown transition."); + logger.warn("FilePickerDialogBase", "currentDirId: " + currentDirId + ", libraryItemPage.getPageId(): " + libraryItemPage.getPageId()); + adapter.setListItems(libraryItemPage); + adapter.notifyItemRangeRemoved(0, currentCount); + adapter.notifyItemRangeInserted(0, libraryItemPage.getListItems().size()); + } + } +} diff --git a/component/common/src/main/java/one/nem/lacerta/component/common/picker/base/placeholder b/component/common/src/main/java/one/nem/lacerta/component/common/picker/base/placeholder new file mode 100644 index 00000000..e69de29b diff --git a/component/common/src/main/java/one/nem/lacerta/component/common/picker/placeholder b/component/common/src/main/java/one/nem/lacerta/component/common/picker/placeholder new file mode 100644 index 00000000..e69de29b diff --git a/component/viewer/src/main/java/one/nem/lacerta/component/viewer/ViewerListFragment.java b/component/viewer/src/main/java/one/nem/lacerta/component/viewer/ViewerListFragment.java index 349bc99a..65518a10 100644 --- a/component/viewer/src/main/java/one/nem/lacerta/component/viewer/ViewerListFragment.java +++ b/component/viewer/src/main/java/one/nem/lacerta/component/viewer/ViewerListFragment.java @@ -23,6 +23,7 @@ import one.nem.lacerta.component.common.LacertaSelectDirDialog; import one.nem.lacerta.component.common.LacertaSelectDirDialogListener; import one.nem.lacerta.component.common.LacertaSelectRevDialog; import one.nem.lacerta.component.common.LacertaSelectRevDialogListener; +import one.nem.lacerta.component.common.picker.LacertaDirPickerDialog; import one.nem.lacerta.data.Document; import one.nem.lacerta.data.LacertaLibrary; import one.nem.lacerta.model.ListItemType; @@ -239,29 +240,21 @@ public class ViewerListFragment extends Fragment { builder.show(); return true; } else if (item.getItemId() == R.id.action_move) { - LacertaSelectDirDialog lacertaSelectDirDialog = new LacertaSelectDirDialog(); - lacertaSelectDirDialog.setListener(new LacertaSelectDirDialogListener() { - @Override - public void onDirSelected(String name, String itemId) { - logger.debug(TAG, "Selected dir: " + name + ", " + itemId); - document.moveDocument(documentId, itemId).thenAccept(aVoid -> { - getActivity().runOnUiThread(() -> { - // Stop Activity - getActivity().finish(); // TODO-rca: ファイル移動後に終了するべきかは検討 - }); + LacertaDirPickerDialog lacertaDirPickerDialog = new LacertaDirPickerDialog(); + lacertaDirPickerDialog.setListener((name, dirId) -> { + logger.debug(TAG, "Selected dir: " + name + ", " + dirId); + document.moveDocument(documentId, dirId).thenAccept(aVoid -> { + getActivity().runOnUiThread(() -> { + // Stop Activity + getActivity().finish(); // TODO-rca: ファイル移動後に終了するべきかは検討 }); - } - - @Override - public void onCanceled() { - logger.debug(TAG, "Canceled"); - } + }); }); - lacertaSelectDirDialog.setTitle("ファイルの移動") - .setMessage("ファイルを移動するフォルダを選択してください。") - .setPositiveButtonText("移動") - .setNegativeButtonText("キャンセル"); - lacertaSelectDirDialog.show(getParentFragmentManager(), "select_dir_dialog"); + lacertaDirPickerDialog.setTitle("ファイルの移動") + .setMessage("ファイルを移動するフォルダを選択してください。") + .setPositiveButtonText("移動") + .setNegativeButtonText("キャンセル"); + lacertaDirPickerDialog.show(getParentFragmentManager(), "select_dir_dialog"); return true; } else { return false;