新增了分类

然后不知道改了啥
This commit is contained in:
zlzw 2024-08-28 17:52:31 +08:00
parent 9e889a2f14
commit de339d31f7
42 changed files with 1356 additions and 343 deletions

View File

@ -3,13 +3,10 @@ apply plugin: 'kotlin-android'
android {
compileSdkVersion 33
buildToolsVersion "30.0.2"
defaultConfig {
minSdkVersion 28
targetSdkVersion 33
versionCode 1
versionName "1.2"
consumerProguardFiles 'consumer-rules.pro'
}
@ -20,6 +17,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
namespace 'com.angcyo.tablayout'
}
dependencies {

View File

@ -1,2 +1 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.angcyo.tablayout" />
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />

View File

@ -3,13 +3,10 @@ apply plugin: 'kotlin-android'
android {
compileSdkVersion 33
buildToolsVersion "30.0.2"
defaultConfig {
minSdkVersion 28
targetSdkVersion 33
versionCode 1
versionName "1.2"
consumerProguardFiles 'consumer-rules.pro'
}
@ -20,6 +17,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
namespace 'com.angcyo.tablayout.delegate2'
}

View File

@ -1,2 +1 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.angcyo.tablayout.delegate2" />
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />

View File

@ -17,15 +17,14 @@ android {
keyPassword '34864394'
}
}
compileSdkVersion 33
buildToolsVersion "30.0.2"
compileSdkVersion 34
defaultConfig {
applicationId "com.yutou.passmanage"
minSdkVersion 28
targetSdkVersion 33
targetSdkVersion 34
versionCode 1
versionName "1.2"
versionName "1.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
signingConfig signingConfigs.yutou
@ -41,24 +40,35 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
namespace 'com.yutou.passmanage'
buildFeatures {
viewBinding true
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'com.google.android.material:material:1.12.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment:2.7.7'
implementation 'androidx.navigation:navigation-ui:2.7.7'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.8.4'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
implementation 'com.alibaba:fastjson:1.2.68'
implementation 'com.alibaba.fastjson2:fastjson2:2.0.52'
def room_version = "2.2.6"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-runtime:2.6.1"
annotationProcessor "androidx.room:room-compiler:2.6.1"
implementation "androidx.biometric:biometric:1.1.0"
implementation 'com.squareup.okhttp3:okhttp:3.14.9'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
api project(path:':TabLayout')
api project(path:':ViewPager2Delegate')
api project(path:':netlibs')
}

View File

@ -1,18 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yutou.passmanage">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.INTERNET"/>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/app_icon"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/Theme.MyPassworldManage">
<activity android:name=".MainActivity"
android:exported="true">
android:theme="@style/Theme.MyPassworldManage"
android:usesCleartextTraffic="true" >
<activity
android:name=".MainActivity"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@ -21,14 +21,17 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.netlibs.http.HttpCallback;
import com.yutou.passmanage.Datas.ToolsPassword;
import com.yutou.passmanage.Datas.ToolsPasswordDao;
import com.yutou.passmanage.Interfaces.NetworkInterface;
import com.yutou.passmanage.NetUtils.NetTools;
import com.yutou.passmanage.R;
import com.yutou.passmanage.Tools.NetworkTool;
import com.yutou.passmanage.Tools.ResTools;
import com.yutou.passmanage.Tools.RoomDatabaseManager;
import com.yutou.passmanage.bean.BaseBean;
import java.util.List;
@ -58,8 +61,8 @@ public class PassWordListAdapter extends RecyclerView.Adapter<PassWordListAdapte
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
ToolsPassword data = list.get(holder.getAdapterPosition());
String account=ResTools.getString(context,R.string.account)+":"+ data.getAccount();
String password=ResTools.getString(context,R.string.password)+":"+data.getPassword();
String account = ResTools.getString(context, R.string.account) + ":" + data.getAccount();
String password = ResTools.getString(context, R.string.password) + ":" + data.getPassword();
holder.name.setText(data.getTitle());
holder.user.setText(account);
holder.password.setText(password);
@ -69,13 +72,45 @@ public class PassWordListAdapter extends RecyclerView.Adapter<PassWordListAdapte
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("", data.getPassword());
clipboard.setPrimaryClip(clip);
Toast.makeText(context, ResTools.getString(context,R.string.toast_copy_password), Toast.LENGTH_LONG).show();
Toast.makeText(context, ResTools.getString(context, R.string.toast_copy_password), Toast.LENGTH_LONG).show();
}
});
holder.item_layout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDialog(data, holder.getAdapterPosition());
NetTools.getApi().getPassword(data.getId()).enqueue(new HttpCallback<String>() {
@Override
public void onResponse(int code, String status, String response) {
data.setPassword(response);
showDialog(data, holder.getAdapterPosition());
save(data);
}
@Override
public void onFailure(Throwable throwable) {
new Thread(() -> {
ToolsPassword queried = dao.queryPassword(data.getId());
if (queried != null) {
new Handler(Looper.getMainLooper())
.post(() -> showDialog(data, holder.getAdapterPosition()));
}
}).start();
}
public void save(ToolsPassword pwd) {
new Thread(new Runnable() {
@Override
public void run() {
ToolsPassword queried = dao.queryPassword(pwd.getId());
if (queried == null) {
dao.insert(pwd);
} else {
dao.update(pwd);
}
}
}).start();
}
});
}
});
@ -86,11 +121,11 @@ public class PassWordListAdapter extends RecyclerView.Adapter<PassWordListAdapte
private void showDialog(ToolsPassword data, int position) {
View view = LayoutInflater.from(context.getApplicationContext()).inflate(R.layout.dialog_add_passworld, null);
Button delete = view.findViewById(R.id.delete);
EditText title, account, password,info;
EditText title, account, password, info;
title = view.findViewById(R.id.title);
account = view.findViewById(R.id.account);
password = view.findViewById(R.id.myPassword);
info=view.findViewById(R.id.info);
info = view.findViewById(R.id.info);
title.setText(data.getTitle());
account.setText(data.getAccount());
password.setText(data.getPassword());
@ -105,40 +140,36 @@ public class PassWordListAdapter extends RecyclerView.Adapter<PassWordListAdapte
.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() {
NetTools.getApi().removePassword(data.getId()).enqueue(new HttpCallback<BaseBean>() {
@Override
public void httpGetData(Object data, int state) {
public void onResponse(int code, String status, BaseBean response) {
remove(false);
}
@Override
public void httpError(Exception e) {
public void onFailure(Throwable throwable) {
remove(true);
}
void remove(boolean isError) {
new Thread(() -> {
if (isError) {
if (data.isUpload()) {
data.setRemove(true);
dao.update(data);
} else {
dao.delete(data);
}
if (isError) {
if (data.isUpload()) {
data.setRemove(true);
dao.update(data);
} else {
dao.delete(data);
}
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> {
dialog.dismiss();
removeDialog.dismiss();
Toast.makeText(context, "删除成功", Toast.LENGTH_LONG).show();
list.remove(position);
notifyDataSetChanged();
});
}).start();
} else {
dao.delete(data);
}
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> {
dialog.dismiss();
removeDialog.dismiss();
Toast.makeText(context, "删除成功", Toast.LENGTH_LONG).show();
list.remove(position);
notifyDataSetChanged();
});
}
});
@ -153,12 +184,13 @@ public class PassWordListAdapter extends RecyclerView.Adapter<PassWordListAdapte
.setTitle("查看信息")
.setView(view)
.setPositiveButton("更新", (dialog1, which) -> {
addPassword(title.getText().toString(), account.getText().toString(), password.getText().toString(),info.getText().toString(), data.getId(), false, new NetworkInterface() {
addPassword(title.getText().toString(), account.getText().toString(), password.getText().toString(), info.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(),
info.getText().toString(),
true);
}
@ -167,20 +199,23 @@ public class PassWordListAdapter extends RecyclerView.Adapter<PassWordListAdapte
addDatabase(title.getText().toString(),
account.getText().toString(),
password.getText().toString(),
info.getText().toString(),
false);
}
void addDatabase(String title1, String account1, String password1, boolean upload) {
void addDatabase(String title1, String account1, String password1, String info, boolean upload) {
new Thread(() -> {
data.setAccount(account1);
data.setTitle(title1);
data.setPassword(password1);
data.setInfo(info);
data.setUpload(upload);
dao.update(data);
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, ResTools.getString(context,R.string.toast_update), Toast.LENGTH_LONG).show();
Toast.makeText(context, ResTools.getString(context, R.string.toast_update), Toast.LENGTH_LONG).show();
notifyDataSetChanged();
}
});

View File

@ -6,9 +6,11 @@ import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import com.alibaba.fastjson2.annotation.JSONField;
/**
* tools_password
* @author
* @author
*/
@Entity
public class ToolsPassword{
@ -17,6 +19,7 @@ public class ToolsPassword{
@ColumnInfo
private String title;
@ColumnInfo
@JSONField(name = "username")
private String account;
@ColumnInfo
private String password;
@ -112,4 +115,20 @@ public class ToolsPassword{
public void setRemove(boolean remove) {
this.remove = remove;
}
@Override
public String toString() {
return "ToolsPassword{" +
"id=" + id +
", title='" + title + '\'' +
", account='" + account + '\'' +
", password='" + password + '\'' +
", url='" + url + '\'' +
", info='" + info + '\'' +
", type=" + type +
", uid=" + uid +
", upload=" + upload +
", remove=" + remove +
'}';
}
}

View File

@ -16,6 +16,8 @@ public interface ToolsPasswordDao {
List<ToolsPassword> getAll();
@Query("select * from ToolsPassword where title=:title and account=:account and password=:password and info=:info")
ToolsPassword isExist(String title,String account,String password,String info);
@Query("select * from ToolsPassword where id=:id")
ToolsPassword queryPassword(int id);
@Query("select * from ToolsPassword where title like :title and remove=0")
List<ToolsPassword> queryPassword(String title);
@Insert

View File

@ -16,18 +16,22 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.angcyo.tablayout.DslTabLayout;
import com.angcyo.tablayout.DslTabLayoutConfig;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.yutou.netlibs.http.HttpCallback;
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.NetUtils.NetTools;
import com.yutou.passmanage.Tools.NetworkTool;
import com.yutou.passmanage.Tools.RoomDatabaseManager;
import com.yutou.passmanage.Tools.Tools;
import com.yutou.passmanage.bean.BaseBean;
import com.yutou.passmanage.bean.PasswordBean;
import com.yutou.passmanage.bean.PasswordTypeBean;
@ -47,6 +51,10 @@ import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK;
import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL;
import static com.yutou.passmanage.Tools.RoomDatabaseManager.addPassword;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import kotlin.jvm.functions.Function4;
public class MainActivity extends AppCompatActivity {
EditText search;
ImageView clearSearch;
@ -69,7 +77,7 @@ public class MainActivity extends AppCompatActivity {
BiometricPrompt prompt;
void auth() {
if(true){
if (BuildConfig.DEBUG) {
init();
authError.setVisibility(View.GONE);
passList.setVisibility(View.VISIBLE);
@ -175,6 +183,32 @@ public class MainActivity extends AppCompatActivity {
}
});
tabLayout.configTabLayoutConfig(new Function1<DslTabLayoutConfig, Unit>() {
@Override
public Unit invoke(DslTabLayoutConfig dslTabLayoutConfig) {
dslTabLayoutConfig.setOnSelectItemView(new Function4<View, Integer, Boolean, Boolean, Boolean>() {
@Override
public Boolean invoke(View view, Integer integer, Boolean aBoolean, Boolean aBoolean2) {
if (aBoolean) {
PasswordTypeBean typeBean = (PasswordTypeBean) view.getTag();
NetTools.getApi().getTypePassword(typeBean.getId()).enqueue(new HttpCallback<List<ToolsPassword>>() {
@Override
public void onResponse(int code, String status, List<ToolsPassword> response) {
setShow(response);
}
@Override
public void onFailure(Throwable throwable) {
throwable.printStackTrace();
}
});
}
return false;
}
});
return null;
}
});
}
void showAddPasswordDialog() {
@ -254,137 +288,52 @@ public class MainActivity extends AppCompatActivity {
ToolsPasswordDao dao;
void initData() {
NetworkTool.httpGet(NetworkTool.NetworkAPI.PASSWORD_TYPE_ALL, new JSONObject(), new NetworkInterface<JSONObject>() {
NetTools.getApi().getAllTypePassword().enqueue(new HttpCallback<List<PasswordTypeBean>>() {
@Override
public void httpGetData(JSONObject json, int state) {
List<PasswordTypeBean> data = JSONArray.parseArray(json.getJSONArray("data").toJSONString(), PasswordTypeBean.class);
for (PasswordTypeBean bean : data) {
public void onResponse(int code, String status, List<PasswordTypeBean> response) {
for (PasswordTypeBean bean : response) {
Button tab = new Button(MainActivity.this);
tab.setOnClickListener(view -> {
});
tab.setText(bean.getTitle());
tab.setTag(bean);
tabLayout.addView(tab);
}
showLocalData();
}
@Override
public void httpError(Exception e) {
e.printStackTrace();
public void onFailure(Throwable throwable) {
showLocalData();
}
});
new Thread(() -> {
List<ToolsPassword> list = dao.getAllAndRemove();
if (list.size() == 0) {
new Thread(() -> {
if (dao.getAll().isEmpty()) {
authError.setText("列表为空,点击右下角+新增配置");
authError.setVisibility(View.VISIBLE);
passList.setVisibility(View.GONE);
} else {
for (ToolsPassword password : list) {
if (!password.isUpload() && !password.isRemove()) {
addPassword(password.getTitle(), password.getAccount(), password.getPassword(), password.getInfo(), -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) {
if (password.isUpload()) {
password.setRemove(true);
dao.update(password);
} else {
dao.delete(password);
}
} else {
dao.delete(password);
}
showData();
}
}).start();
}
});
}
}
}
}).start();
}
NetworkTool.httpGet(NetworkTool.NetworkAPI.PASSWORD_ALL, new JSONObject(), new NetworkInterface<JSONObject>() {
@Override
public void httpGetData(JSONObject json, int state) {
// data = ((String) data).replace("desc", "info");
// JSONObject json = JSONObject.parseObject((String) data);
if (json.getInteger("code") == 0) {
List<ToolsPassword> list = JSONArray.parseArray(json.getJSONArray("data").toJSONString(), ToolsPassword.class);
new Thread(() -> {
try {
for (ToolsPassword password : list) {
if (dao.isExist(password.getTitle(), password.getAccount(), password.getPassword(), password.getInfo()) == null) {
password.setUpload(true);
dao.insert(password);
}
}
} catch (Exception e) {
e.printStackTrace();
dao.clear();
for (ToolsPassword password : list) {
if (dao.isExist(password.getTitle(), password.getAccount(), password.getPassword(), password.getInfo()) == null) {
password.setUpload(true);
dao.insert(password);
}
}
} finally {
showData();
}
}).start();
}
}
@Override
public void httpError(Exception e) {
new Thread(() -> showData()).start();
}
});
private void showLocalData() {
showData();
}
private void setShow(List<ToolsPassword> data) {
adapter.setList(data);
adapter.notifyDataSetChanged();
}
void showData() {
new Thread(new Runnable() {
@Override
public void run() {
List<ToolsPassword> list = dao.getAll();
handler.post(() -> {
adapter.setList(list);
adapter.notifyDataSetChanged();
});
}
}).start();
}
void showData() {
List<ToolsPassword> list = dao.getAll();
handler.post(() -> {
adapter.setList(list);
adapter.notifyDataSetChanged();
});
}
}

View File

@ -0,0 +1,48 @@
package com.yutou.passmanage.NetUtils;
import com.yutou.netlibs.http.HttpBody;
import com.yutou.passmanage.Datas.ToolsPassword;
import com.yutou.passmanage.bean.BaseBean;
import com.yutou.passmanage.bean.PasswordTypeBean;
import java.util.List;
import okhttp3.FormBody;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
public interface NetApi {
@GET("/tools/password/type/get/list.do")
Call<HttpBody<List<PasswordTypeBean>>> getAllTypePassword();
@GET("/tools/password/get/list.do")
Call<HttpBody<List<ToolsPassword>>> getTypePassword(
@Query("type") int type
);
@GET("/tools/password/get/password.do")
Call<HttpBody<String>> getPassword(
@Query("id") int id
);
@FormUrlEncoded
@POST("/tools/password/set/add.do")
Call<HttpBody<BaseBean>> addPassword(@Field("title") String title,
@Field("account") String account,
@Field("password") String password,
@Field("info") String info);
@FormUrlEncoded
@POST("/tools/password/set/update.do")
Call<HttpBody<BaseBean>> updatePassword(@Field("id") int id,
@Field("title") String title,
@Field("account") String account,
@Field("password") String password,
@Field("info") String info);
@FormUrlEncoded
@POST("/tools/password/set/remove.do")
Call<HttpBody<BaseBean>> removePassword(@Field("id") int id);
}

View File

@ -0,0 +1,19 @@
package com.yutou.passmanage.NetUtils;
import com.yutou.netlibs.http.API;
import com.yutou.netlibs.http.BaseAPI;
import com.yutou.passmanage.Datas.AppData;
import java.util.HashMap;
public class NetTools extends API<NetApi> {
private NetTools(String url,HashMap<String,String> map) {
super(url,map);
}
public static NetApi getApi(){
HashMap<String,String> map=new HashMap<>();
map.put("token", AppData.key);
return new NetTools("https://tools.yutou233.cn",map).createAPI(NetApi.class);
}
}

View File

@ -3,10 +3,8 @@ package com.yutou.passmanage.Tools;
import android.util.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.passmanage.Datas.AppData;
import com.yutou.passmanage.Interfaces.NetworkInterface;
@ -29,162 +27,11 @@ public class NetworkTool {
private final static String TAG = NetworkTool.class.getSimpleName();
public static class NetworkAPI {
public static String HOME = "http://tools.yutou233.cn/tools/password/";
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";
}
public static <T> void httpGet(String url, JSONObject body, NetworkInterface<T> networkInterface) {
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(url + "?" + toGetSplice(body));
HttpURLConnection connection = (HttpURLConnection) new URL(url + "?" + toGetSplice(body)).openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
connection.connect();
if (connection.getResponseCode() != 200) {
networkInterface.httpError(new RuntimeException("http code to :" + connection.getResponseCode()));
return;
}
String tmp;
StringBuilder str = new StringBuilder();
while ((tmp = reader.readLine()) != null) {
str.append(tmp);
}
reader.close();
AppData.handler.post(new Runnable() {
@Override
public void run() {
if (networkInterface != null) {
try {
JSONObject json=JSONObject.parseObject(str.toString());
Type[] types = ((ParameterizedType) networkInterface.getClass().getGenericSuperclass()).getActualTypeArguments();
if(types.length==0){
networkInterface.httpGetData((T) JSONObject.parseObject(str.toString()),connection.getResponseCode());
}else {
Type type=types[0];
if (type.getTypeName().contains("JSON")) {
networkInterface.httpGetData((T) JSONObject.parseObject(str.toString()), connection.getResponseCode());
}else {
networkInterface.httpGetData(JSONObject.parseObject(json.getJSONObject("data").toJSONString(), type), connection.getResponseCode());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
Log.i(TAG + "[" + url + "]", "body:" + str + " (" + connection.getResponseCode() + ")");
} catch (Exception e) {
e.printStackTrace();
AppData.handler.post(new Runnable() {
@Override
public void run() {
if (networkInterface != null)
networkInterface.httpError(e);
}
});
Log.e(TAG, url + " body =" + body.toJSONString());
}
}
}).start();
}
private void ping(String url, NetworkInterface networkInterface) {
new Thread(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setConnectTimeout(50);
connection.setReadTimeout(50);
connection.connect();
InputStream inputStream = connection.getErrorStream();
System.out.println(inputStream.read());
inputStream.close();
System.out.println(connection.getResponseCode());
networkInterface.httpGetData(null, 0);
connection.disconnect();
} catch (Exception e) {
networkInterface.httpError(e);
}
}
}).start();
}
public static void httpPost(final String url, final JSONObject body, final NetworkInterface networkInterface) {
if (!url.startsWith("http:") && !Tools.isEmpty(NetworkAPI.HOME)) {
httpPost(NetworkAPI.HOME + url, body, networkInterface);
return;
}
body.put("token", AppData.key);
new Thread(new Runnable() {
@Override
public void run() {
String tmp;
StringBuilder str = new StringBuilder();
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout(5 * 1000);
connection.setReadTimeout(10 * 1000);
//connection.addRequestProperty("Connection", "keep-alive");
//connection.addRequestProperty("User-Agent", getExtUa());
// connection.addRequestProperty("content-type", "application/json");
connection.addRequestProperty("charset", "UTF-8");
OutputStream outputStream = connection.getOutputStream();
outputStream.write(toGetSplice(body).getBytes());
outputStream.flush();
outputStream.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while ((tmp = reader.readLine()) != null) {
str.append(tmp);
}
final String finalStr = str.toString();
Log.i(TAG + "[" + url + "?" + toGetSplice(body) + "]", "body:" + str + " (" + connection.getResponseCode() + ")");
AppData.handler.post(new Runnable() {
@Override
public void run() {
if (networkInterface != null) {
try {
networkInterface.httpGetData(str.toString(), connection.getResponseCode());
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
connection.disconnect();
reader.close();
} catch (Exception e) {
e.printStackTrace();
if (networkInterface != null)
networkInterface.httpError(e);
} finally {
Log.e(TAG, url + "\n传参:" + body.toString() + "\n接收" + str);
}
}
}).start();
}
private String getExtUa() {
return "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36";

View File

@ -1,6 +1,7 @@
package com.yutou.passmanage.Tools;
import android.content.Context;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.room.Database;
@ -12,10 +13,17 @@ import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.sqlite.db.SupportSQLiteOpenHelper;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.netlibs.http.HttpBody;
import com.yutou.passmanage.Datas.ToolsPassword;
import com.yutou.passmanage.Datas.ToolsPasswordDao;
import com.yutou.passmanage.Interfaces.NetworkInterface;
import com.yutou.passmanage.NetUtils.NetTools;
import com.yutou.passmanage.bean.BaseBean;
import retrofit2.Call;
import retrofit2.HttpException;
import retrofit2.Response;
@Database(entities = {ToolsPassword.class}, version = 2,exportSchema = false)
public abstract class RoomDatabaseManager extends RoomDatabase {
@ -62,9 +70,29 @@ public abstract class RoomDatabaseManager extends RoomDatabase {
json.put("id",id);
}
if(isAdd) {
NetworkTool.httpPost(NetworkTool.NetworkAPI.PASSWORD_ADD, json, networkInterface);
NetTools.getApi().addPassword(title,account,password,info).enqueue(new retrofit2.Callback<HttpBody<BaseBean>>() {
@Override
public void onResponse(Call<HttpBody<BaseBean>> call, Response<HttpBody<BaseBean>> response) {
networkInterface.httpGetData(response.body().getData(), response.body().getCode());
}
@Override
public void onFailure(Call<HttpBody<BaseBean>> call, Throwable t) {
networkInterface.httpError(new RuntimeException(t.getMessage()));
}
});
}else{
NetworkTool.httpPost(NetworkTool.NetworkAPI.PASSWORD_UPDATE, json, networkInterface);
NetTools.getApi().updatePassword(id,title,account,password,info).enqueue(new retrofit2.Callback<HttpBody<BaseBean>>() {
@Override
public void onResponse(Call<HttpBody<BaseBean>> call, Response<HttpBody<BaseBean>> response) {
networkInterface.httpGetData(response.body().getData(), response.body().getCode());
}
@Override
public void onFailure(Call<HttpBody<BaseBean>> call, Throwable t) {
networkInterface.httpError(new RuntimeException(t.getMessage()));
}
});
}
}
}

View File

@ -8,7 +8,7 @@ import java.util.List;
public class Tools {
public static boolean isEmpty(String str){
if(str==null||str.trim().length()==0){
if(str==null|| str.trim().isEmpty()){
return true;
}
return false;

View File

@ -71,4 +71,6 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@android:drawable/ic_input_add" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -13,4 +13,9 @@
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
<!-- Base application theme. -->
<style name="Base.Theme.MyPassworldManage" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your dark theme here. -->
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
</style>
</resources>

View File

@ -7,4 +7,50 @@
<string name="name">名字</string>
<string name="toast_copy_password">已复制密码</string>
<string name="toast_update">更新成功</string>
<!-- Strings used for fragments for navigation -->
<string name="first_fragment_label">First Fragment</string>
<string name="second_fragment_label">Second Fragment</string>
<string name="next">Next</string>
<string name="previous">Previous</string>
<string name="lorem_ipsum">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in scelerisque sem. Mauris
volutpat, dolor id interdum ullamcorper, risus dolor egestas lectus, sit amet mattis purus
dui nec risus. Maecenas non sodales nisi, vel dictum dolor. Class aptent taciti sociosqu ad
litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse blandit eleifend
diam, vel rutrum tellus vulputate quis. Aliquam eget libero aliquet, imperdiet nisl a,
ornare ex. Sed rhoncus est ut libero porta lobortis. Fusce in dictum tellus.\n\n
Suspendisse interdum ornare ante. Aliquam nec cursus lorem. Morbi id magna felis. Vivamus
egestas, est a condimentum egestas, turpis nisl iaculis ipsum, in dictum tellus dolor sed
neque. Morbi tellus erat, dapibus ut sem a, iaculis tincidunt dui. Interdum et malesuada
fames ac ante ipsum primis in faucibus. Curabitur et eros porttitor, ultricies urna vitae,
molestie nibh. Phasellus at commodo eros, non aliquet metus. Sed maximus nisl nec dolor
bibendum, vel congue leo egestas.\n\n
Sed interdum tortor nibh, in sagittis risus mollis quis. Curabitur mi odio, condimentum sit
amet auctor at, mollis non turpis. Nullam pretium libero vestibulum, finibus orci vel,
molestie quam. Fusce blandit tincidunt nulla, quis sollicitudin libero facilisis et. Integer
interdum nunc ligula, et fermentum metus hendrerit id. Vestibulum lectus felis, dictum at
lacinia sit amet, tristique id quam. Cras eu consequat dui. Suspendisse sodales nunc ligula,
in lobortis sem porta sed. Integer id ultrices magna, in luctus elit. Sed a pellentesque
est.\n\n
Aenean nunc velit, lacinia sed dolor sed, ultrices viverra nulla. Etiam a venenatis nibh.
Morbi laoreet, tortor sed facilisis varius, nibh orci rhoncus nulla, id elementum leo dui
non lorem. Nam mollis ipsum quis auctor varius. Quisque elementum eu libero sed commodo. In
eros nisl, imperdiet vel imperdiet et, scelerisque a mauris. Pellentesque varius ex nunc,
quis imperdiet eros placerat ac. Duis finibus orci et est auctor tincidunt. Sed non viverra
ipsum. Nunc quis augue egestas, cursus lorem at, molestie sem. Morbi a consectetur ipsum, a
placerat diam. Etiam vulputate dignissim convallis. Integer faucibus mauris sit amet finibus
convallis.\n\n
Phasellus in aliquet mi. Pellentesque habitant morbi tristique senectus et netus et
malesuada fames ac turpis egestas. In volutpat arcu ut felis sagittis, in finibus massa
gravida. Pellentesque id tellus orci. Integer dictum, lorem sed efficitur ullamcorper,
libero justo consectetur ipsum, in mollis nisl ex sed nisl. Donec maximus ullamcorper
sodales. Praesent bibendum rhoncus tellus nec feugiat. In a ornare nulla. Donec rhoncus
libero vel nunc consequat, quis tincidunt nisl eleifend. Cras bibendum enim a justo luctus
vestibulum. Fusce dictum libero quis erat maximus, vitae volutpat diam dignissim.
</string>
<string name="title_activity_main2">MainActivity2</string>
<string name="title_home">Home</string>
<string name="title_dashboard">Dashboard</string>
<string name="title_notifications">Notifications</string>
</resources>

View File

@ -13,4 +13,9 @@
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
<!-- Base application theme. -->
<style name="Base.Theme.MyPassworldManage" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your light theme here. -->
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
</style>
</resources>

View File

@ -5,8 +5,8 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.20"
classpath 'com.android.tools.build:gradle:8.5.2'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}

View File

@ -22,3 +22,6 @@ systemProp.http.proxyHost=127.0.0.1
systemProp.https.proxyHost=127.0.0.1
systemProp.https.proxyPort=7980
systemProp.http.proxyPort=7890
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

244
gradlew vendored Normal file
View File

@ -0,0 +1,244 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

92
gradlew.bat vendored Normal file
View File

@ -0,0 +1,92 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

1
netlibs/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

34
netlibs/build.gradle Normal file
View File

@ -0,0 +1,34 @@
plugins {
id 'com.android.library'
}
android {
namespace 'com.yutou.netlibs'
compileSdk 34
defaultConfig {
minSdk 28
targetSdk 34
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
api 'com.squareup.okhttp3:okhttp:3.14.9'
api 'com.squareup.retrofit2:retrofit:2.3.0'
api 'com.alibaba.fastjson2:fastjson2:2.0.52'
}

21
netlibs/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application />
</manifest>

View File

@ -0,0 +1,17 @@
package com.yutou.netlibs.converter;
import retrofit2.CallAdapter;
import retrofit2.Retrofit;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
public class JsonCallAdapter extends CallAdapter.Factory{
public static JsonCallAdapter create(){
return new JsonCallAdapter();
}
@Override
public CallAdapter<?, ?> get(Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
}

View File

@ -0,0 +1,27 @@
package com.yutou.netlibs.converter;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
public class JsonConverterFactory extends Converter.Factory {
public static JsonConverterFactory create() {
return new JsonConverterFactory();
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
// return super.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit);
return new JsonRequestBodyConverter<>();
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
// return super.responseBodyConverter(type, annotations, retrofit);
return new JsonResponseBodyConverter<>(type);
}
}

View File

@ -0,0 +1,14 @@
package com.yutou.netlibs.converter;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import retrofit2.Converter;
import java.io.IOException;
public class JsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
@Override
public RequestBody convert(T t) throws IOException {
return RequestBody.create(MediaType.parse("application/json);charset=UTF-8"), t.toString());
}
}

View File

@ -0,0 +1,34 @@
package com.yutou.netlibs.converter;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.netlibs.http.HttpBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import java.io.IOException;
import java.lang.reflect.Type;
public class JsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
Type type;
public JsonResponseBodyConverter(Type type) {
this.type=type;
}
@Override
public T convert(ResponseBody responseBody) throws IOException {
String string = new String(responseBody.bytes());
responseBody.close();
HttpBody<T> body ;
try {
body = JSONObject.parseObject(string, type);
return (T) body;
} catch (Exception e) {
e.printStackTrace();
body = new HttpBody();
body.setSrc(string);
}
return (T) body;
}
}

View File

@ -0,0 +1,57 @@
package com.yutou.netlibs.http;
import com.yutou.netlibs.converter.JsonCallAdapter;
import com.yutou.netlibs.converter.JsonConverterFactory;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.util.HashMap;
public class API<T> extends BaseAPI<T> {
private String URL;
private HashMap<String, String> params;
public API(String url, HashMap<String, String> params) {
this.URL = url;
this.params = params;
}
public API(String url) {
this.URL = url;
this.params = new HashMap<>();
}
@Override
public T createAPI(Class<T> t) {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor("http");
loggingInterceptor.setPrintLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder builder = new OkHttpClient()
.newBuilder()
.addInterceptor(initQuery())
.addInterceptor(loggingInterceptor);
return create(builder.build(),
JsonConverterFactory.create(),
JsonCallAdapter.create(),
URL,
t);
}
public Interceptor initQuery() {
Interceptor addQueryParameterInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//配置公共参数
request = new ParamsContext(params,request).getInRequest();
return chain.proceed(request);
}
};
return addQueryParameterInterceptor;
}
}

View File

@ -0,0 +1,44 @@
package com.yutou.netlibs.http;
import okhttp3.OkHttpClient;
import retrofit2.CallAdapter;
import retrofit2.Converter;
import retrofit2.Retrofit;
public abstract class BaseAPI<T> {
public abstract T createAPI(Class<T> t);
/**
* 创建一个接口方法
*
* @param okHttpClient okhttp客户端
* @param converterFactory 处理工厂类
* @param callAdapterFactory 请求适配器工厂
* @param baseUrl 基础地质
* @param service 接口
* @return 接口
*/
public T create(OkHttpClient okHttpClient,
Converter.Factory converterFactory,
CallAdapter.Factory callAdapterFactory,
String baseUrl,
Class<T> service) {
Retrofit.Builder builder = new Retrofit.Builder()
//基础url
.baseUrl(baseUrl)
//客户端OKHttp
.client(okHttpClient);
//添加转换工厂
if (null != converterFactory) {
builder.addConverterFactory(converterFactory);
}
//添加请求工厂
if (null != callAdapterFactory) {
builder.addCallAdapterFactory(callAdapterFactory);
}
//创建retrofit对象
Retrofit retrofit = builder.build();
//返回创建的api
return retrofit.create(service);
}
}

View File

@ -0,0 +1,25 @@
package com.yutou.netlibs.http;
import okhttp3.HttpUrl;
import okhttp3.Request;
import java.util.HashMap;
public class GetRequestParams implements IRequestParam {
/**
* 构建Request
*
* @param request
* @return
*/
@Override
public Request getRequest(HashMap<String, String> map, Request request) {
//添加公共参数
HttpUrl.Builder builder = request.url().newBuilder();
for (String key : map.keySet()) {
builder.addQueryParameter(key, String.valueOf(map.get(key)));
}
return request.newBuilder().url(builder.build()).build();
}
}

View File

@ -0,0 +1,40 @@
package com.yutou.netlibs.http;
public class HttpBody<T> {
private String msg;
private int code;
private T data;
private String src;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
}

View File

@ -0,0 +1,27 @@
package com.yutou.netlibs.http;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public abstract class HttpCallback<T> implements Callback<HttpBody<T>> {
public abstract void onResponse(int code,String status,T response);
public abstract void onFailure(Throwable throwable);
@Override
public void onResponse(Call<HttpBody<T>> call, Response<HttpBody<T>> response) {
if (response.body() != null) {
System.out.println("response = " + response.body());
System.out.println("response.data = " + response.body().getData());
onResponse(response.body().getCode(),response.body().getMsg(),response.body().getData());
}else{
onFailure(new NullPointerException("response body is null"));
}
}
@Override
public void onFailure(Call<HttpBody<T>> call, Throwable throwable) {
onFailure(throwable);
}
}

View File

@ -0,0 +1,213 @@
package com.yutou.netlibs.http;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import okhttp3.Connection;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.internal.http.HttpHeaders;
import okio.Buffer;
public class HttpLoggingInterceptor implements Interceptor {
private static final String TAG = "HttpLog";
private static final Charset UTF8 = StandardCharsets.UTF_8;
private volatile Level printLevel = Level.NONE;
private java.util.logging.Level colorLevel;
private Logger logger;
public enum Level {
NONE, //不打印log
BASIC, //只打印 请求首行 响应首行
HEADERS, //打印请求和响应的所有 Header
BODY //所有数据全部打印
}
public HttpLoggingInterceptor(String tag) {
logger = Logger.getLogger(tag);
colorLevel = java.util.logging.Level.ALL;
}
public void setPrintLevel(Level level) {
if (printLevel == null)
throw new NullPointerException("printLevel == null. Use Level.NONE instead.");
printLevel = level;
}
public void setColorLevel(java.util.logging.Level level) {
colorLevel = level;
}
private void log(String message) {
logger.log(colorLevel, message);
System.err.println(message);
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (printLevel == Level.NONE) {
return chain.proceed(request);
}
//请求日志拦截
// logForRequest(request, chain.connection());
//执行请求计算请求时间
long startNs = System.nanoTime();
Response response;
try {
response = chain.proceed(request);
} catch (Exception e) {
log("<-- HTTP FAILED: " + e);
throw e;
}
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
//响应日志拦截
return logForResponse(request, response, tookMs);
}
private void logForRequest(Request request, Connection connection) throws IOException {
boolean logBody = (printLevel == Level.BODY);
boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS);
RequestBody requestBody = request.body();
boolean hasRequestBody = requestBody != null;
Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1;
try {
String requestStartMessage = "--> " + request.method() + ' ' + request.url() + ' ' + protocol;
log(requestStartMessage);
if (logHeaders) {
if (hasRequestBody) {
// Request body headers are only present when installed as a network interceptor. Force
// them to be included (when available) so there values are known.
if (requestBody.contentType() != null) {
log("\tContent-Type: " + requestBody.contentType());
}
if (requestBody.contentLength() != -1) {
log("\tContent-Length: " + requestBody.contentLength());
}
}
Headers headers = request.headers();
for (int i = 0, count = headers.size(); i < count; i++) {
String name = headers.name(i);
// Skip headers from the request body as they are explicitly logged above.
if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
log("\t" + name + ": " + headers.value(i));
}
}
log(" ");
if (logBody && hasRequestBody) {
if (isPlaintext(requestBody.contentType())) {
bodyToString(request);
} else {
log("\tbody: maybe [binary body], omitted!");
}
}
}
} catch (Exception e) {
logger.log(colorLevel, "error", e);
} finally {
log("--> END " + request.method());
}
}
private Response logForResponse(Request request, Response response, long tookMs) {
Response.Builder builder = response.newBuilder();
Response clone = builder.build();
ResponseBody responseBody = clone.body();
RequestBody requestBody = request.body();
boolean hasRequestBody = requestBody != null;
boolean logBody = (printLevel == Level.BODY);
boolean logHeaders = (printLevel == Level.BODY || printLevel == Level.HEADERS);
try {
log("<-- " + clone.code() + ' ' + clone.message() + ' ' + clone.request().url() + " (" + tookMs + "ms");
if (logHeaders) {
Headers headers = clone.headers();
for (int i = 0, count = headers.size(); i < count; i++) {
log("\t" + headers.name(i) + ": " + headers.value(i));
}
log(" ");
if (logBody && hasRequestBody) {
if (isPlaintext(requestBody.contentType())) {
bodyToString(request);
} else {
log("\trequest: maybe [binary body], omitted!");
}
}
if (logBody && HttpHeaders.hasBody(clone)) {
if (responseBody == null) return response;
if (isPlaintext(responseBody.contentType())) {
byte[] bytes = responseBody.bytes();// IOUtils.toByteArray(responseBody.byteStream());
MediaType contentType = responseBody.contentType();
String body = new String(bytes, getCharset(contentType));
log("\tbody:" + body);
responseBody = ResponseBody.create(responseBody.contentType(), bytes);
return response.newBuilder().body(responseBody).build();
} else {
log("\tbody: maybe [binary body], omitted!");
}
}
}
} catch (Exception e) {
logger.log(colorLevel, "error", e);
} finally {
log("<-- END HTTP");
}
return response;
}
private static Charset getCharset(MediaType contentType) {
Charset charset = contentType != null ? contentType.charset(UTF8) : UTF8;
if (charset == null) charset = UTF8;
return charset;
}
/**
* Returns true if the body in question probably contains human readable text. Uses a small sample
* of code points to detect unicode control characters commonly used in binary file signatures.
*/
private static boolean isPlaintext(MediaType mediaType) {
if (mediaType == null) return false;
if (mediaType.type() != null && mediaType.type().equals("text")) {
return true;
}
String subtype = mediaType.subtype();
if (subtype != null) {
subtype = subtype.toLowerCase();
if (subtype.contains("x-www-form-urlencoded") || subtype.contains("json") || subtype.contains("xml") || subtype.contains("html")) //
return true;
}
return false;
}
private void bodyToString(Request request) {
try {
Request copy = request.newBuilder().build();
RequestBody body = copy.body();
if (body == null) return;
Buffer buffer = new Buffer();
body.writeTo(buffer);
Charset charset = getCharset(body.contentType());
log("\tbody:" + buffer.readString(charset));
} catch (Exception e) {
logger.log(colorLevel, "error", e);
}
}
}

View File

@ -0,0 +1,9 @@
package com.yutou.netlibs.http;
import okhttp3.Request;
import java.util.HashMap;
public interface IRequestParam {
Request getRequest(HashMap<String,String> map, Request request);
}

View File

@ -0,0 +1,29 @@
package com.yutou.netlibs.http;
import okhttp3.Request;
import java.util.HashMap;
public class ParamsContext {
private IRequestParam iRequestParam;
private Request request;
private HashMap<String,String> map;
public ParamsContext(HashMap<String,String> map,Request request) {
this.map=map;
this.request = request;
}
public Request getInRequest() {
switch (request.method()) {
case "GET":
iRequestParam = new GetRequestParams();
break;
case "POST":
iRequestParam = new PostRequestParams();
break;
}
return iRequestParam.getRequest(map,request);
}
}

View File

@ -0,0 +1,65 @@
package com.yutou.netlibs.http;
import com.alibaba.fastjson2.JSONObject;
import okhttp3.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class PostRequestParams implements IRequestParam {
@Override
public Request getRequest(HashMap<String, String> map, Request request) {
if (request.body() instanceof FormBody) {
FormBody.Builder bodyBuilder = new FormBody.Builder();
FormBody formBody = (FormBody) request.body();
for (int i = 0; i < formBody.size(); i++) {
bodyBuilder.addEncoded(formBody.encodedName(i), formBody.encodedValue(i));
}
for (String key : map.keySet()) {
bodyBuilder.addEncoded(key, String.valueOf(map.get(key)));
}
formBody = bodyBuilder.build();
request = request.newBuilder().post(formBody).build();
} else if (request.body() != null) {
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),toUrlParams(map));
request = request.newBuilder().post(request.body())
.post(requestBody).build();
}
return request;
}
public static String toUrlParams(JSONObject json) {
StringBuilder string = new StringBuilder();
Set<String> keys = json.keySet();
for (String key : keys) {
try {
string.append("&").append(key).append("=").append(URLEncoder.encode(json.getString(key), "UTF-8"));
} catch (Exception e) {
e.printStackTrace();
try {
string.append("&").append(URLEncoder.encode(key,"UTF-8")).append("=");
// string += "&" + key + "=";
} catch (Exception e1) {
string.append("&").append(key).append("=");
}
}
}
string = new StringBuilder(string.substring(1, string.length()).replaceAll(" ", ""));
return string.toString();
}
public static String toUrlParams(Map<String, String> map) {
StringBuilder builder = new StringBuilder();
for (String key : map.keySet()) {
builder.append(key).append("=").append(map.get(key)).append("&");
}
return builder.substring(0, builder.length() - 1);
}
}

View File

@ -1,4 +1,5 @@
include ':app'
include ':ViewPager2Delegate'
include ':TabLayout'
include ':netlibs'
rootProject.name = "MyPassworldManage"