@ -1,6 +1,7 @@
@@ -1,6 +1,7 @@
package cc.niushuai.dididone.ui.setting ;
import android.Manifest ;
import android.app.Activity ;
import android.content.Intent ;
import android.content.pm.PackageManager ;
import android.net.Uri ;
@ -15,6 +16,7 @@ import androidx.core.app.ActivityCompat;
@@ -15,6 +16,7 @@ import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat ;
import java.io.FileNotFoundException ;
import java.io.InputStream ;
import java.io.OutputStream ;
import java.nio.charset.StandardCharsets ;
import java.util.ArrayList ;
@ -33,12 +35,17 @@ import cc.niushuai.dididone.ui.base.BaseFragment;
@@ -33,12 +35,17 @@ import cc.niushuai.dididone.ui.base.BaseFragment;
import cc.niushuai.dididone.util.GsonUtil ;
import cc.niushuai.dididone.util.Toasts ;
import cc.niushuai.dididone.util.XLog ;
import cn.hutool.core.bean.BeanUtil ;
import cn.hutool.core.collection.CollUtil ;
import cn.hutool.core.date.DatePattern ;
import cn.hutool.core.date.DateUtil ;
import cn.hutool.core.io.IoUtil ;
import cn.hutool.core.util.StrUtil ;
import io.reactivex.Completable ;
import io.reactivex.CompletableObserver ;
import io.reactivex.Single ;
import io.reactivex.android.schedulers.AndroidSchedulers ;
import io.reactivex.disposables.Disposable ;
import io.reactivex.schedulers.Schedulers ;
public class SettingFragment extends BaseFragment {
@ -66,32 +73,38 @@ public class SettingFragment extends BaseFragment {
@@ -66,32 +73,38 @@ public class SettingFragment extends BaseFragment {
}
private void addRestoreClickListener ( ) {
binding . sSetRestore . setOnClickListener ( view - > {
requestForPermission ( BizGlobal . REQUEST_CODE_RESTORE , Intent . ACTION_GET_CONTENT ) ;
} ) ;
}
private void addBackupClickListener ( ) {
binding . sSetBackup . setOnClickListener ( view - > {
if (
// true表示未授权读权限
ContextCompat . checkSelfPermission ( getContext ( ) , Manifest . permission . READ_EXTERNAL_STORAGE ) = = PackageManager . PERMISSION_DENIED | |
// true表示未授权写权限
ContextCompat . checkSelfPermission ( getContext ( ) , Manifest . permission . WRITE_EXTERNAL_STORAGE ) = = PackageManager . PERMISSION_DENIED ) {
// 申请授权
if ( ActivityCompat . shouldShowRequestPermissionRationale ( getActivity ( ) , Manifest . permission . READ_EXTERNAL_STORAGE )
| | ActivityCompat . shouldShowRequestPermissionRationale ( getActivity ( ) , Manifest . permission . WRITE_EXTERNAL_STORAGE )
) {
Toasts . longShow ( getContext ( ) , "您曾经选择过禁止弹窗授权, 请手动进入应用管理授权" ) ;
} else {
ActivityCompat . requestPermissions ( getActivity ( ) , new String [ ] {
Manifest . permission . READ_EXTERNAL_STORAGE ,
Manifest . permission . WRITE_EXTERNAL_STORAGE ,
} , BizGlobal . REQUEST_CODE_GENERAL ) ;
}
requestForPermission ( BizGlobal . REQUEST_CODE_BACKUP , Intent . ACTION_CREATE_DOCUMENT ) ;
} ) ;
}
private void requestForPermission ( Integer requestCode , String action ) {
if (
// true表示未授权读权限
ContextCompat . checkSelfPermission ( getContext ( ) , Manifest . permission . READ_EXTERNAL_STORAGE ) = = PackageManager . PERMISSION_DENIED | |
// true表示未授权写权限
ContextCompat . checkSelfPermission ( getContext ( ) , Manifest . permission . WRITE_EXTERNAL_STORAGE ) = = PackageManager . PERMISSION_DENIED ) {
// 申请授权
if ( ActivityCompat . shouldShowRequestPermissionRationale ( getActivity ( ) , Manifest . permission . READ_EXTERNAL_STORAGE )
| | ActivityCompat . shouldShowRequestPermissionRationale ( getActivity ( ) , Manifest . permission . WRITE_EXTERNAL_STORAGE )
) {
Toasts . longShow ( getContext ( ) , "您曾经选择过禁止弹窗授权, 请手动进入应用管理授权" ) ;
} else {
chooseBackupFileLocation ( ) ;
ActivityCompat . requestPermissions ( getActivity ( ) , new String [ ] {
Manifest . permission . READ_EXTERNAL_STORAGE ,
Manifest . permission . WRITE_EXTERNAL_STORAGE ,
} , BizGlobal . REQUEST_CODE_GENERAL ) ;
}
} ) ;
} else {
chooseBackupFileLocation ( requestCode , action ) ;
}
}
@Override
@ -99,39 +112,47 @@ public class SettingFragment extends BaseFragment {
@@ -99,39 +112,47 @@ public class SettingFragment extends BaseFragment {
boolean isAllGranted = false ;
switch ( requestCode ) {
case BizGlobal . REQUEST_CODE_GENERAL :
for ( int i = 0 ; i < permissions . length ; i + + ) {
XLog . d ( "permission: {} result: {}" , permissions [ i ] , grantResults [ i ] ) ;
for ( int i = 0 ; i < permissions . length ; i + + ) {
XLog . d ( "permission: {} result: {}" , permissions [ i ] , grantResults [ i ] ) ;
if ( grantResults [ i ] = = PackageManager . PERMISSION_DENIED ) {
isAllGranted = false ;
if ( grantResults [ i ] = = PackageManager . PERMISSION_DENIED ) {
isAllGranted = false ;
// break;
}
}
break ;
default :
XLog . d ( "un case requestCode: {}" , requestCode ) ;
}
}
if ( isAllGranted ) {
// 授权通过时 打开文件保存逻辑
chooseBackupFileLocation ( ) ;
String action = null ;
if ( BizGlobal . REQUEST_CODE_BACKUP . equals ( requestCode ) ) {
action = Intent . ACTION_CREATE_DOCUMENT ;
} else if ( BizGlobal . REQUEST_CODE_RESTORE . equals ( requestCode ) ) {
action = Intent . ACTION_GET_CONTENT ;
} else {
XLog . d ( "unknown request code: {}" , requestCode ) ;
Toasts . shortShow ( getContext ( ) , "未知的请求码: {}" , requestCode + "" ) ;
return ;
}
chooseBackupFileLocation ( requestCode , action ) ;
}
}
private void chooseBackupFileLocation ( ) {
private void chooseBackupFileLocation ( Integer requestCode , String action ) {
// 写文件
Intent chooseFileLocationIntent = new Intent ( Intent . ACTION_CREATE_DOCUMENT ) ;
Intent chooseFileLocationIntent = new Intent ( action ) ;
chooseFileLocationIntent . addCategory ( Intent . CATEGORY_OPENABLE ) ;
chooseFileLocationIntent . setType ( "*/*" ) ;
chooseFileLocationIntent . putExtra ( Intent . EXTRA_TITLE , StrUtil . format ( FILE_NAME , getString ( R . string . app_name ) , DateUtil . date ( ) . toString ( DatePattern . PURE_DATETIME_PATTERN ) ) ) ;
if ( BizGlobal . REQUEST_CODE_BACKUP . equals ( requestCode ) ) {
chooseFileLocationIntent . putExtra ( Intent . EXTRA_TITLE , StrUtil . format ( FILE_NAME , getString ( R . string . app_name ) , DateUtil . date ( ) . toString ( DatePattern . PURE_DATETIME_PATTERN ) ) ) ;
}
// 选择文件 在onActivityResult中监听选择的文件
startActivityForResult ( chooseFileLocationIntent , BizGlobal . REQUEST_CODE_GENERAL ) ;
startActivityForResult ( chooseFileLocationIntent , requestCode ) ;
}
private String dealBackupContent ( List < Record > recordList ) {
@ -144,33 +165,131 @@ public class SettingFragment extends BaseFragment {
@@ -144,33 +165,131 @@ public class SettingFragment extends BaseFragment {
projectRecordList . add ( new ProjectRecord ( allProjectMap . get ( projectId ) , collect ) ) ;
}
// JSON化
return GsonUtil . toJsonString ( projectRecordList ) ;
return GsonUtil . toJson ( projectRecordList ) ;
}
@Override
public void onActivityResult ( int requestCode , int resultCode , @Nullable Intent data ) {
if ( requestCode = = BizGlobal . REQUEST_CODE_GENERAL & & requestCode = = 1 ) {
Uri fileUri = data . getData ( ) ;
Single < List < Record > > listSingle = DBManager . INSTANCE . recordDao ( ) . xListAll ( ) ;
listSingle . subscribeOn ( Schedulers . io ( ) )
. observeOn ( AndroidSchedulers . mainThread ( ) )
. subscribe ( ( recordList , throwable ) - > {
XLog . d ( "addBackClickListener == " + recordList . size ( ) ) ;
try {
String content = dealBackupContent ( recordList ) ;
OutputStream outputStream = getContext ( ) . getContentResolver ( ) . openOutputStream ( fileUri ) ;
IoUtil . write ( outputStream , true , content . getBytes ( StandardCharsets . UTF_8 ) ) ;
Toasts . shortShow ( getContext ( ) , "文件已备份: {}" , fileUri . getPath ( ) . substring ( fileUri . getPath ( ) . indexOf ( ":" ) ) . replace ( ":" , "/sdcard/" ) ) ;
} catch ( FileNotFoundException e ) {
XLog . d ( "save file【{}】 error: {}" , fileUri . getPath ( ) , e . getMessage ( ) , e ) ;
}
} ) ;
if ( resultCode ! = Activity . RESULT_OK ) {
Toasts . shortShow ( getContext ( ) , "操作失败 {} --> {}" , requestCode + "" , resultCode + "" ) ;
return ;
}
if ( BizGlobal . REQUEST_CODE_BACKUP . equals ( requestCode ) ) {
backupResult ( data ) ;
} else if ( BizGlobal . REQUEST_CODE_RESTORE . equals ( requestCode ) ) {
restoreResult ( data ) ;
}
}
private void restoreResult ( Intent data ) {
try {
Uri uri = data . getData ( ) ;
InputStream inputStream = getContext ( ) . getContentResolver ( ) . openInputStream ( uri ) ;
String readStr = IoUtil . read ( inputStream , StandardCharsets . UTF_8 ) ;
List < Map < String , Object > > list = GsonUtil . toBean ( readStr , List . class ) ;
if ( CollUtil . isEmpty ( list ) ) {
Toasts . shortShow ( getContext ( ) , "未发现可导入内容, 请检查文件是否正确" ) ;
return ;
}
List < ProjectRecord > projectRecordList = new ArrayList < > ( list . size ( ) ) ;
for ( Map < String , Object > map : list ) {
String json = GsonUtil . toJson ( map ) ;
ProjectRecord projectRecord = GsonUtil . toBean ( json , ProjectRecord . class ) ;
projectRecordList . add ( projectRecord ) ;
}
restoreProjectRecord ( projectRecordList ) ;
} catch ( FileNotFoundException e ) {
XLog . d ( "文件读取失败: {}" , e . getMessage ( ) , e ) ;
Toasts . shortShow ( getContext ( ) , "文件读取失败: {}" , e . getMessage ( ) ) ;
}
}
private void restoreProjectRecord ( List < ProjectRecord > projectRecordList ) {
if ( CollUtil . isNotEmpty ( projectRecordList ) ) {
for ( ProjectRecord projectRecord : projectRecordList ) {
List < Record > recordList = projectRecord . getRecordList ( ) ;
if ( CollUtil . isNotEmpty ( recordList ) ) {
// 插入record
Completable completable = DBManager . INSTANCE . recordDao ( ) . insertAll ( recordList ) ;
completable . subscribeOn ( Schedulers . io ( ) )
. observeOn ( AndroidSchedulers . mainThread ( ) )
. subscribe ( new CompletableObserver ( ) {
@Override
public void onSubscribe ( Disposable d ) {
XLog . d ( "restore onSubscribe" ) ;
}
@Override
public void onComplete ( ) {
XLog . d ( "restore onComplete" ) ;
BizGlobal . buildCache ( ) ;
}
@Override
public void onError ( Throwable e ) {
XLog . d ( "restore onError: {}" , e . getMessage ( ) , e ) ;
}
} ) ;
}
// 插入project
Project project = new Project ( ) ;
BeanUtil . copyProperties ( projectRecord , project ) ;
Completable completable = DBManager . INSTANCE . projectDao ( ) . insertAll ( project ) ;
completable . subscribeOn ( Schedulers . io ( ) )
. observeOn ( AndroidSchedulers . mainThread ( ) )
. subscribe ( new CompletableObserver ( ) {
@Override
public void onSubscribe ( Disposable d ) {
}
@Override
public void onComplete ( ) {
BizGlobal . buildCache ( ) ;
}
@Override
public void onError ( Throwable e ) {
}
} ) ;
}
}
}
private void backupResult ( @NonNull Intent data ) {
Uri fileUri = data . getData ( ) ;
Single < List < Record > > listSingle = DBManager . INSTANCE . recordDao ( ) . xListAll ( ) ;
listSingle . subscribeOn ( Schedulers . io ( ) )
. observeOn ( AndroidSchedulers . mainThread ( ) )
. subscribe ( ( recordList , throwable ) - > {
XLog . d ( "addBackClickListener == " + recordList . size ( ) ) ;
try {
String content = dealBackupContent ( recordList ) ;
OutputStream outputStream = getContext ( ) . getContentResolver ( ) . openOutputStream ( fileUri ) ;
IoUtil . write ( outputStream , true , content . getBytes ( StandardCharsets . UTF_8 ) ) ;
Toasts . shortShow ( getContext ( ) , "文件已备份: {}" , fileUri . getPath ( ) . substring ( fileUri . getPath ( ) . indexOf ( ":" ) ) . replace ( ":" , "/sdcard/" ) ) ;
} catch ( FileNotFoundException e ) {
XLog . d ( "save file【{}】 error: {}" , fileUri . getPath ( ) , e . getMessage ( ) , e ) ;
}
} ) ;
}
@Override
public void onDestroyView ( ) {
super . onDestroyView ( ) ;