|
|
|
|
@ -183,6 +183,7 @@ public class SidebarFragment extends Fragment {
|
|
|
|
|
// 设置RecyclerView
|
|
|
|
|
rvFolderTree.setLayoutManager(new LinearLayoutManager(requireContext()));
|
|
|
|
|
adapter = new FolderTreeAdapter(new ArrayList<>(), viewModel);
|
|
|
|
|
adapter.setOnFolderItemClickListener(this::handleFolderItemClick);
|
|
|
|
|
rvFolderTree.setAdapter(adapter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -243,22 +244,27 @@ public class SidebarFragment extends Fragment {
|
|
|
|
|
*/
|
|
|
|
|
private void setupFolderClickListener(View view, long folderId) {
|
|
|
|
|
view.setOnClickListener(v -> {
|
|
|
|
|
android.util.Log.d(TAG, "setupFolderClickListener: folderId=" + folderId);
|
|
|
|
|
long currentTime = System.currentTimeMillis();
|
|
|
|
|
if (lastClickedView == view && (currentTime - lastClickTime) < DOUBLE_CLICK_INTERVAL) {
|
|
|
|
|
android.util.Log.d(TAG, "Double click on root folder, jumping to: " + folderId);
|
|
|
|
|
// 这是双击,执行跳转
|
|
|
|
|
if (listener != null && folderId != Notes.ID_ROOT_FOLDER) {
|
|
|
|
|
if (listener != null) {
|
|
|
|
|
// 根文件夹也可以跳转(回到根)
|
|
|
|
|
listener.onFolderSelected(folderId);
|
|
|
|
|
}
|
|
|
|
|
// 重置双击状态
|
|
|
|
|
lastClickTime = 0;
|
|
|
|
|
lastClickedView = null;
|
|
|
|
|
} else {
|
|
|
|
|
android.util.Log.d(TAG, "Single click on root folder, will toggle expand in " + DOUBLE_CLICK_INTERVAL + "ms");
|
|
|
|
|
// 可能是单击,延迟处理
|
|
|
|
|
lastClickTime = currentTime;
|
|
|
|
|
lastClickedView = view;
|
|
|
|
|
view.postDelayed(() -> {
|
|
|
|
|
// 如果在延迟期间没有发生双击,则执行单击操作(展开/收起)
|
|
|
|
|
if (System.currentTimeMillis() - lastClickTime >= DOUBLE_CLICK_INTERVAL) {
|
|
|
|
|
android.util.Log.d(TAG, "Toggling root folder expand");
|
|
|
|
|
toggleFolderExpand(folderId);
|
|
|
|
|
}
|
|
|
|
|
}, DOUBLE_CLICK_INTERVAL);
|
|
|
|
|
@ -284,9 +290,44 @@ public class SidebarFragment extends Fragment {
|
|
|
|
|
* 切换文件夹展开/收起状态
|
|
|
|
|
*/
|
|
|
|
|
private void toggleFolderExpand(long folderId) {
|
|
|
|
|
android.util.Log.d(TAG, "toggleFolderExpand: folderId=" + folderId);
|
|
|
|
|
viewModel.toggleFolderExpand(folderId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理文件夹项点击(单击/双击)
|
|
|
|
|
*/
|
|
|
|
|
private void handleFolderItemClick(long folderId) {
|
|
|
|
|
android.util.Log.d(TAG, "handleFolderItemClick: folderId=" + folderId);
|
|
|
|
|
long currentTime = System.currentTimeMillis();
|
|
|
|
|
if (lastClickedFolderId == folderId && (currentTime - lastFolderClickTime) < DOUBLE_CLICK_INTERVAL) {
|
|
|
|
|
android.util.Log.d(TAG, "Double click detected, jumping to folder: " + folderId);
|
|
|
|
|
// 这是双击,执行跳转
|
|
|
|
|
if (listener != null) {
|
|
|
|
|
listener.onFolderSelected(folderId);
|
|
|
|
|
}
|
|
|
|
|
// 重置双击状态
|
|
|
|
|
lastFolderClickTime = 0;
|
|
|
|
|
lastClickedFolderId = -1;
|
|
|
|
|
} else {
|
|
|
|
|
android.util.Log.d(TAG, "Single click, will toggle expand in " + DOUBLE_CLICK_INTERVAL + "ms");
|
|
|
|
|
// 可能是单击,延迟处理
|
|
|
|
|
lastFolderClickTime = currentTime;
|
|
|
|
|
lastClickedFolderId = folderId;
|
|
|
|
|
new android.os.Handler().postDelayed(() -> {
|
|
|
|
|
// 如果在延迟期间没有发生双击,则执行单击操作(展开/收起)
|
|
|
|
|
if (System.currentTimeMillis() - lastFolderClickTime >= DOUBLE_CLICK_INTERVAL) {
|
|
|
|
|
android.util.Log.d(TAG, "Toggling folder expand: " + folderId);
|
|
|
|
|
toggleFolderExpand(folderId);
|
|
|
|
|
}
|
|
|
|
|
}, DOUBLE_CLICK_INTERVAL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 双击检测专用变量(针对文件夹列表项)
|
|
|
|
|
private long lastFolderClickTime = 0;
|
|
|
|
|
private long lastClickedFolderId = -1;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 显示创建文件夹对话框
|
|
|
|
|
*/
|
|
|
|
|
@ -323,7 +364,7 @@ public class SidebarFragment extends Fragment {
|
|
|
|
|
public void onSuccess(Long folderId) {
|
|
|
|
|
if (getActivity() != null) {
|
|
|
|
|
getActivity().runOnUiThread(() -> {
|
|
|
|
|
Toast.makeText(requireContext(), "创建文件夹成功", Toast.LENGTH_SHORT).show();
|
|
|
|
|
Toast.makeText(requireContext(), R.string.create_folder_success, Toast.LENGTH_SHORT).show();
|
|
|
|
|
// 刷新文件夹列表
|
|
|
|
|
viewModel.loadFolderTree();
|
|
|
|
|
});
|
|
|
|
|
@ -334,7 +375,9 @@ public class SidebarFragment extends Fragment {
|
|
|
|
|
public void onError(Exception error) {
|
|
|
|
|
if (getActivity() != null) {
|
|
|
|
|
getActivity().runOnUiThread(() -> {
|
|
|
|
|
Toast.makeText(requireContext(), "创建文件夹失败: " + error.getMessage(), Toast.LENGTH_SHORT).show();
|
|
|
|
|
Toast.makeText(requireContext(),
|
|
|
|
|
getString(R.string.error_folder_name_too_long) + ": " + error.getMessage(),
|
|
|
|
|
Toast.LENGTH_SHORT).show();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -345,82 +388,106 @@ public class SidebarFragment extends Fragment {
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* FolderTreeAdapter
|
|
|
|
|
* 文件夹树适配器,支持层级显示和展开/收起
|
|
|
|
|
*/
|
|
|
|
|
private static class FolderTreeAdapter extends RecyclerView.Adapter<FolderTreeAdapter.FolderViewHolder> {
|
|
|
|
|
/**
|
|
|
|
|
* FolderTreeAdapter
|
|
|
|
|
* 文件夹树适配器,支持层级显示和展开/收起
|
|
|
|
|
*/
|
|
|
|
|
private static class FolderTreeAdapter extends RecyclerView.Adapter<FolderTreeAdapter.FolderViewHolder> {
|
|
|
|
|
|
|
|
|
|
private List<FolderTreeItem> folderItems;
|
|
|
|
|
private FolderListViewModel viewModel;
|
|
|
|
|
private List<FolderTreeItem> folderItems;
|
|
|
|
|
private FolderListViewModel viewModel;
|
|
|
|
|
private OnFolderItemClickListener folderItemClickListener;
|
|
|
|
|
|
|
|
|
|
public FolderTreeAdapter(List<FolderTreeItem> folderItems, FolderListViewModel viewModel) {
|
|
|
|
|
this.folderItems = folderItems;
|
|
|
|
|
this.viewModel = viewModel;
|
|
|
|
|
}
|
|
|
|
|
public FolderTreeAdapter(List<FolderTreeItem> folderItems, FolderListViewModel viewModel) {
|
|
|
|
|
this.folderItems = folderItems;
|
|
|
|
|
this.viewModel = viewModel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setData(List<FolderTreeItem> folderItems) {
|
|
|
|
|
this.folderItems = folderItems;
|
|
|
|
|
}
|
|
|
|
|
public void setData(List<FolderTreeItem> folderItems) {
|
|
|
|
|
this.folderItems = folderItems;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
|
@Override
|
|
|
|
|
public FolderViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
|
|
|
View view = LayoutInflater.from(parent.getContext())
|
|
|
|
|
.inflate(R.layout.sidebar_folder_item, parent, false);
|
|
|
|
|
return new FolderViewHolder(view);
|
|
|
|
|
}
|
|
|
|
|
public void setOnFolderItemClickListener(OnFolderItemClickListener listener) {
|
|
|
|
|
this.folderItemClickListener = listener;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onBindViewHolder(@NonNull FolderViewHolder holder, int position) {
|
|
|
|
|
FolderTreeItem item = folderItems.get(position);
|
|
|
|
|
boolean isExpanded = viewModel != null && viewModel.isFolderExpanded(item.folderId);
|
|
|
|
|
holder.bind(item, isExpanded);
|
|
|
|
|
}
|
|
|
|
|
@NonNull
|
|
|
|
|
@Override
|
|
|
|
|
public FolderViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
|
|
|
View view = LayoutInflater.from(parent.getContext())
|
|
|
|
|
.inflate(R.layout.sidebar_folder_item, parent, false);
|
|
|
|
|
return new FolderViewHolder(view, folderItemClickListener);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int getItemCount() {
|
|
|
|
|
return folderItems.size();
|
|
|
|
|
}
|
|
|
|
|
@Override
|
|
|
|
|
public void onBindViewHolder(@NonNull FolderViewHolder holder, int position) {
|
|
|
|
|
FolderTreeItem item = folderItems.get(position);
|
|
|
|
|
boolean isExpanded = viewModel != null && viewModel.isFolderExpanded(item.folderId);
|
|
|
|
|
holder.bind(item, isExpanded);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static class FolderViewHolder extends RecyclerView.ViewHolder {
|
|
|
|
|
private View indentView;
|
|
|
|
|
private ImageView ivExpandIcon;
|
|
|
|
|
private ImageView ivFolderIcon;
|
|
|
|
|
private TextView tvFolderName;
|
|
|
|
|
private TextView tvNoteCount;
|
|
|
|
|
|
|
|
|
|
public FolderViewHolder(@NonNull View itemView) {
|
|
|
|
|
super(itemView);
|
|
|
|
|
indentView = itemView.findViewById(R.id.indent_view);
|
|
|
|
|
ivExpandIcon = itemView.findViewById(R.id.iv_expand_icon);
|
|
|
|
|
ivFolderIcon = itemView.findViewById(R.id.iv_folder_icon);
|
|
|
|
|
tvFolderName = itemView.findViewById(R.id.tv_folder_name);
|
|
|
|
|
tvNoteCount = itemView.findViewById(R.id.tv_note_count);
|
|
|
|
|
@Override
|
|
|
|
|
public int getItemCount() {
|
|
|
|
|
return folderItems.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void bind(FolderTreeItem item, boolean isExpanded) {
|
|
|
|
|
// 设置缩进
|
|
|
|
|
int indent = item.level * 32;
|
|
|
|
|
indentView.setLayoutParams(new LinearLayout.LayoutParams(indent, LinearLayout.LayoutParams.MATCH_PARENT));
|
|
|
|
|
|
|
|
|
|
// 设置展开/收起图标
|
|
|
|
|
if (item.hasChildren) {
|
|
|
|
|
ivExpandIcon.setVisibility(View.VISIBLE);
|
|
|
|
|
ivExpandIcon.setRotation(isExpanded ? 90 : 0);
|
|
|
|
|
} else {
|
|
|
|
|
ivExpandIcon.setVisibility(View.INVISIBLE);
|
|
|
|
|
static class FolderViewHolder extends RecyclerView.ViewHolder {
|
|
|
|
|
private View indentView;
|
|
|
|
|
private ImageView ivExpandIcon;
|
|
|
|
|
private ImageView ivFolderIcon;
|
|
|
|
|
private TextView tvFolderName;
|
|
|
|
|
private TextView tvNoteCount;
|
|
|
|
|
private FolderTreeItem currentItem;
|
|
|
|
|
private final OnFolderItemClickListener folderItemClickListener;
|
|
|
|
|
|
|
|
|
|
public FolderViewHolder(@NonNull View itemView, OnFolderItemClickListener listener) {
|
|
|
|
|
super(itemView);
|
|
|
|
|
this.folderItemClickListener = listener;
|
|
|
|
|
indentView = itemView.findViewById(R.id.indent_view);
|
|
|
|
|
ivExpandIcon = itemView.findViewById(R.id.iv_expand_icon);
|
|
|
|
|
ivFolderIcon = itemView.findViewById(R.id.iv_folder_icon);
|
|
|
|
|
tvFolderName = itemView.findViewById(R.id.tv_folder_name);
|
|
|
|
|
tvNoteCount = itemView.findViewById(R.id.tv_note_count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置文件夹名称
|
|
|
|
|
tvFolderName.setText(item.name);
|
|
|
|
|
public void bind(FolderTreeItem item, boolean isExpanded) {
|
|
|
|
|
this.currentItem = item;
|
|
|
|
|
|
|
|
|
|
// 设置缩进
|
|
|
|
|
int indent = item.level * 32;
|
|
|
|
|
indentView.setLayoutParams(new LinearLayout.LayoutParams(indent, LinearLayout.LayoutParams.MATCH_PARENT));
|
|
|
|
|
|
|
|
|
|
// 设置展开/收起图标
|
|
|
|
|
if (item.hasChildren) {
|
|
|
|
|
ivExpandIcon.setVisibility(View.VISIBLE);
|
|
|
|
|
ivExpandIcon.setRotation(isExpanded ? 90 : 0);
|
|
|
|
|
} else {
|
|
|
|
|
ivExpandIcon.setVisibility(View.INVISIBLE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置文件夹名称
|
|
|
|
|
tvFolderName.setText(item.name);
|
|
|
|
|
|
|
|
|
|
// 设置便签数量
|
|
|
|
|
tvNoteCount.setText(String.format(itemView.getContext()
|
|
|
|
|
.getString(R.string.folder_note_count), item.noteCount));
|
|
|
|
|
|
|
|
|
|
// 设置便签数量
|
|
|
|
|
tvNoteCount.setText(String.format(itemView.getContext()
|
|
|
|
|
.getString(R.string.folder_note_count), item.noteCount));
|
|
|
|
|
// 设置点击监听器
|
|
|
|
|
itemView.setOnClickListener(v -> {
|
|
|
|
|
if (folderItemClickListener != null) {
|
|
|
|
|
folderItemClickListener.onFolderClick(item.folderId);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 文件夹项点击监听器接口
|
|
|
|
|
*/
|
|
|
|
|
public interface OnFolderItemClickListener {
|
|
|
|
|
void onFolderClick(long folderId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* FolderTreeItem
|
|
|
|
|
|