diff --git a/app/build.gradle b/app/build.gradle index 5a72c0f..f078951 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,4 +38,10 @@ dependencies { androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' implementation 'com.alibaba:fastjson:1.2.68' + + def room_version = "2.2.6" + + implementation "androidx.room:room-runtime:$room_version" + annotationProcessor "androidx.room:room-compiler:$room_version" + } \ No newline at end of file diff --git a/app/src/main/java/com/yutou/passmanage/Adapters/PassWordListAdapter.java b/app/src/main/java/com/yutou/passmanage/Adapters/PassWordListAdapter.java index d0a2241..70929e2 100644 --- a/app/src/main/java/com/yutou/passmanage/Adapters/PassWordListAdapter.java +++ b/app/src/main/java/com/yutou/passmanage/Adapters/PassWordListAdapter.java @@ -1,71 +1,209 @@ package com.yutou.passmanage.Adapters; +import android.annotation.SuppressLint; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.content.DialogInterface; +import android.os.Handler; +import android.os.Looper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.EditText; import android.widget.ImageButton; +import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; import androidx.recyclerview.widget.RecyclerView; -import com.yutou.passmanage.Datas.PassWordData; +import com.alibaba.fastjson.JSONObject; +import com.yutou.passmanage.Datas.ToolsPassword; +import com.yutou.passmanage.Datas.ToolsPasswordDao; +import com.yutou.passmanage.Interfaces.NetworkInterface; import com.yutou.passmanage.R; +import com.yutou.passmanage.Tools.NetworkTool; +import com.yutou.passmanage.Tools.RoomDatabaseManager; import java.util.List; +import static com.yutou.passmanage.Tools.RoomDatabaseManager.addPassword; + public class PassWordListAdapter extends RecyclerView.Adapter { private Context context; - private List list; + private List list; + ToolsPasswordDao dao; - public PassWordListAdapter(Context context, List list) { + public PassWordListAdapter(Context context, List list) { this.context = context; this.list = list; + this.dao = RoomDatabaseManager.build(context).passwordDao(); + } + + public void setList(List list) { + this.list = list; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.recycler_list,parent,false)); + return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.recycler_list, parent, false)); } + @SuppressLint("SetTextI18n") @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { - PassWordData data=list.get(position); - holder.name.setText(data.getName()); - holder.user.setText(data.getUser()); - holder.password.setText(data.getPassword()); + ToolsPassword data = list.get(position); + holder.name.setText(data.getTitle()); + holder.user.setText("账号:" + data.getAccount()); + holder.password.setText("密码:" + data.getPassword()); holder.copy.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - ClipboardManager clipboard = (ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE); + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("simple text", data.getPassword()); clipboard.setPrimaryClip(clip); + Toast.makeText(context, "已复制密码", Toast.LENGTH_LONG).show(); + } + }); + holder.item_layout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showDialog(data); } }); } + AlertDialog removeDialog = null; + + private void showDialog(ToolsPassword data) { + View view = LayoutInflater.from(context.getApplicationContext()).inflate(R.layout.dialog_add_passworld, null); + Button delete = view.findViewById(R.id.delete); + EditText title, account, password; + title = view.findViewById(R.id.title); + account = view.findViewById(R.id.account); + password = view.findViewById(R.id.myPassword); + title.setText(data.getTitle()); + account.setText(data.getAccount()); + password.setText(data.getPassword()); + delete.setVisibility(View.VISIBLE); + delete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AlertDialog dialog = new AlertDialog.Builder(context) + .setTitle("确认删除操作") + .setMessage("确定删除这条密码吗?本操作不可反悔") + .setPositiveButton("删除", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + JSONObject json = new JSONObject(); + json.put("id", data.getId()); + NetworkTool.httpPost(NetworkTool.NetworkAPI.PASSWORD_REMOVE, json, new NetworkInterface() { + @Override + public void httpGetData(Object data, int state) { + remove(false); + } + + @Override + public void httpError(Exception e) { + remove(true); + } + + void remove(boolean isError) { + new Thread(() -> { + if (isError) { + data.setRemove(true); + dao.update(data); + } else { + dao.delete(data); + } + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(() -> { + dialog.dismiss(); + Toast.makeText(context, "删除成功", Toast.LENGTH_LONG).show(); + notifyDataSetChanged(); + }); + }).start(); + + } + }); + dialog.dismiss(); + } + }) + .setNegativeButton("取消", (dialog13, which) -> dialog13.dismiss()).create(); + dialog.show(); + } + }); + removeDialog = new AlertDialog.Builder(context) + .setTitle("查看信息") + .setView(view) + .setPositiveButton("更新", (dialog1, which) -> { + addPassword(title.getText().toString(), account.getText().toString(), password.getText().toString(), data.getId(), false, new NetworkInterface() { + @Override + public void httpGetData(Object data, int state) { + addDatabase(title.getText().toString(), + account.getText().toString(), + password.getText().toString(), + true); + } + + @Override + public void httpError(Exception e) { + addDatabase(title.getText().toString(), + account.getText().toString(), + password.getText().toString(), + false); + } + + void addDatabase(String title1, String account1, String password1, boolean upload) { + new Thread(() -> { + data.setTitle(title1); + data.setPassword(password1); + data.setUpload(upload); + dao.update(data); + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(new Runnable() { + @Override + public void run() { + Toast.makeText(context, "更新成功", Toast.LENGTH_LONG).show(); + notifyDataSetChanged(); + } + }); + }).start(); + + } + }); + dialog1.dismiss(); + }) + .setNegativeButton("取消", (dialog12, which) -> dialog12.dismiss()).create(); + removeDialog.show(); + } + @Override public int getItemCount() { return list.size(); } - public static class MyViewHolder extends RecyclerView.ViewHolder{ + + public static class MyViewHolder extends RecyclerView.ViewHolder { ImageButton icon; - TextView name,user,password; + TextView name, user, password; Button copy; + LinearLayout item_layout; public MyViewHolder(@NonNull View itemView) { super(itemView); - icon=itemView.findViewById(R.id.icon); - name=itemView.findViewById(R.id.name); - user=itemView.findViewById(R.id.user); - password=itemView.findViewById(R.id.password); - copy=itemView.findViewById(R.id.copy); + icon = itemView.findViewById(R.id.icon); + name = itemView.findViewById(R.id.name); + user = itemView.findViewById(R.id.user); + password = itemView.findViewById(R.id.password); + copy = itemView.findViewById(R.id.copy); + item_layout = itemView.findViewById(R.id.item_layout); } + } } diff --git a/app/src/main/java/com/yutou/passmanage/Datas/ToolsPassword.java b/app/src/main/java/com/yutou/passmanage/Datas/ToolsPassword.java index 46f8724..6ac4261 100644 --- a/app/src/main/java/com/yutou/passmanage/Datas/ToolsPassword.java +++ b/app/src/main/java/com/yutou/passmanage/Datas/ToolsPassword.java @@ -1,26 +1,37 @@ package com.yutou.passmanage.Datas; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.Ignore; +import androidx.room.PrimaryKey; + /** * tools_password * @author */ +@Entity public class ToolsPassword{ + @PrimaryKey private Integer id; - + @ColumnInfo private String title; - - private String username; - + @ColumnInfo + private String account; + @ColumnInfo private String password; - + @Ignore private String url; - + @Ignore private String info; - + @ColumnInfo private Integer type; - + @Ignore private Integer uid; + @ColumnInfo + private boolean upload; + @ColumnInfo + private boolean remove; public Integer getId() { return id; @@ -38,12 +49,12 @@ public class ToolsPassword{ this.title = title; } - public String getUsername() { - return username; + public String getAccount() { + return account; } - public void setUsername(String username) { - this.username = username; + public void setAccount(String account) { + this.account = account; } public String getPassword() { @@ -85,4 +96,20 @@ public class ToolsPassword{ public void setUid(Integer uid) { this.uid = uid; } + + public boolean isUpload() { + return upload; + } + + public void setUpload(boolean upload) { + this.upload = upload; + } + + public boolean isRemove() { + return remove; + } + + public void setRemove(boolean remove) { + this.remove = remove; + } } \ No newline at end of file diff --git a/app/src/main/java/com/yutou/passmanage/Datas/ToolsPasswordDao.java b/app/src/main/java/com/yutou/passmanage/Datas/ToolsPasswordDao.java new file mode 100644 index 0000000..8597ea8 --- /dev/null +++ b/app/src/main/java/com/yutou/passmanage/Datas/ToolsPasswordDao.java @@ -0,0 +1,27 @@ +package com.yutou.passmanage.Datas; + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.Query; +import androidx.room.Update; + +import java.util.List; + +@Dao +public interface ToolsPasswordDao { + @Query("select * from ToolsPassword") + List getAll(); + @Query("select * from ToolsPassword where title=:title and account=:account and password=:password") + ToolsPassword isExist(String title,String account,String password); + @Query("select * from ToolsPassword where title like :title and remove=0") + List queryPassword(String title); + @Insert + void insert(ToolsPassword password); + @Insert + void insertAll(List list); + @Delete + void delete(ToolsPassword password); + @Update + void update(ToolsPassword password); +} diff --git a/app/src/main/java/com/yutou/passmanage/MainActivity.java b/app/src/main/java/com/yutou/passmanage/MainActivity.java index 7560c06..7412291 100644 --- a/app/src/main/java/com/yutou/passmanage/MainActivity.java +++ b/app/src/main/java/com/yutou/passmanage/MainActivity.java @@ -2,34 +2,53 @@ package com.yutou.passmanage; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.content.DialogInterface; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; import android.widget.EditText; import android.widget.ImageButton; +import android.widget.MultiAutoCompleteTextView; +import android.widget.TextView; import android.widget.Toast; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.yutou.passmanage.Adapters.PassWordListAdapter; import com.yutou.passmanage.Datas.AppData; import com.yutou.passmanage.Datas.ToolsPassword; +import com.yutou.passmanage.Datas.ToolsPasswordDao; import com.yutou.passmanage.Interfaces.NetworkInterface; import com.yutou.passmanage.Tools.NetworkTool; +import com.yutou.passmanage.Tools.RoomDatabaseManager; import com.yutou.passmanage.Tools.Tools; +import java.util.ArrayList; import java.util.List; +import static com.yutou.passmanage.Tools.RoomDatabaseManager.addPassword; + public class MainActivity extends AppCompatActivity { EditText search; ImageButton clearSearch; RecyclerView passList; FloatingActionButton floatButton; + PassWordListAdapter adapter; + Handler handler = new Handler(Looper.getMainLooper()); @Override protected void onCreate(Bundle savedInstanceState) { @@ -40,80 +59,209 @@ public class MainActivity extends AppCompatActivity { } void initView() { + dao = RoomDatabaseManager.build(this).passwordDao(); + adapter = new PassWordListAdapter(this, new ArrayList<>()); search = findViewById(R.id.search); clearSearch = findViewById(R.id.clearSearch); passList = findViewById(R.id.passList); floatButton = findViewById(R.id.floatButton); - floatButton.setOnClickListener(new View.OnClickListener() { + floatButton.setOnClickListener(v -> showAddPasswordDialog()); + passList.setLayoutManager(new LinearLayoutManager(this)); + passList.setAdapter(adapter); + clearSearch.setOnClickListener(v -> { + search.setText(""); + new Thread(this::showData).start(); + }); + search.addTextChangedListener(new TextWatcher() { @Override - public void onClick(View v) { - View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.dialog_add_passworld, null); - AlertDialog dialog = new AlertDialog.Builder(MainActivity.this) - .setTitle("添加账号") - .setView(view) - .setPositiveButton("保存", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }) - .setNegativeButton("取消", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + new Thread(() -> { + List list; + if (Tools.isEmpty(s.toString())) { + list = dao.getAll(); + } else { + list = dao.queryPassword("%" + s.toString() + "%"); + } + handler.post(() -> { + adapter.setList(list); + adapter.notifyDataSetChanged(); + }); + }).start(); + } + + @Override + public void afterTextChanged(Editable s) { - } - }).create(); - dialog.show(); } }); } + void showAddPasswordDialog() { + View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.dialog_add_passworld, null); + EditText title, account, password; + title = view.findViewById(R.id.title); + account = view.findViewById(R.id.account); + password = view.findViewById(R.id.myPassword); + AlertDialog dialog = new AlertDialog.Builder(MainActivity.this) + .setTitle("添加账号") + .setView(view) + .setPositiveButton("保存", (dialog1, which) -> { + addPassword(title.getText().toString(), account.getText().toString(), password.getText().toString(), -1, true, new NetworkInterface() { + @Override + public void httpGetData(Object data, int state) { + addDatabase(title.getText().toString(), + account.getText().toString(), + password.getText().toString(), + true); + } + + @Override + public void httpError(Exception e) { + addDatabase(title.getText().toString(), + account.getText().toString(), + password.getText().toString(), + false); + } + + void addDatabase(String title1, String account1, String password1, boolean upload) { + new Thread(() -> { + ToolsPassword psd = new ToolsPassword(); + psd.setTitle(title1); + psd.setAccount(account1); + psd.setPassword(password1); + psd.setUpload(upload); + dao.insert(psd); + showData(); + }).start(); + + } + }); + dialog1.dismiss(); + }) + .setNegativeButton("取消", (dialog12, which) -> dialog12.dismiss()).create(); + dialog.show(); + } + + void init() { AppData.key = Tools.getConfig("key", this); + AppData.key = "6B059119-C8F6-4E19-A8F0-71801D776A1F"; if (Tools.isEmpty(AppData.key)) { EditText key = new EditText(this); key.setHint("激活码"); AlertDialog dialog = new AlertDialog.Builder(this) .setTitle("输入激活码") .setView(key) - .setPositiveButton("确定", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String k = key.getText().toString().trim(); - if (Tools.isEmpty(k)) { - Toast.makeText(MainActivity.this, "激活码不能为空", Toast.LENGTH_LONG).show(); - return; - } - Tools.setConfig("key", k, MainActivity.this); - AppData.key = k; - dialog.dismiss(); - initData(); + .setPositiveButton("确定", (dialog1, which) -> { + String k = key.getText().toString().trim(); + if (Tools.isEmpty(k)) { + Toast.makeText(MainActivity.this, "激活码不能为空", Toast.LENGTH_LONG).show(); + return; } + Tools.setConfig("key", k, MainActivity.this); + AppData.key = k; + dialog1.dismiss(); + initData(); }).create(); dialog.show(); - }else{ + } else { initData(); } } - void initData(){ - NetworkTool.httpGet(NetworkTool.NetworkAPI.PASSWORD_ALL, new JSONObject(), new NetworkInterface() { - @Override - public void httpGetData(Object data, int state) { - JSONObject json=JSONObject.parseObject((String) data); - if(json.getInteger("code")==0){ - List list= JSONArray.parseArray(json.getJSONArray("data").toJSONString(),ToolsPassword.class); - showData(list); + + ToolsPasswordDao dao; + + void initData() { + new Thread(() -> { + List list = dao.getAll(); + for (ToolsPassword password : list) { + System.out.println(JSONObject.toJSONString(password)); + if (!password.isUpload()&&!password.isRemove()) { + addPassword(password.getTitle(), password.getAccount(), password.getPassword(), -1, true, new NetworkInterface() { + @Override + public void httpGetData(Object data, int state) { + new Thread(() -> { + password.setUpload(true); + dao.update(password); + }).start(); + + } + + @Override + public void httpError(Exception e) { + + } + }); + }else if(password.isRemove()){ + JSONObject json = new JSONObject(); + json.put("id", password.getId()); + NetworkTool.httpPost(NetworkTool.NetworkAPI.PASSWORD_REMOVE, json, new NetworkInterface() { + @Override + public void httpGetData(Object data, int state) { + remove(false); + } + + @Override + public void httpError(Exception e) { + remove(true); + } + + void remove(boolean isError) { + new Thread(new Runnable() { + @Override + public void run() { + if (isError) { + password.setRemove(true); + dao.update(password); + } else { + dao.delete(password); + } + } + }).start(); + + } + }); } } - @Override - public void httpError(Exception e) { + NetworkTool.httpGet(NetworkTool.NetworkAPI.PASSWORD_ALL, new JSONObject(), new NetworkInterface() { + @Override + public void httpGetData(Object data, int state) { + JSONObject json = JSONObject.parseObject((String) data); + if (json.getInteger("code") == 0) { + List list = JSONArray.parseArray(json.getJSONArray("data").toJSONString(), ToolsPassword.class); + new Thread(() -> { + for (ToolsPassword password : list) { + if (dao.isExist(password.getTitle(), password.getAccount(), password.getPassword()) == null) { + password.setUpload(true); + dao.insert(password); + } + } + showData(); + }).start(); + } + } - } + @Override + public void httpError(Exception e) { + new Thread(() -> showData()).start(); + } + }); + + }).start(); + + } + + void showData() { + List list = dao.getAll(); + handler.post(() -> { + adapter.setList(list); + adapter.notifyDataSetChanged(); }); } - void showData(List list){ - - } } \ No newline at end of file diff --git a/app/src/main/java/com/yutou/passmanage/Tools/NetworkTool.java b/app/src/main/java/com/yutou/passmanage/Tools/NetworkTool.java index f991bbd..e4e9937 100644 --- a/app/src/main/java/com/yutou/passmanage/Tools/NetworkTool.java +++ b/app/src/main/java/com/yutou/passmanage/Tools/NetworkTool.java @@ -37,6 +37,7 @@ public class NetworkTool { public static String PASSWORD_ALL = HOME + "get/all.do"; public static String PASSWORD_ADD = HOME + "set/add.do"; public static String PASSWORD_UPDATE = HOME + "set/update.do"; + public static String PASSWORD_REMOVE = HOME + "set/remove.do"; public static String PASSWORD_TYPE_ALL = HOME + "type/get/list.do"; public static String PASSWORD_TYPE_ADD = HOME + "type/set/add.do"; @@ -142,14 +143,13 @@ public class NetworkTool { connection.setReadTimeout(10 * 1000); //connection.addRequestProperty("Connection", "keep-alive"); //connection.addRequestProperty("User-Agent", getExtUa()); - connection.addRequestProperty("content-type", "application/json"); + // connection.addRequestProperty("content-type", "application/json"); connection.addRequestProperty("charset", "UTF-8"); OutputStream outputStream = connection.getOutputStream(); - outputStream.write(body.toJSONString().getBytes()); + outputStream.write(toGetSplice(body).getBytes()); outputStream.flush(); outputStream.close(); - System.out.println(connection.getResponseCode()); BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); while ((tmp = reader.readLine()) != null) { str.append(tmp); diff --git a/app/src/main/java/com/yutou/passmanage/Tools/RoomDatabaseManager.java b/app/src/main/java/com/yutou/passmanage/Tools/RoomDatabaseManager.java new file mode 100644 index 0000000..74ed111 --- /dev/null +++ b/app/src/main/java/com/yutou/passmanage/Tools/RoomDatabaseManager.java @@ -0,0 +1,59 @@ +package com.yutou.passmanage.Tools; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.room.Database; +import androidx.room.DatabaseConfiguration; +import androidx.room.InvalidationTracker; +import androidx.room.Room; +import androidx.room.RoomDatabase; +import androidx.sqlite.db.SupportSQLiteOpenHelper; + +import com.alibaba.fastjson.JSONObject; +import com.yutou.passmanage.Datas.ToolsPassword; +import com.yutou.passmanage.Datas.ToolsPasswordDao; +import com.yutou.passmanage.Interfaces.NetworkInterface; + +@Database(entities = {ToolsPassword.class}, version = 1,exportSchema = false) +public abstract class RoomDatabaseManager extends RoomDatabase { + public abstract ToolsPasswordDao passwordDao(); + + @NonNull + @Override + protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config) { + return null; + } + + @NonNull + @Override + protected InvalidationTracker createInvalidationTracker() { + return null; + } + + @Override + public void clearAllTables() { + + } + + public static RoomDatabaseManager build(Context context) { + return Room.databaseBuilder(context.getApplicationContext(), RoomDatabaseManager.class, "password.db").build(); + } + public static void addPassword(String title, String account, String password,int id,boolean isAdd, NetworkInterface networkInterface) { + JSONObject json = new JSONObject(); + json.put("title", title); + json.put("username", account); + json.put("password", password); + json.put("url", ""); + json.put("info", ""); + json.put("type", "-1"); + if(id!=-1){ + json.put("id",id); + } + if(isAdd) { + NetworkTool.httpPost(NetworkTool.NetworkAPI.PASSWORD_ADD, json, networkInterface); + }else{ + NetworkTool.httpPost(NetworkTool.NetworkAPI.PASSWORD_UPDATE, json, networkInterface); + } + } +} diff --git a/app/src/main/res/layout/dialog_add_passworld.xml b/app/src/main/res/layout/dialog_add_passworld.xml index f6128f4..5fcd6c2 100644 --- a/app/src/main/res/layout/dialog_add_passworld.xml +++ b/app/src/main/res/layout/dialog_add_passworld.xml @@ -16,14 +16,16 @@ android:layout_gravity="center" android:layout_marginStart="20dp" android:layout_weight="1" - android:text="对应软件" /> + android:text="名字" /> - + @@ -41,7 +43,7 @@ android:text="账号" /> + +