1.实现了根目录下再按一次返回键退出APP

2.再次思考完成解压需要做的事情
点击文件,有个按钮直接检测md5值在数据库中有没有数据,有的话填充密码框,密码框可勾选是否明文,还有一个选项是是否上传当前文件的密码,有密码指定目的路径点击解压按钮就可以直接解压
3.改了APP主题
4.添加了一个解压用的dialog,但是要给dialog传入bundle数据不知道从何下手
master
ThankVinci 4 years ago
parent 3f421d1d69
commit 8fde82cffd

@ -12,7 +12,7 @@
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
android:theme="@style/Theme.CloudKey">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

@ -13,6 +13,7 @@ import androidx.navigation.Navigation;
import androidx.recyclerview.widget.RecyclerView;
import com.thankvinci.CloudKey.Fragment.FileManageFragment;
import com.thankvinci.CloudKey.Fragment.UnzipDialogFragment;
import com.thankvinci.CloudKey.MainActivity;
import com.thankvinci.CloudKey.R;
import com.thankvinci.CloudKey.Utils.FileHandler;
@ -70,15 +71,27 @@ public class FileAdapter extends RecyclerView.Adapter<FileAdapter.ViewHolder> {
}else{
//Toast.makeText(v.getContext(),fitem.getName()+" "+fitem.isCompress(),Toast.LENGTH_SHORT).show();
if (fitem.isCompress()){
FileHandler fileHandler = new FileHandler((MainActivity)v.getContext());
Thread ft = new Thread(new FileThread(fileHandler,builder.toString(),null,0));
ft.start();
Toast.makeText(v.getContext(),"线程正在处理,请稍后",Toast.LENGTH_LONG).show();
UnzipDialogFragment unzipDialog = new UnzipDialogFragment();
unzipDialog.setListener(new UnzipDialogFragment.UnzipDialogListener() {
@Override
public void onDialogUnzipClicked() {
Toast.makeText(v.getContext(),"打开",Toast.LENGTH_SHORT).show();
}
});
Bundle data = new Bundle();
data.putString("srcFile",builder.toString());
data.putString("desPath",builder.toString().substring(0,builder.toString().lastIndexOf(".")));
unzipDialog.setArguments(data);
unzipDialog.show(((MainActivity)v.getContext()).getSupportFragmentManager(),"unzip");
//FileHandler fileHandler = new FileHandler((MainActivity)v.getContext());
//Thread ft = new Thread(new FileThread(fileHandler,,,"12341234",FileThread.FUNCTION_DECOMPRESS));
//ft.start();
//Toast.makeText(v.getContext(),"线程正在处理,请稍后",Toast.LENGTH_LONG).show();
}else{
Toast.makeText(v.getContext(),"没有打开除文件夹和压缩包以外的功能",Toast.LENGTH_SHORT).show();
Toast.makeText(v.getContext(),"本软件暂时只支持zip解压",Toast.LENGTH_SHORT).show();
}
}
}
});
return holder;

@ -1,5 +1,15 @@
package com.thankvinci.CloudKey.Files;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.thankvinci.CloudKey.Utils.FileHandler;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.File;
@ -33,4 +43,27 @@ public class FileUtils {
String filemd5 = DigestUtils.md5Hex(new FileInputStream(path));
return filemd5;
}
//文件解压
public static void unzip(String srcFile, String desPath, String passwd, Handler handler) throws ZipException {
ZipFile zipFile = new ZipFile(srcFile);
//zipFile.setCharset();
Bundle data = new Bundle();
Message msg = new Message();
if (!zipFile.isValidZipFile()){
data.putString("error","压缩包已损坏");
msg.what = FileHandler.ERROR;
msg.setData(data);
handler.sendMessage(msg);
}
File f = new File(desPath);
if (f.isDirectory() && !f.exists()){
f.mkdirs();
}
if (zipFile.isEncrypted()) {
zipFile.setPassword(passwd.toCharArray());
}
Log.d("TAG:",zipFile.getFile().getName());
zipFile.extractAll(desPath);
}
}

