diff --git a/src/Notes-master/src/net/micode/notes/ui/ChatFragment.java b/src/Notes-master/src/net/micode/notes/ui/ChatFragment.java new file mode 100644 index 0000000..60aa21e --- /dev/null +++ b/src/Notes-master/src/net/micode/notes/ui/ChatFragment.java @@ -0,0 +1,49 @@ +package net.micode.notes.ui; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import net.micode.notes.R; +import net.micode.notes.model.ChatMessage; +import java.util.ArrayList; +import java.util.List; + +public class ChatFragment extends Fragment { + private RecyclerView mRecyclerView; + private ChatAdapter mAdapter; + private List mMessages = new ArrayList<>(); + private EditText mInput; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_chat, container, false); + mRecyclerView = view.findViewById(R.id.rv_chat_list); + mInput = view.findViewById(R.id.et_chat_input); + + mAdapter = new ChatAdapter(mMessages); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + mRecyclerView.setAdapter(mAdapter); + + view.findViewById(R.id.btn_chat_send).setOnClickListener(v -> { + String text = mInput.getText().toString().trim(); + if (!text.isEmpty()) { + // 1. 本地插入用户消息 + ChatMessage userMsg = new ChatMessage(0, 0, text); + mMessages.add(userMsg); + mAdapter.notifyItemInserted(mMessages.size() - 1); + mRecyclerView.smoothScrollToPosition(mMessages.size() - 1); + mInput.setText(""); + + // TODO: Step 3 将在此处调用 CozeClient + } + }); + + return view; + } +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java b/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java index ae8108f..9928b28 100644 --- a/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java +++ b/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java @@ -67,6 +67,7 @@ import android.graphics.drawable.Drawable; // [新增] 修复错误 3 & 4 import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.view.ActionMode; import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; import net.micode.notes.tool.DataUtils.AppWidgetAttribute; @@ -329,12 +330,6 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe super.onResume(); applyCustomBackground(); updateViewMode(); - - // [新增] 触发一次性的异步同步任务 - androidx.work.OneTimeWorkRequest syncRequest = - new androidx.work.OneTimeWorkRequest.Builder(net.micode.notes.sync.SyncWorker.class) - .build(); - androidx.work.WorkManager.getInstance(this).enqueue(syncRequest); } private void applyCustomBackground() { @@ -510,9 +505,13 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe } } else if (itemId == R.id.nav_ai) { - // --- AI 助手(预留) --- findViewById(R.id.fragment_container).setVisibility(View.VISIBLE); if (getSupportActionBar() != null) getSupportActionBar().setTitle("AI 助理"); + + Fragment chatFrag = fm.findFragmentByTag("CHAT"); + if (chatFrag == null) { + ft.replace(R.id.fragment_container, new ChatFragment(), "CHAT"); + } } // 使用 commitAllowingStateLoss 彻底杜绝由于异步同步导致的 Activity 状态丢失闪退 @@ -1389,10 +1388,7 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe // 移除之前的 menu.clear(),因为这会清空 onCreate 加载的内容 // 仅保留原有的动态逻辑,例如同步按钮的状态切换 if (mState == ListEditState.NOTE_LIST) { - MenuItem syncItem = menu.findItem(R.id.menu_sync); - if (syncItem != null) { - syncItem.setTitle(R.string.menu_sync); // 始终显示“同步” - } + } else if (mState == ListEditState.SUB_FOLDER) { menu.clear(); // 子文件夹模式下可能需要清除并重新加载 getMenuInflater().inflate(R.menu.sub_folder, menu); @@ -1407,6 +1403,9 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe @Override public boolean onOptionsItemSelected(MenuItem item) { + androidx.work.Data inputData; + androidx.work.OneTimeWorkRequest syncRequest; + switch (item.getItemId()) { case R.id.menu_new_folder: { showCreateOrModifyFolderDialog(true); @@ -1416,18 +1415,47 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe exportNoteToText(); break; } - case R.id.menu_sync: - // [新增] 弹出提示,告知用户正在同步 - Toast.makeText(this, "正在同步云端便签...", Toast.LENGTH_SHORT).show(); - - // [核心] 触发 WorkManager 立即执行同步 - androidx.work.OneTimeWorkRequest syncRequest = - new androidx.work.OneTimeWorkRequest.Builder(net.micode.notes.sync.SyncWorker.class) - .build(); + // [修改] 处理 Pull (原 Sync) + case R.id.menu_pull: + Toast.makeText(this, "正在从云端拉取数据...", Toast.LENGTH_SHORT).show(); + // 1. 构造参数 + inputData = new androidx.work.Data.Builder() + .putInt(net.micode.notes.sync.SyncWorker.KEY_SYNC_MODE, net.micode.notes.sync.SyncWorker.MODE_PULL) + .build(); + // 2. 构建请求 + syncRequest = new androidx.work.OneTimeWorkRequest.Builder(net.micode.notes.sync.SyncWorker.class) + .setInputData(inputData) + .build(); + // 3. 提交任务 androidx.work.WorkManager.getInstance(this).enqueue(syncRequest); + // [核心修改]:删除原来的 startAsyncNotesListQuery(); + // 改为监听任务状态,只有当任务 SUCCEEDED (成功) 时才刷新列表 + androidx.work.WorkManager.getInstance(this).getWorkInfoByIdLiveData(syncRequest.getId()) + .observe(this, new androidx.lifecycle.Observer() { + @Override + public void onChanged(androidx.work.WorkInfo workInfo) { + if (workInfo != null && workInfo.getState() == androidx.work.WorkInfo.State.SUCCEEDED) { + // 任务真正结束,且数据已入库,此时刷新界面 + startAsyncNotesListQuery(); + Toast.makeText(NotesListActivity.this, "拉取完成", Toast.LENGTH_SHORT).show(); + } + } + }); + break; + // [新增] 处理 Push + case R.id.menu_push: + Toast.makeText(this, "正在上传数据到云端...", Toast.LENGTH_SHORT).show(); - // 刷新列表显示 - startAsyncNotesListQuery(); + // 构造参数:MODE_PUSH + inputData = new androidx.work.Data.Builder() + .putInt(net.micode.notes.sync.SyncWorker.KEY_SYNC_MODE, net.micode.notes.sync.SyncWorker.MODE_PUSH) + .build(); + + syncRequest = new androidx.work.OneTimeWorkRequest.Builder(net.micode.notes.sync.SyncWorker.class) + .setInputData(inputData) + .build(); + + androidx.work.WorkManager.getInstance(this).enqueue(syncRequest); break; case R.id.menu_setting: { startPreferenceActivity();