@ -2,6 +2,7 @@ package com.thankvinci.CloudKey.Fragment;
import android.os.Bundle;
import android.os.Environment;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -28,6 +29,9 @@ import java.util.Stack;
public class FileManageFragment extends Fragment {
private long lastTime = 0;
private long currentTime = 0;
private String dir; //当前fragment加载的目录
private boolean isRoot; //是否是根目录布局
@ -71,6 +75,9 @@ public class FileManageFragment extends Fragment {
public String getDir(){
return dir;
}
public boolean isRoot(){
return isRoot;
}
public void loadDirectory(){
ActivityCompat.requestPermissions(getActivity(), new String[]{ //运行时权限
"android.permission.WRITE_EXTERNAL_STORAGE",
@ -122,4 +129,15 @@ public class FileManageFragment extends Fragment {
FileAdapter adapter = new FileAdapter(fileItemList,this);
directoryView.setAdapter(adapter);
}
public void onKeyDownChild(int key,KeyEvent event){
if (isRoot && key==event.KEYCODE_BACK){
currentTime = System.currentTimeMillis();
if(currentTime - lastTime > 2000){
Toast.makeText(getActivity(),"再按一次返回键退出",Toast.LENGTH_SHORT).show();
lastTime = currentTime;
}else{
getActivity().finish();
}
}
}
}

@ -0,0 +1,48 @@
package com.thankvinci.CloudKey.Fragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import com.thankvinci.CloudKey.R;
public class UnzipDialogFragment extends DialogFragment {
//点击压缩文件弹出来的Dialog
private UnzipDialogListener listener;
//源文件绝对路径,目标文件夹绝对路径和密码
private EditText srcFile_edit;
private EditText desPath_edit;
private EditText passwd_edit;
public interface UnzipDialogListener{
public void onDialogUnzipClicked();
}
public void setListener(UnzipDialogListener listener){
this.listener = listener;
}
public AlertDialog onCreateDialog(Bundle bundle){
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = requireActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.unzip_dialog,null);
srcFile_edit = view.findViewById(R.id.src_edit);
desPath_edit = view.findViewById(R.id.des_edit);
builder.setView(view).setTitle("解压到当前路径").setPositiveButton("解压", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
listener.onDialogUnzipClicked();
}
}).setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(getActivity(),"取消操作",Toast.LENGTH_SHORT).show();
}
});;
return builder.create();
}
}

@ -2,6 +2,7 @@ package com.thankvinci.CloudKey;
import androidx.appcompat.app.AppCompatActivity;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.fragment.NavHostFragment;
import androidx.navigation.ui.AppBarConfiguration;
@ -9,10 +10,13 @@ import androidx.navigation.ui.NavigationUI;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.navigation.NavigationView;
import com.thankvinci.CloudKey.Fragment.FileManageFragment;
import com.thankvinci.CloudKey.NetUtils.NetHandler;
import com.thankvinci.CloudKey.NetUtils.NetThread;
@ -40,4 +44,19 @@ public class MainActivity extends AppCompatActivity {
public boolean onSupportNavigateUp() {
return NavigationUI.navigateUp(navController,appBarConfiguration)||super.onSupportNavigateUp();
}
@Override
public boolean onKeyDown(int key, KeyEvent event){
//当前nav导航的fragment如果是fm的话,调用返回键
if(navController.getCurrentDestination().getId() == R.id.fileManageFragment){
for(Fragment fragment:navHostFragment.getChildFragmentManager().getFragments()){
if(fragment instanceof FileManageFragment){
if (((FileManageFragment)fragment).isRoot()) {
((FileManageFragment) fragment).onKeyDownChild(key, event);
return false; //结束activity是在fm中结束的
}
}
}
}
return super.onKeyDown(key, event); //只有当当前页面不是fm的根目录时会执行原本的返回操作
}
}

@ -18,6 +18,7 @@ import java.net.MalformedURLException;
import java.net.URL;
public class NetThread implements Runnable {
final static int ERROR = 2;
Handler handler;
String strUrl;
public NetThread(Handler handler,String strUrl){

@ -10,8 +10,9 @@ import com.thankvinci.CloudKey.NetUtils.NetThread;
public class FileHandler extends Handler {
//定义功能选择的常量 获取MD5和解压
final static int FUNCTION_GET_MD5 = 0;
final static int FUNCTION_DECOMPRESS = 1;
public final static int FUNCTION_GET_MD5 = 0;
public final static int FUNCTION_DECOMPRESS = 1;
public final static int ERROR = -1;
private Activity activity;
@ -33,6 +34,8 @@ public class FileHandler extends Handler {
Thread nt = new Thread(new NetThread(handler,url));
nt.start();
break;
case ERROR:
Toast.makeText(activity,msg.getData().getString("error"),Toast.LENGTH_SHORT).show();
}
}
}

@ -6,22 +6,26 @@ import android.os.Message;
import com.thankvinci.CloudKey.Files.FileUtils;
import net.lingala.zip4j.exception.ZipException;
import java.io.IOException;
public class FileThread implements Runnable{
final static int FUNCTION_GET_MD5 = 0;
final static int FUNCTION_DECOMPRESS = 1;
public final static int FUNCTION_GET_MD5 = 0;
public final static int FUNCTION_DECOMPRESS = 1;
public final static int ERROR = -1;
private String srcFile,desPath,md5;
private String srcFile,desPath,md5,passwd;
private Handler handler;
private int function;
public FileThread(Handler handler,String srcFile,String desPath,final int FUNCTION){
public FileThread(Handler handler,String srcFile,String desPath,String passwd,final int FUNCTION){
this.handler = handler;
this.srcFile = srcFile;
this.desPath = desPath;
this.passwd = passwd;
this.function = FUNCTION;
}
@Override
@ -39,9 +43,13 @@ public class FileThread implements Runnable{
} catch (IOException e) {
e.printStackTrace();
}
break;
case FUNCTION_DECOMPRESS:
try {
FileUtils.unzip(srcFile,desPath,passwd,handler);
} catch (ZipException e) {
e.printStackTrace();
}
break;
default: break;
}

@ -5,8 +5,12 @@ import android.content.ClipboardManager;
import android.content.Context;
public class MyUtils {
//private long
public static void copyToClipboard(Activity activity,String str){
ClipboardManager cmb = (ClipboardManager)activity.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setText(str);
}
public static void onBackExit(){
}
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:color="@color/blue_1"/>
<item android:state_pressed="true" android:color="@color/grey"/>
</selector>

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/src_text"
android:textSize="14dp"
android:text="源文件名:"
android:textColor="@color/blue_1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
tools:ignore="MissingConstraints" />
<EditText
android:layout_width="220dp"
android:layout_height="wrap_content"
android:textSize="14dp"
android:id="@+id/src_edit"
android:textColor="@color/grey"
android:focusable="false"
tools:ignore="MissingConstraints"
app:layout_constraintLeft_toRightOf="@id/src_text"
app:layout_constraintBaseline_toBaselineOf="@id/src_text"
android:layout_marginLeft="5dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/des_text"
android:textSize="14dp"
android:text="目标地址:"
android:textColor="@color/blue_1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/src_text"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
tools:ignore="MissingConstraints" />
<EditText
android:layout_width="220dp"
android:layout_height="wrap_content"
android:textSize="14dp"
android:id="@+id/des_edit"
android:textColor="@color/grey"
android:focusable="false"
tools:ignore="MissingConstraints"
app:layout_constraintLeft_toRightOf="@id/des_text"
app:layout_constraintBaseline_toBaselineOf="@id/des_text"
android:layout_marginLeft="5dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/pwd_text"
android:textSize="14dp"
android:text="文件密码:"
android:textColor="@color/blue_1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/des_text"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
tools:ignore="MissingConstraints" />
<EditText
android:layout_width="220dp"
android:layout_height="wrap_content"
android:textSize="14dp"
android:id="@+id/pwd_edit"
android:textColor="@color/grey"
android:focusable="false"
tools:ignore="MissingConstraints"
app:layout_constraintLeft_toRightOf="@id/pwd_text"
app:layout_constraintBaseline_toBaselineOf="@id/pwd_text"
android:layout_marginLeft="5dp"
/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/accept_pwd_2_sql"
android:text="同意将密码同步到数据库"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/pwd_edit"
android:layout_marginTop="10dp"
android:layout_marginLeft="20dp"
tools:ignore="MissingConstraints" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/getpwd"
android:text="获取密码"
android:clickable="true"
android:textColor="@drawable/text_be_clicked"
app:layout_constraintLeft_toRightOf="@id/accept_pwd_2_sql"
app:layout_constraintBaseline_toBaselineOf="@id/accept_pwd_2_sql"
android:layout_marginLeft="20dp"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,16 +1,17 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.CloudKey" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<style name="Theme.CloudKey" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Primary brand color.
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorOnPrimary">@color/black</item>-->
<!-- Secondary brand color.
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<item name="colorOnSecondary">@color/black</item>-->
<!-- Status bar color.
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>-->
<!-- Customize your theme here. -->
<item name="colorAccent">@color/blue_1</item>
</style>
</resources>

@ -10,6 +10,7 @@
<color name="white">#FFFFFFFF</color>
<color name="red">#FFff0000</color>
<color name="blue">#FF0000ff</color>
<color name="blue_1">#FF41A2EF</color>
<color name="yellow">#FFffff00</color>
<color name="green">#FF00ff00</color>
<color name="transparent">#00ffffff</color>

@ -1,16 +1,17 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.CloudKey" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<style name="Theme.CloudKey" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Primary brand color.
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorOnPrimary">@color/white</item>-->
<!-- Secondary brand color.
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<item name="colorOnSecondary">@color/black</item>-->
<!-- Status bar color.
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>-->
<!-- Customize your theme here. -->
<item name="colorAccent">@color/blue_1</item>
</style>
</resources>

@ -255,4 +255,16 @@ FileHandler负责将获取到的md5码发到NetThread,然后将得到的密码
数据流向:
主线程(文件路径)-->FileThread(MD5)-->FileHandler(MD5)-->NetThread(pwd)-->NetHandler(pwd)
主线程(文件路径)-->FileThread(MD5)-->FileHandler(MD5)-->NetThread(pwd)-->NetHandler(pwd)
**2021/6/12**
实现了根目录下再按一次返回键退出APP
再次思考完成解压需要做的事情
点击文件,有个按钮直接检测md5值在数据库中有没有数据,有的话填充密码框,密码框可勾选是否明文,还有一个选项是是否上传当前文件的密码,有密码指定目的路径点击解压按钮就可以直接解压
改了主题
添加了一个解压用的dialog
Loading…
Cancel
Save