diff --git a/app/build.gradle b/app/build.gradle index 8a1f065..4b7f58d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { //There are no CERT files because If the mini sdk version is 23+, the AGP will ignore the V1 scheme signature. minSdkVersion 23 targetSdkVersion 29 - versionCode 1 - versionName "1.0.0" + versionCode 3 + versionName "1.0.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -139,6 +139,7 @@ dependencies { implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation "androidx.viewpager2:viewpager2:1.0.0" + implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'junit:junit:4.12' @@ -203,4 +204,6 @@ dependencies { implementation 'me.jessyan:autosize:1.2.1' // 权限请求框架:https://github.com/getActivity/XXPermissions implementation 'com.github.getActivity:XXPermissions:20.0' + // 吐司框架:https://github.com/getActivity/Toaster + implementation 'com.github.getActivity:Toaster:12.6' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7d68b2a..20a9e98 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,13 +30,42 @@ + android:name=".activity.user.UserActivity" + android:launchMode="singleTask" + android:screenOrientation="portrait" /> + android:name=".activity.login.LoginActivity" + android:launchMode="singleTask" + android:screenOrientation="portrait" /> + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/hainaos/vc/activity/category/CategoryViewModel.java b/app/src/main/java/com/hainaos/vc/activity/category/CategoryViewModel.java deleted file mode 100644 index 6d8dea9..0000000 --- a/app/src/main/java/com/hainaos/vc/activity/category/CategoryViewModel.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.hainaos.vc.activity.category; - -import android.os.Environment; -import android.util.Log; - -import androidx.lifecycle.MutableLiveData; - -import com.hainaos.vc.base.mvvm.BaseViewModel; -import com.hainaos.vc.bean.LocalVideoInfo; -import com.hainaos.vc.databinding.ActivityCategoryBinding; -import com.hainaos.vc.utils.VideoUtils; -import com.trello.rxlifecycle4.android.ActivityEvent; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class CategoryViewModel extends BaseViewModel { - - private static final String TAG = "CategoryViewModel"; - - @Override - public ActivityCategoryBinding getVDBinding() { - return binding; - } - - @Override - public void onDestroy() { - - } - - public MutableLiveData> mLocalVideoInfosData = new MutableLiveData<>(); - - public void getViedoList(String dir) { - File file = new File(Environment.getExternalStorageDirectory() + File.separator + "haina" + File.separator + dir); - if (file.exists()) { - String[] strings = file.list(); - Log.e(TAG, "getViedoList: " + Arrays.toString(strings)); - if (strings != null) { - List paths = new ArrayList<>(Arrays.asList(strings)); - ArrayList localVideoInfos = paths.stream().map(new Function() { - @Override - public LocalVideoInfo apply(String s) { - LocalVideoInfo localVideoInfo = new LocalVideoInfo(); - localVideoInfo.setFile_name(VideoUtils.getFileNameWithoutExtension(s)); - localVideoInfo.setLocalPath(new File(file.getAbsolutePath() + File.separator + s).getAbsolutePath()); - return localVideoInfo; - } - }).collect(Collectors.toCollection(ArrayList::new)); - mLocalVideoInfosData.setValue(localVideoInfos); - } else { - mLocalVideoInfosData.setValue(null); - } - } else { - mLocalVideoInfosData.setValue(null); - } - } -} diff --git a/app/src/main/java/com/hainaos/vc/activity/category/list/CategoryListActivity.java b/app/src/main/java/com/hainaos/vc/activity/category/list/CategoryListActivity.java new file mode 100644 index 0000000..6b5549d --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/category/list/CategoryListActivity.java @@ -0,0 +1,59 @@ +package com.hainaos.vc.activity.category.list; + +import android.view.View; + +import androidx.lifecycle.Observer; +import androidx.recyclerview.widget.GridLayoutManager; + +import com.hainaos.vc.R; +import com.hainaos.vc.adapter.CategoryAdapter; +import com.hainaos.vc.base.mvvm.BaseMvvmActivity; +import com.hainaos.vc.bean.CategoryInfo; +import com.hainaos.vc.databinding.ActivityCategoryListBinding; + +import java.util.List; + +public class CategoryListActivity extends BaseMvvmActivity { + private static final String TAG = "CategoryListActivity"; + + private CategoryAdapter mCategoryAdapter; + + @Override + protected int getLayoutId() { + return R.layout.activity_category_list; + } + + @Override + protected void initDataBinding() { + mViewModel.setCtx(this); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView() { + mCategoryAdapter = new CategoryAdapter(); + mViewDataBinding.rvCategory.setLayoutManager(new GridLayoutManager(CategoryListActivity.this, 5)); + mViewDataBinding.rvCategory.setAdapter(mCategoryAdapter); + } + + @Override + protected void initData() { + mViewModel.mCategoryInfoListData.observe(this, new Observer>() { + @Override + public void onChanged(List categoryInfos) { + mCategoryAdapter.setCategoryInfos(categoryInfos); + } + }); + mViewModel.getCategoryList(); + + } + + + public class BtnClick { + public void exit(View view) { + finish(); + } + } +} diff --git a/app/src/main/java/com/hainaos/vc/activity/category/list/CategoryListViewModel.java b/app/src/main/java/com/hainaos/vc/activity/category/list/CategoryListViewModel.java new file mode 100644 index 0000000..dd364f2 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/category/list/CategoryListViewModel.java @@ -0,0 +1,66 @@ +package com.hainaos.vc.activity.category.list; + +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CategoryInfo; +import com.hainaos.vc.databinding.ActivityCategoryListBinding; +import com.hainaos.vc.network.NetInterfaceManager; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; + +import java.util.List; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; + +public class CategoryListViewModel extends BaseViewModel { + + private static final String TAG = "CategoryViewModel"; + + @Override + public ActivityCategoryListBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } + + public MutableLiveData> mCategoryInfoListData = new MutableLiveData<>(); + + public void getCategoryList() { + NetInterfaceManager.getInstance().getCategoryListObservable() + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getCategoryList", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse> baseResponse) { + Log.e("getCategoryList", "onNext: " + baseResponse); + if (baseResponse.code == 200) { + List categoryInfos = baseResponse.data; + mCategoryInfoListData.setValue(categoryInfos); + } + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getCategoryList", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("getCategoryList", "onComplete: "); + } + }); + } +} diff --git a/app/src/main/java/com/hainaos/vc/activity/category/CategoryActivity.java b/app/src/main/java/com/hainaos/vc/activity/category/local/LocalCategoryActivity.java similarity index 71% rename from app/src/main/java/com/hainaos/vc/activity/category/CategoryActivity.java rename to app/src/main/java/com/hainaos/vc/activity/category/local/LocalCategoryActivity.java index a783787..4c90c09 100644 --- a/app/src/main/java/com/hainaos/vc/activity/category/CategoryActivity.java +++ b/app/src/main/java/com/hainaos/vc/activity/category/local/LocalCategoryActivity.java @@ -1,4 +1,4 @@ -package com.hainaos.vc.activity.category; +package com.hainaos.vc.activity.category.local; import android.content.Intent; import android.view.View; @@ -11,9 +11,10 @@ import com.hainaos.vc.R; import com.hainaos.vc.adapter.VideoAdapter; import com.hainaos.vc.base.mvvm.BaseMvvmActivity; import com.hainaos.vc.bean.LocalVideoInfo; -import com.hainaos.vc.databinding.ActivityCategoryBinding; +import com.hainaos.vc.databinding.ActivityCategoryLocalBinding; +import com.hainaos.vc.utils.FileUtils; import com.hainaos.vc.utils.ScreenUtils; -import com.hainaos.vc.utils.VideoUtils; +import com.hainaos.vc.utils.ToastUtil; import com.hainaos.vc.view.CustomDialog; import com.hainaos.vc.view.EquallyDividedItemDecoration; import com.hainaos.vc.view.RecycleGridLayoutManager; @@ -21,9 +22,9 @@ import com.hainaos.vc.view.RecycleGridLayoutManager; import java.io.File; import java.util.ArrayList; -public class CategoryActivity extends BaseMvvmActivity { +public class LocalCategoryActivity extends BaseMvvmActivity { + private static final String TAG = "LocalCategoryActivity"; - private static final String TAG = "CategoryActivity"; private String mTitle; private String mDirName; @@ -33,7 +34,7 @@ public class CategoryActivity extends BaseMvvmActivity>() { @Override public void onChanged(ArrayList localVideoInfos) { + if (localVideoInfos == null || localVideoInfos.isEmpty()) { + mViewDataBinding.clNodata.setVisibility(View.VISIBLE); + mViewDataBinding.rvVideo.setVisibility(View.GONE); + } else { + mViewDataBinding.clNodata.setVisibility(View.GONE); + mViewDataBinding.rvVideo.setVisibility(View.VISIBLE); + } mVideoAdapter.setData(localVideoInfos); mViewDataBinding.swipeRefreshLayout.setRefreshing(false); } @@ -92,9 +100,9 @@ public class CategoryActivity extends BaseMvvmActivity { + + private static final String TAG = "CategoryViewModel"; + + @Override + public ActivityCategoryLocalBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } + + public MutableLiveData> mLocalVideoInfosData = new MutableLiveData<>(); + + public void getViedoList(String dir) { + File file = new File(Environment.getExternalStorageDirectory() + File.separator + "haina" + File.separator + dir); + Observable + .fromCallable(new Callable>() { + @Override + public List call() throws Exception { + String[] strings = file.list(); + Log.e(TAG, "getViedoList: " + Arrays.toString(strings)); + if (strings != null) { + return new ArrayList<>(Arrays.asList(strings)); + } else { + return null; + } + } + }) + .subscribeOn(Schedulers.io()) + .map(new io.reactivex.rxjava3.functions.Function, ArrayList>() { + @Override + public ArrayList apply(List stringList) throws Throwable { + ArrayList localVideoInfos = stringList.stream().map(new Function() { + @Override + public LocalVideoInfo apply(String s) { + File videoFile = new File(file.getAbsolutePath() + File.separator + s); + LocalVideoInfo localVideoInfo = new LocalVideoInfo(); + localVideoInfo.setFile_name(FileUtils.getFileNameWithoutExtension(s)); + localVideoInfo.setLocalPath(videoFile.getAbsolutePath()); + + long time = System.currentTimeMillis(); + FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever(); + mmr.setDataSource(videoFile.getAbsolutePath()); + int duration = Integer.parseInt(mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION)); + Log.e("AudioUtils", "getDurationInMilliseconds: " + (System.currentTimeMillis() - time)); + mmr.release();//释放资源 + localVideoInfo.setDuration(duration / 1000); + return localVideoInfo; + } + }).collect(Collectors.toCollection(ArrayList::new)); + return localVideoInfos; + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getViedoList", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull ArrayList localVideoInfos) { + Log.e("getViedoList", "onNext: "); + mLocalVideoInfosData.setValue(localVideoInfos); + + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getViedoList", "onError: " + e.getMessage()); + mLocalVideoInfosData.setValue(null); + } + + @Override + public void onComplete() { + Log.e("getViedoList", "onComplete: "); + } + }); + + } +} diff --git a/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoActivity.java b/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoActivity.java new file mode 100644 index 0000000..3281910 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoActivity.java @@ -0,0 +1,172 @@ +package com.hainaos.vc.activity.category.online; + +import android.content.Intent; +import android.view.View; + +import androidx.lifecycle.Observer; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.hainaos.vc.R; +import com.hainaos.vc.adapter.CategoryVideoAdapter; +import com.hainaos.vc.base.mvvm.BaseMvvmActivity; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CategoryInfo; +import com.hainaos.vc.bean.CategoryVideoInfo; +import com.hainaos.vc.bean.VideoListData; +import com.hainaos.vc.databinding.ActivityCategoryVideoBinding; +import com.hainaos.vc.fragment.passwd.PasswdDialogFragment; +import com.hainaos.vc.utils.FileUtils; +import com.hainaos.vc.utils.ScreenUtils; +import com.hainaos.vc.view.CustomDialog; +import com.hainaos.vc.view.EquallyDividedItemDecoration; +import com.hainaos.vc.view.RecycleGridLayoutManager; +import com.hjq.toast.Toaster; + +import java.io.File; +import java.util.List; + +public class CategoryVideoActivity extends BaseMvvmActivity { + private static final String TAG = "CategoryActivity"; + + private CategoryInfo mCategoryInfo; + private String mPasswd = ""; + private CategoryVideoAdapter mCategoryVideoAdapter; + + private static final int SPAN_COUNT = 3; + + @Override + protected int getLayoutId() { + return R.layout.activity_category_video; + } + + @Override + protected void initDataBinding() { + mViewModel.setCtx(this); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView() { + RecycleGridLayoutManager manager = new RecycleGridLayoutManager(CategoryVideoActivity.this, SPAN_COUNT); + mViewDataBinding.rvVideo.setLayoutManager(manager); + + EquallyDividedItemDecoration equallyDividedItemDecoration = new EquallyDividedItemDecoration(SPAN_COUNT, ScreenUtils.dip2px(CategoryVideoActivity.this, 1)); + mViewDataBinding.rvVideo.addItemDecoration(equallyDividedItemDecoration); + mViewDataBinding.rvVideo.setNestedScrollingEnabled(false); + + ((DefaultItemAnimator) mViewDataBinding.rvVideo.getItemAnimator()).setSupportsChangeAnimations(false); + mCategoryVideoAdapter = new CategoryVideoAdapter(); + mViewDataBinding.rvVideo.setAdapter(mCategoryVideoAdapter); + + mViewDataBinding.swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + mViewDataBinding.swipeRefreshLayout.setRefreshing(true); + mViewModel.getVideoList(mCategoryInfo.getUuid(), mPasswd); + } + }); + } + + @Override + protected void initData() { + Intent intent = getIntent(); + mCategoryInfo = (CategoryInfo) intent.getSerializableExtra("CategoryInfo"); + if (mCategoryInfo == null) { + Toaster.show("获取分类信息失败"); + finish(); + return; + } + mCategoryVideoAdapter.setDirName(mCategoryInfo.getFolder()); + mPasswd = intent.getStringExtra("Password"); + mViewDataBinding.setTitle(mCategoryInfo.getCategory_name()); + + +// mViewModel.mLocalVideoInfosData.observe(this, new Observer>() { +// @Override +// public void onChanged(ArrayList localVideoInfos) { +// +// } +// }); +// mViewModel.getViedoList(mCategoryInfo.getUuid()); + + mViewModel.mCategoryVideoInfoListData.observe(this, new Observer>() { + @Override + public void onChanged(BaseResponse baseResponse) { + if (baseResponse.code == 200) { + VideoListData videoListData = baseResponse.data; + List categoryVideoInfos = videoListData.getData(); + mCategoryVideoAdapter.setData(categoryVideoInfos); + + if (categoryVideoInfos == null || categoryVideoInfos.isEmpty()) { + mViewDataBinding.clNodata.setVisibility(View.VISIBLE); + mViewDataBinding.rvVideo.setVisibility(View.GONE); + } else { + mViewDataBinding.clNodata.setVisibility(View.GONE); + mViewDataBinding.rvVideo.setVisibility(View.VISIBLE); + } + } else { + Toaster.show(baseResponse.msg); + PasswdDialogFragment passwdDialogFragment = new PasswdDialogFragment(mCategoryInfo); + passwdDialogFragment.setConfimCallback(new PasswdDialogFragment.ConfimCallback() { + @Override + public void onConfig(String passwd) { + mPasswd = passwd; + mViewModel.getVideoList(mCategoryInfo.getUuid(), mPasswd); + } + }); + passwdDialogFragment.show(getSupportFragmentManager(), "PasswdDialogFragment"); + + + } + mViewDataBinding.swipeRefreshLayout.setRefreshing(false); + } + }); + + mViewModel.getVideoList(mCategoryInfo.getUuid(), mPasswd); + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mCategoryVideoAdapter != null) { + mCategoryVideoAdapter.unregister(); + } + } + + private void showDialog(String path, int position) { + CustomDialog dialog = new CustomDialog(CategoryVideoActivity.this); + dialog.setTitle("删除文件") + .setMessage("确定要删除文件 " + FileUtils.getFileNameWithoutExtension(path) + "吗") + .setPositive("确定") + .setNegtive("取消") + .setOnClickBottomListener(new CustomDialog.OnClickBottomListener() { + @Override + public void onPositiveClick() { + dialog.dismiss(); + File file = new File(path); +// if (file.delete()) { +// mVideoAdapter.removeItem(position); +// ToastUtil.show("删除成功"); +// } else { +// ToastUtil.show("删除失败,检查权限是否开启"); +// } + } + + @Override + public void onNegtiveClick() { + dialog.dismiss(); + } + }); + dialog.show(); + } + + public class BtnClick { + public void exit(View view) { + finish(); + } + } +} diff --git a/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoViewModel.java b/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoViewModel.java new file mode 100644 index 0000000..e51b4b6 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/category/online/CategoryVideoViewModel.java @@ -0,0 +1,101 @@ +package com.hainaos.vc.activity.category.online; + +import android.os.Environment; +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.LocalVideoInfo; +import com.hainaos.vc.bean.VideoListData; +import com.hainaos.vc.databinding.ActivityCategoryVideoBinding; +import com.hainaos.vc.network.NetInterfaceManager; +import com.hainaos.vc.utils.FileUtils; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; + +public class CategoryVideoViewModel extends BaseViewModel { + + private static final String TAG = "CategoryViewModel"; + + @Override + public ActivityCategoryVideoBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } + + @Deprecated + public MutableLiveData> mLocalVideoInfosData = new MutableLiveData<>(); + + @Deprecated + public void getViedoList(String dir) { + File file = new File(Environment.getExternalStorageDirectory() + File.separator + "haina" + File.separator + dir); + if (file.exists()) { + String[] strings = file.list(); + Log.e(TAG, "getViedoList: " + Arrays.toString(strings)); + if (strings != null) { + List paths = new ArrayList<>(Arrays.asList(strings)); + ArrayList localVideoInfos = paths.stream().map(new Function() { + @Override + public LocalVideoInfo apply(String s) { + LocalVideoInfo localVideoInfo = new LocalVideoInfo(); + localVideoInfo.setFile_name(FileUtils.getFileNameWithoutExtension(s)); + localVideoInfo.setLocalPath(new File(file.getAbsolutePath() + File.separator + s).getAbsolutePath()); + return localVideoInfo; + } + }).collect(Collectors.toCollection(ArrayList::new)); + mLocalVideoInfosData.setValue(localVideoInfos); + } else { + mLocalVideoInfosData.setValue(null); + } + } else { + mLocalVideoInfosData.setValue(null); + } + } + + public MutableLiveData> mCategoryVideoInfoListData = new MutableLiveData<>(); + + public void getVideoList(String uuid, String password) { + NetInterfaceManager.getInstance().getVideoListObservable(uuid, password) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getVideoList", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse listBaseResponse) { + Log.e("getVideoList", "onNext: "); + mCategoryVideoInfoListData.setValue(listBaseResponse); + + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getVideoList", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("getVideoList", "onComplete: "); + } + }); + } +} diff --git a/app/src/main/java/com/hainaos/vc/activity/lockpasswd/LockPasswdActivity.java b/app/src/main/java/com/hainaos/vc/activity/lockpasswd/LockPasswdActivity.java new file mode 100644 index 0000000..7942a83 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/lockpasswd/LockPasswdActivity.java @@ -0,0 +1,177 @@ +package com.hainaos.vc.activity.lockpasswd; + +import android.app.Activity; +import android.content.Intent; +import android.text.Editable; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; + +import androidx.lifecycle.Observer; + +import com.hainaos.vc.R; +import com.hainaos.vc.base.mvvm.BaseMvvmActivity; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.databinding.ActivityPasswdLockBinding; +import com.hjq.toast.Toaster; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.observers.DisposableObserver; +import io.reactivex.rxjava3.schedulers.Schedulers; + +public class LockPasswdActivity extends BaseMvvmActivity { + + private Disposable mDisposable; + private String mVerifyKey; + + @Override + protected int getLayoutId() { + return R.layout.activity_passwd_lock; + } + + @Override + protected void initDataBinding() { + mViewModel.setCtx(this); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView() { + + } + + @Override + protected void initData() { + mViewModel.mCodeInfoyData.observe(this, new Observer>() { + @Override + public void onChanged(BaseResponse response) { + if (response.code == 200) { + Toaster.show("验证码发送成功"); + CodeInfo codeInfo = response.data; + mVerifyKey = codeInfo.getVerify_key(); + startCountdown(codeInfo.getTtl()); + } else { + Toaster.show(response.msg); + setCodeTextEnable(); + } + } + }); + + mViewModel.mSuccessfulData.observe(this, new Observer() { + @Override + public void onChanged(Boolean aBoolean) { + if (aBoolean) { + Toaster.show("修改成功"); + Intent intent = new Intent(); + setResult(Activity.RESULT_OK, intent); + finish(); + } + } + }); + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mDisposable != null && !mDisposable.isDisposed()) { + mDisposable.dispose(); + mDisposable = null; + } + } + + + private void startCountdown(int countdownTime) { + // 倒计时总时长 + if (countdownTime == 0) { + countdownTime = 60; + } + + int finalCountdownTime = countdownTime; + mDisposable = Observable.interval(0, 1, TimeUnit.SECONDS) // 立即执行,间隔1秒 + .take(countdownTime + 1) // 总共发射的次数(从0开始,所以+1) + .map(aLong -> finalCountdownTime - aLong) // 将递增序列转换为递减的剩余时间 + .subscribeOn(Schedulers.computation()) // 计时任务在计算线程执行 + .observeOn(AndroidSchedulers.mainThread()) // 结果回调到主线程更新UI + .compose(RxLifecycle.bindUntilEvent(getLifecycleSubject(), ActivityEvent.DESTROY)) + .subscribeWith(new DisposableObserver() { + @Override + public void onNext(Long remainingTime) { + Log.v("startCountdown", "onNext: " + remainingTime); + // 每秒更新UI,显示剩余时间 + mViewDataBinding.tvGetCode.setText(remainingTime + "秒"); + mViewDataBinding.tvGetCode.setEnabled(true);// 倒计时期间禁用按钮 + } + + @Override + public void onError(Throwable e) { + // 错误处理(通常很少发生) + Log.e("startCountdown", "Error: ", e); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("startCountdown", "onComplete: "); + setCodeTextEnable(); + } + }); + } + + + private void setCodeTextEnable() { + mViewDataBinding.tvGetCode.setText("验证码"); + mViewDataBinding.cardView.setEnabled(true); + } + + public class BtnClick { + public void getCode(View view) { + mViewDataBinding.tvGetCode.setText("发送中"); + mViewDataBinding.cardView.setEnabled(false); + mViewModel.sendCode(); + } + + public void restPasswd(View view) { + Editable passwdEditable = mViewDataBinding.etPasswd.getText(); + if (TextUtils.isEmpty(passwdEditable)) { + Toaster.show("请输入新密码"); + return; + } + Editable rePasswdEditable = mViewDataBinding.etConfirmPassword.getText(); + if (TextUtils.isEmpty(rePasswdEditable)) { + Toaster.show("请确认新密码"); + return; + } + Editable codeEditable = mViewDataBinding.etCode.getText(); + if (TextUtils.isEmpty(codeEditable)) { + Toaster.show("请输入验证码"); + return; + } + if (TextUtils.isEmpty(mVerifyKey)) { + Toaster.show("请重新获取验证码"); + return; + } + String passwd = passwdEditable.toString(); + String rePasswd = rePasswdEditable.toString(); + + if (!passwd.equals(rePasswd)) { + Toaster.show("两次输入密码不一致,请确认"); + return; + } + String captcha = codeEditable.toString(); + + mViewModel.restPasswd(passwd, rePasswd, captcha, mVerifyKey); + } + } + + +} diff --git a/app/src/main/java/com/hainaos/vc/activity/lockpasswd/LockPasswdViewModel.java b/app/src/main/java/com/hainaos/vc/activity/lockpasswd/LockPasswdViewModel.java new file mode 100644 index 0000000..9f0520d --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/lockpasswd/LockPasswdViewModel.java @@ -0,0 +1,89 @@ +package com.hainaos.vc.activity.lockpasswd; + +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.databinding.ActivityPasswdLockBinding; +import com.hainaos.vc.network.NetInterfaceManager; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; + +public class LockPasswdViewModel extends BaseViewModel { + + @Override + public ActivityPasswdLockBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } + + public MutableLiveData> mCodeInfoyData = new MutableLiveData<>(); + + public void sendCode() { + NetInterfaceManager.getInstance().getSetCodeObservable() + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("sendCode", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("sendCode", "onNext: "); + mCodeInfoyData.setValue(baseResponse); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("sendCode", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("sendCode", "onComplete: "); + } + }); + } + + public MutableLiveData mSuccessfulData = new MutableLiveData<>(); + + public void restPasswd(String password, String confirm_password, String captcha, String verify_key) { + NetInterfaceManager.getInstance().getSetPasswdObservable(password, confirm_password, captcha, verify_key) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("restPasswd", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("restPasswd", "onNext: " + baseResponse); + mSuccessfulData.setValue(baseResponse.code == 200); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("restPasswd", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("restPasswd", "onComplete: "); + } + }); + } + +} diff --git a/app/src/main/java/com/hainaos/vc/activity/login/LoginActivity.java b/app/src/main/java/com/hainaos/vc/activity/login/LoginActivity.java index 43749da..7f12007 100644 --- a/app/src/main/java/com/hainaos/vc/activity/login/LoginActivity.java +++ b/app/src/main/java/com/hainaos/vc/activity/login/LoginActivity.java @@ -1,11 +1,37 @@ package com.hainaos.vc.activity.login; +import android.app.Activity; +import android.content.Intent; +import android.text.Editable; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; + +import androidx.lifecycle.Observer; + import com.hainaos.vc.R; import com.hainaos.vc.base.mvvm.BaseMvvmActivity; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.bean.LoginInfo; import com.hainaos.vc.databinding.ActivityLoginBinding; +import com.hjq.toast.Toaster; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.observers.DisposableObserver; +import io.reactivex.rxjava3.schedulers.Schedulers; public class LoginActivity extends BaseMvvmActivity { + private Disposable mDisposable; + private String mVerifyKey; + @Override protected int getLayoutId() { return R.layout.activity_login; @@ -26,10 +52,129 @@ public class LoginActivity extends BaseMvvmActivity>() { + @Override + public void onChanged(BaseResponse response) { + if (response.code == 200) { + Toaster.show("验证码发送成功"); + CodeInfo codeInfo = response.data; + mVerifyKey = codeInfo.getVerify_key(); + startCountdown(codeInfo.getTtl()); + } else { + Toaster.show(response.msg); + setCodeTextEnable(); + } + } + }); + mViewModel.mLoginInfoMutableLiveData.observe(this, new Observer() { + @Override + public void onChanged(LoginInfo loginInfo) { + if (loginInfo != null) { + Toaster.show("登录成功"); + Intent intent = new Intent(); + setResult(Activity.RESULT_OK, intent); + finish(); + } + } + }); + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mDisposable != null && !mDisposable.isDisposed()) { + mDisposable.dispose(); + mDisposable = null; + } + } + + + private void startCountdown(int countdownTime) { + // 倒计时总时长 + if (countdownTime == 0) { + countdownTime = 60; + } + + int finalCountdownTime = countdownTime; + mDisposable = Observable.interval(0, 1, TimeUnit.SECONDS) // 立即执行,间隔1秒 + .take(countdownTime + 1) // 总共发射的次数(从0开始,所以+1) + .map(aLong -> finalCountdownTime - aLong) // 将递增序列转换为递减的剩余时间 + .subscribeOn(Schedulers.computation()) // 计时任务在计算线程执行 + .observeOn(AndroidSchedulers.mainThread()) // 结果回调到主线程更新UI + .compose(RxLifecycle.bindUntilEvent(getLifecycleSubject(), ActivityEvent.DESTROY)) + .subscribeWith(new DisposableObserver() { + @Override + public void onNext(Long remainingTime) { + Log.v("startCountdown", "onNext: " + remainingTime); + // 每秒更新UI,显示剩余时间 + mViewDataBinding.tvGetCode.setText(remainingTime + "秒"); + mViewDataBinding.tvGetCode.setEnabled(true);// 倒计时期间禁用按钮 + } + + @Override + public void onError(Throwable e) { + // 错误处理(通常很少发生) + Log.e("startCountdown", "Error: ", e); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("startCountdown", "onComplete: "); + setCodeTextEnable(); + } + }); + } + + + private void setCodeTextEnable() { + mViewDataBinding.tvGetCode.setText("验证码"); + mViewDataBinding.cardView.setEnabled(true); } public class BtnClick { + public void getCode(View view) { + mViewDataBinding.tvGetCode.setText("发送中"); + mViewDataBinding.cardView.setEnabled(false); + Editable editable = mViewDataBinding.etPhoneNumber.getText(); + if (TextUtils.isEmpty(editable)) { + Toaster.show("请输入手机号"); + setCodeTextEnable(); + return; + } + String phoneNumber = editable.toString(); + if (TextUtils.isEmpty(phoneNumber)) { + Toaster.show("请输入手机号"); + setCodeTextEnable(); + return; + } + mViewModel.sendCode(phoneNumber); + } + + public void codeLogin(View view) { + Editable phoneEditable = mViewDataBinding.etPhoneNumber.getText(); + if (TextUtils.isEmpty(phoneEditable)) { + Toaster.show("请输入手机号"); + return; + } + Editable codeEditable = mViewDataBinding.etCode.getText(); + if (TextUtils.isEmpty(codeEditable)) { + Toaster.show("请输入验证码"); + return; + } + if (TextUtils.isEmpty(mVerifyKey)) { + Toaster.show("请重新获取验证码"); + return; + } + String phoneNumber = phoneEditable.toString(); + String captcha = codeEditable.toString(); + + mViewModel.codeLogin(mVerifyKey, phoneNumber, captcha); + } } + + } diff --git a/app/src/main/java/com/hainaos/vc/activity/login/LoginViewModel.java b/app/src/main/java/com/hainaos/vc/activity/login/LoginViewModel.java index e990114..a447127 100644 --- a/app/src/main/java/com/hainaos/vc/activity/login/LoginViewModel.java +++ b/app/src/main/java/com/hainaos/vc/activity/login/LoginViewModel.java @@ -1,9 +1,24 @@ package com.hainaos.vc.activity.login; +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.bean.LoginInfo; import com.hainaos.vc.databinding.ActivityLoginBinding; +import com.hainaos.vc.network.NetInterfaceManager; +import com.hainaos.vc.utils.LoginUtils; +import com.hjq.toast.Toaster; +import com.trello.rxlifecycle4.RxLifecycle; import com.trello.rxlifecycle4.android.ActivityEvent; +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; + public class LoginViewModel extends BaseViewModel { @Override @@ -15,4 +30,69 @@ public class LoginViewModel extends BaseViewModel> mCodeInfoyData = new MutableLiveData<>(); + + public void sendCode(String phoneNumber) { + NetInterfaceManager.getInstance().getSendCodeObservable(phoneNumber) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("sendCode", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("sendCode", "onNext: "); + mCodeInfoyData.setValue(baseResponse); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("sendCode", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("sendCode", "onComplete: "); + } + }); + } + + public MutableLiveData mLoginInfoMutableLiveData = new MutableLiveData<>(); + + public void codeLogin(String verify_key, String mobile, String captcha) { + NetInterfaceManager.getInstance().getPhoneLoginObservable(verify_key, mobile, captcha) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("codeLogin", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("codeLogin", "onNext: " + baseResponse); + if (baseResponse.code == 200) { + LoginInfo loginInfo = baseResponse.data; + LoginUtils.getInstance().setLoginInfo(loginInfo); + mLoginInfoMutableLiveData.setValue(loginInfo); + } else { + LoginUtils.getInstance().clearLoginInfo(); + Toaster.show(baseResponse.msg); + } + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("codeLogin", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("codeLogin", "onComplete: "); + } + }); + } } diff --git a/app/src/main/java/com/hainaos/vc/activity/main/MainActivity.java b/app/src/main/java/com/hainaos/vc/activity/main/MainActivity.java index 9501392..96926d7 100644 --- a/app/src/main/java/com/hainaos/vc/activity/main/MainActivity.java +++ b/app/src/main/java/com/hainaos/vc/activity/main/MainActivity.java @@ -15,15 +15,24 @@ import android.view.View; import android.widget.Toast; import androidx.core.app.ActivityCompat; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.lifecycle.Observer; +import com.hainaos.vc.BuildConfig; import com.hainaos.vc.R; -import com.hainaos.vc.activity.category.CategoryActivity; +import com.hainaos.vc.activity.category.local.LocalCategoryActivity; import com.hainaos.vc.activity.login.LoginActivity; +import com.hainaos.vc.base.BaseFragmentPagerAdapter; import com.hainaos.vc.base.mvvm.BaseMvvmActivity; +import com.hainaos.vc.bean.uiuios.AppUpdateInfo; import com.hainaos.vc.config.CommonConfig; import com.hainaos.vc.databinding.ActivityMainBinding; import com.hainaos.vc.dialog.PermissionsDialog; import com.hainaos.vc.dialog.PrivacyPolicyDialog; +import com.hainaos.vc.fragment.app.AppFragment; +import com.hainaos.vc.fragment.category.CategoryFragment; +import com.hainaos.vc.utils.ApkUtils; import com.hainaos.vc.utils.JgyUtils; import com.hainaos.vc.utils.ToastUtil; import com.hainaos.vc.utils.Utils; @@ -46,6 +55,10 @@ public class MainActivity extends BaseMvvmActivity mFragments; + private static final int REQUEST_PERMISSION_CODE = 200; String[] permissions = new String[]{ @@ -75,11 +88,36 @@ public class MainActivity extends BaseMvvmActivity { private static final String TAG = "MainViewModel"; @@ -17,5 +49,160 @@ public class MainViewModel extends BaseViewModel() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("checkUpdate", "onSubscribe: "); + } + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("checkUpdate", "onNext: " + baseResponse); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("checkUpdate", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("checkUpdate", "onComplete: "); + } + }); + } + + public MutableLiveData mAppUpdateInfoUiUiOSData = new MutableLiveData<>(); + + public void checkUpdateUiUiOS(String pkg) { + NetInterfaceManager.getInstance().getCheckUpdateObservable(pkg) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("checkUpdate", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse appUpdateInfoBaseResponse) { + Log.e("checkUpdate", "onNext: " + appUpdateInfoBaseResponse); + if (appUpdateInfoBaseResponse.code == 200) { + AppUpdateInfo appUpdateInfo = appUpdateInfoBaseResponse.data; + mAppUpdateInfoUiUiOSData.setValue(appUpdateInfo); + } else { + mAppUpdateInfoUiUiOSData.setValue(null); + } + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("checkUpdate", "onError: "); + Toaster.show("网络连接失败"); + } + + @Override + public void onComplete() { + Log.e("checkUpdate", "onComplete: "); + } + }); + } + + private static final List mExcludePackages = new ArrayList() {{ + this.add(BuildConfig.APPLICATION_ID); + }}; + + public MutableLiveData> mHomeAppInfoListData = new MutableLiveData<>(); + + public void getAppList() { + Observable.fromCallable(new Callable>() { + @Override + public List call() throws Exception { + List homeAppInfos = new ArrayList<>(); + homeAppInfos.add(new HomeAppInfo("分类1", "", "", "1", true)); + homeAppInfos.add(new HomeAppInfo("分类2", "", "", "2", true)); + homeAppInfos.add(new HomeAppInfo("分类3", "", "", "3", true)); + homeAppInfos.add(new HomeAppInfo("分类4", "", "", "4", true)); + homeAppInfos.add(new HomeAppInfo("分类5", "", "", "5", true)); + homeAppInfos.add(new HomeAppInfo("分类6", "", "", "6", true)); + homeAppInfos.add(new HomeAppInfo("分类7", "", "", "7", true)); + homeAppInfos.add(new HomeAppInfo("分类8", "", "", "8", true)); + homeAppInfos.add(new HomeAppInfo("分类9", "", "", "9", true)); + homeAppInfos.add(new HomeAppInfo("分类10", "", "", "10", true)); + + homeAppInfos.add(new HomeAppInfo("用户中心", "user_center", "", "", true)); + + PackageManager packageManager = getCtx().getPackageManager(); + // 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent + Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null); + resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER); + + // 通过getPackageManager()的queryIntentActivities方法遍历,得到所有能打开的app的packageName + List resolveinfoList = packageManager.queryIntentActivities(resolveIntent, 0); + List appInfos = resolveinfoList + .stream() + .filter(new Predicate() { + @Override + public boolean test(ResolveInfo resolveInfo) { + return !mExcludePackages.contains(resolveInfo.activityInfo.packageName); + } + }) + .sorted(new Comparator() { + @Override + public int compare(ResolveInfo o1, ResolveInfo o2) { + if ((o1.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) <= (o2.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)) { + return 1; + } else { + return -1; + } + } + }) + .map(new Function() { + @Override + public HomeAppInfo apply(ResolveInfo resolveInfo) { + return new HomeAppInfo(resolveInfo.loadLabel(packageManager).toString(), resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name, "", false); + } + }) + .sorted(new Comparator() { + @Override + public int compare(HomeAppInfo o1, HomeAppInfo o2) { + return Collator.getInstance(Locale.CHINESE).compare(o1.getName(), o2.getName()); + } + }) + + .collect(Collectors.toList()); + + homeAppInfos.addAll(appInfos); + + return homeAppInfos; + } + }).subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getAppList", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull List homeAppInfos) { + Log.e("getAppList", "onNext: " + homeAppInfos.size()); + mHomeAppInfoListData.setValue(homeAppInfos); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getAppList", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("getAppList", "onComplete: "); + } + }); + + } } diff --git a/app/src/main/java/com/hainaos/vc/activity/mobile/ModifyActivity.java b/app/src/main/java/com/hainaos/vc/activity/mobile/ModifyActivity.java new file mode 100644 index 0000000..8da1fa3 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/mobile/ModifyActivity.java @@ -0,0 +1,174 @@ +package com.hainaos.vc.activity.mobile; + +import android.app.Activity; +import android.content.Intent; +import android.text.Editable; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; + +import androidx.lifecycle.Observer; + +import com.hainaos.vc.R; +import com.hainaos.vc.base.mvvm.BaseMvvmActivity; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.databinding.ActivityModifyMobileBinding; +import com.hjq.toast.Toaster; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.observers.DisposableObserver; +import io.reactivex.rxjava3.schedulers.Schedulers; + +public class ModifyActivity extends BaseMvvmActivity { + + private Disposable mDisposable; + private String mVerifyKey; + + @Override + protected int getLayoutId() { + return R.layout.activity_modify_mobile; + } + + @Override + protected void initDataBinding() { + mViewModel.setCtx(this); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView() { + + } + + @Override + protected void initData() { + mViewModel.mCodeInfoyData.observe(this, new Observer>() { + @Override + public void onChanged(BaseResponse response) { + if (response.code == 200) { + Toaster.show("验证码发送成功"); + CodeInfo codeInfo = response.data; + mVerifyKey = codeInfo.getVerify_key(); + startCountdown(codeInfo.getTtl()); + } else { + Toaster.show(response.msg); + setCodeTextEnable(); + } + } + }); + + mViewModel.mSuccessfulData.observe(this, new Observer() { + @Override + public void onChanged(Boolean aBoolean) { + if (aBoolean) { + Toaster.show("修改成功"); + Intent intent = new Intent(); + setResult(Activity.RESULT_OK, intent); + finish(); + } + } + }); + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mDisposable != null && !mDisposable.isDisposed()) { + mDisposable.dispose(); + mDisposable = null; + } + } + + + private void startCountdown(int countdownTime) { + // 倒计时总时长 + if (countdownTime == 0) { + countdownTime = 60; + } + + int finalCountdownTime = countdownTime; + mDisposable = Observable.interval(0, 1, TimeUnit.SECONDS) // 立即执行,间隔1秒 + .take(countdownTime + 1) // 总共发射的次数(从0开始,所以+1) + .map(aLong -> finalCountdownTime - aLong) // 将递增序列转换为递减的剩余时间 + .subscribeOn(Schedulers.computation()) // 计时任务在计算线程执行 + .observeOn(AndroidSchedulers.mainThread()) // 结果回调到主线程更新UI + .compose(RxLifecycle.bindUntilEvent(getLifecycleSubject(), ActivityEvent.DESTROY)) + .subscribeWith(new DisposableObserver() { + @Override + public void onNext(Long remainingTime) { + Log.v("startCountdown", "onNext: " + remainingTime); + // 每秒更新UI,显示剩余时间 + mViewDataBinding.tvGetCode.setText(remainingTime + "秒"); + mViewDataBinding.tvGetCode.setEnabled(true);// 倒计时期间禁用按钮 + } + + @Override + public void onError(Throwable e) { + // 错误处理(通常很少发生) + Log.e("startCountdown", "Error: ", e); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("startCountdown", "onComplete: "); + setCodeTextEnable(); + } + }); + } + + + private void setCodeTextEnable() { + mViewDataBinding.tvGetCode.setText("验证码"); + mViewDataBinding.cardView.setEnabled(true); + } + + public class BtnClick { + public void getCode(View view) { + mViewDataBinding.tvGetCode.setText("发送中"); + mViewDataBinding.cardView.setEnabled(false); + Editable phoneEditable = mViewDataBinding.etPhoneNumber.getText(); + if (TextUtils.isEmpty(phoneEditable)) { + Toaster.show("请输入手机号码"); + return; + } + String phoneNumber = phoneEditable.toString(); + + mViewModel.sendModifyMobileCode(phoneNumber); + } + + public void restPasswd(View view) { + Editable phoneEditable = mViewDataBinding.etPhoneNumber.getText(); + if (TextUtils.isEmpty(phoneEditable)) { + Toaster.show("请输入手机号码"); + return; + } + + Editable codeEditable = mViewDataBinding.etCode.getText(); + if (TextUtils.isEmpty(codeEditable)) { + Toaster.show("请输入验证码"); + return; + } + if (TextUtils.isEmpty(mVerifyKey)) { + Toaster.show("请重新获取验证码"); + return; + } + String phoneNumber = phoneEditable.toString(); + String captcha = codeEditable.toString(); + + mViewModel.modifyMobileNumber(phoneNumber, captcha, mVerifyKey); + } + } + + +} diff --git a/app/src/main/java/com/hainaos/vc/activity/mobile/ModifyViewModel.java b/app/src/main/java/com/hainaos/vc/activity/mobile/ModifyViewModel.java new file mode 100644 index 0000000..bb12b3f --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/mobile/ModifyViewModel.java @@ -0,0 +1,89 @@ +package com.hainaos.vc.activity.mobile; + +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.databinding.ActivityModifyMobileBinding; +import com.hainaos.vc.network.NetInterfaceManager; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; + +public class ModifyViewModel extends BaseViewModel { + + @Override + public ActivityModifyMobileBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } + + public MutableLiveData> mCodeInfoyData = new MutableLiveData<>(); + + public void sendModifyMobileCode(String phoneNumber) { + NetInterfaceManager.getInstance().getModifyMobileCodeObservable(phoneNumber) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("sendModifyMobileCode", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("sendModifyMobileCode", "onNext: "); + mCodeInfoyData.setValue(baseResponse); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("sendModifyMobileCode", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("sendModifyMobileCode", "onComplete: "); + } + }); + } + + public MutableLiveData mSuccessfulData = new MutableLiveData<>(); + + public void modifyMobileNumber(String mobile, String captcha, String verify_key) { + NetInterfaceManager.getInstance().getModifyMobileObservable(mobile, captcha, verify_key) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("modifyMobileNumber", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("modifyMobileNumber", "onNext: " + baseResponse); + mSuccessfulData.setValue(baseResponse.code == 200); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("modifyMobileNumber", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("modifyMobileNumber", "onComplete: "); + } + }); + } + +} diff --git a/app/src/main/java/com/hainaos/vc/activity/passwd/PasswdActivity.java b/app/src/main/java/com/hainaos/vc/activity/passwd/PasswdActivity.java new file mode 100644 index 0000000..9d4f806 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/passwd/PasswdActivity.java @@ -0,0 +1,177 @@ +package com.hainaos.vc.activity.passwd; + +import android.app.Activity; +import android.content.Intent; +import android.text.Editable; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; + +import androidx.lifecycle.Observer; + +import com.hainaos.vc.R; +import com.hainaos.vc.base.mvvm.BaseMvvmActivity; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.databinding.ActivityPasswdBinding; +import com.hjq.toast.Toaster; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.observers.DisposableObserver; +import io.reactivex.rxjava3.schedulers.Schedulers; + +public class PasswdActivity extends BaseMvvmActivity { + + private Disposable mDisposable; + private String mVerifyKey; + + @Override + protected int getLayoutId() { + return R.layout.activity_passwd; + } + + @Override + protected void initDataBinding() { + mViewModel.setCtx(this); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView() { + + } + + @Override + protected void initData() { + mViewModel.mCodeInfoyData.observe(this, new Observer>() { + @Override + public void onChanged(BaseResponse response) { + if (response.code == 200) { + Toaster.show("验证码发送成功"); + CodeInfo codeInfo = response.data; + mVerifyKey = codeInfo.getVerify_key(); + startCountdown(codeInfo.getTtl()); + } else { + Toaster.show(response.msg); + setCodeTextEnable(); + } + } + }); + + mViewModel.mSuccessfulData.observe(this, new Observer() { + @Override + public void onChanged(Boolean aBoolean) { + if (aBoolean) { + Toaster.show("修改成功"); + Intent intent = new Intent(); + setResult(Activity.RESULT_OK, intent); + finish(); + } + } + }); + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mDisposable != null && !mDisposable.isDisposed()) { + mDisposable.dispose(); + mDisposable = null; + } + } + + + private void startCountdown(int countdownTime) { + // 倒计时总时长 + if (countdownTime == 0) { + countdownTime = 60; + } + + int finalCountdownTime = countdownTime; + mDisposable = Observable.interval(0, 1, TimeUnit.SECONDS) // 立即执行,间隔1秒 + .take(countdownTime + 1) // 总共发射的次数(从0开始,所以+1) + .map(aLong -> finalCountdownTime - aLong) // 将递增序列转换为递减的剩余时间 + .subscribeOn(Schedulers.computation()) // 计时任务在计算线程执行 + .observeOn(AndroidSchedulers.mainThread()) // 结果回调到主线程更新UI + .compose(RxLifecycle.bindUntilEvent(getLifecycleSubject(), ActivityEvent.DESTROY)) + .subscribeWith(new DisposableObserver() { + @Override + public void onNext(Long remainingTime) { + Log.v("startCountdown", "onNext: " + remainingTime); + // 每秒更新UI,显示剩余时间 + mViewDataBinding.tvGetCode.setText(remainingTime + "秒"); + mViewDataBinding.tvGetCode.setEnabled(true);// 倒计时期间禁用按钮 + } + + @Override + public void onError(Throwable e) { + // 错误处理(通常很少发生) + Log.e("startCountdown", "Error: ", e); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("startCountdown", "onComplete: "); + setCodeTextEnable(); + } + }); + } + + + private void setCodeTextEnable() { + mViewDataBinding.tvGetCode.setText("验证码"); + mViewDataBinding.cardView.setEnabled(true); + } + + public class BtnClick { + public void getCode(View view) { + mViewDataBinding.tvGetCode.setText("发送中"); + mViewDataBinding.cardView.setEnabled(false); + mViewModel.sendCode(); + } + + public void restPasswd(View view) { + Editable passwdEditable = mViewDataBinding.etPasswd.getText(); + if (TextUtils.isEmpty(passwdEditable)) { + Toaster.show("请输入新密码"); + return; + } + Editable rePasswdEditable = mViewDataBinding.etConfirmPassword.getText(); + if (TextUtils.isEmpty(rePasswdEditable)) { + Toaster.show("请确认新密码"); + return; + } + Editable codeEditable = mViewDataBinding.etCode.getText(); + if (TextUtils.isEmpty(codeEditable)) { + Toaster.show("请输入验证码"); + return; + } + if (TextUtils.isEmpty(mVerifyKey)) { + Toaster.show("请重新获取验证码"); + return; + } + String passwd = passwdEditable.toString(); + String rePasswd = rePasswdEditable.toString(); + + if (!passwd.equals(rePasswd)) { + Toaster.show("两次输入密码不一致,请确认"); + return; + } + String captcha = codeEditable.toString(); + + mViewModel.restPasswd(passwd, rePasswd, captcha, mVerifyKey); + } + } + + +} diff --git a/app/src/main/java/com/hainaos/vc/activity/passwd/PasswdViewModel.java b/app/src/main/java/com/hainaos/vc/activity/passwd/PasswdViewModel.java new file mode 100644 index 0000000..644f33b --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/passwd/PasswdViewModel.java @@ -0,0 +1,89 @@ +package com.hainaos.vc.activity.passwd; + +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.databinding.ActivityPasswdBinding; +import com.hainaos.vc.network.NetInterfaceManager; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; + +public class PasswdViewModel extends BaseViewModel { + + @Override + public ActivityPasswdBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } + + public MutableLiveData> mCodeInfoyData = new MutableLiveData<>(); + + public void sendCode() { + NetInterfaceManager.getInstance().getResetCodeObservable() + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("sendCode", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("sendCode", "onNext: "); + mCodeInfoyData.setValue(baseResponse); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("sendCode", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("sendCode", "onComplete: "); + } + }); + } + + public MutableLiveData mSuccessfulData = new MutableLiveData<>(); + + public void restPasswd(String password, String confirm_password, String captcha, String verify_key) { + NetInterfaceManager.getInstance().getRestPasswdObservable(password, confirm_password, captcha, verify_key) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("restPasswd", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("restPasswd", "onNext: " + baseResponse); + mSuccessfulData.setValue(baseResponse.code == 200); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("restPasswd", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("restPasswd", "onComplete: "); + } + }); + } + +} diff --git a/app/src/main/java/com/hainaos/vc/activity/pic/GalleryViewModel.java b/app/src/main/java/com/hainaos/vc/activity/pic/GalleryViewModel.java index a0c7dbe..4efdbcf 100644 --- a/app/src/main/java/com/hainaos/vc/activity/pic/GalleryViewModel.java +++ b/app/src/main/java/com/hainaos/vc/activity/pic/GalleryViewModel.java @@ -5,7 +5,6 @@ import androidx.lifecycle.MutableLiveData; import com.hainaos.vc.base.mvvm.BaseViewModel; import com.hainaos.vc.bean.PhotoInfo; import com.hainaos.vc.databinding.ActivityGalleryBinding; -import com.hainaos.vc.network.NetInterfaceManager; import com.trello.rxlifecycle4.android.ActivityEvent; import java.util.ArrayList; @@ -27,16 +26,6 @@ public class GalleryViewModel extends BaseViewModel mCompleteData = new MutableLiveData<>(); public void getHomePhoto() { - NetInterfaceManager.getInstance().getHomePhoto(true, getLifecycle(), new NetInterfaceManager.onPhotoCallback() { - @Override - public void setPhotoList(ArrayList photoList) { - mPhotoInfosData.setValue(photoList); - } - @Override - public void onComplete() { - mCompleteData.setValue(true); - } - }); } } diff --git a/app/src/main/java/com/hainaos/vc/activity/preview/VideoPreviewActivity.java b/app/src/main/java/com/hainaos/vc/activity/preview/VideoPreviewActivity.java new file mode 100644 index 0000000..a49778c --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/preview/VideoPreviewActivity.java @@ -0,0 +1,112 @@ +package com.hainaos.vc.activity.preview; + +import android.content.Intent; +import android.text.TextUtils; +import android.util.Log; +import android.view.MenuItem; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; +import com.hainaos.vc.R; +import com.hainaos.vc.base.mvvm.BaseMvvmActivity; +import com.hainaos.vc.databinding.ActivityVideoPreviewBinding; +import com.hainaos.vc.utils.FileUtils; +import com.hjq.toast.Toaster; + +import cn.jzvd.JZDataSource; +import cn.jzvd.Jzvd; + +public class VideoPreviewActivity extends BaseMvvmActivity { + private static final String TAG = "VideoPreviewActivity"; + + private String mUrl; + private String mCover; + + @Override + public boolean setfitWindow() { + return false; + } + + @Override + protected int getLayoutId() { + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + return R.layout.activity_video_preview; + } + + @Override + protected void initDataBinding() { + mViewModel.setCtx(this); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView() { + + + } + + @Override + protected void initData() { + Intent intent = getIntent(); + mUrl = intent.getStringExtra("url"); + if (TextUtils.isEmpty(mUrl)) { + Toaster.show("未获取到视频地址"); + finish(); + return; + } + Log.e(TAG, "initData: " + mUrl); + mCover = intent.getStringExtra("cover"); + + setData(); + } + + private void setData() { + JZDataSource jzDataSource = new JZDataSource(mUrl, FileUtils.getFileNameWithoutExtension(mUrl)); + mViewDataBinding.videoplayer.setUp(jzDataSource, Jzvd.SCREEN_NORMAL); + mViewDataBinding.videoplayer.posterImageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + Glide.with(mViewDataBinding.videoplayer.posterImageView).load(mCover).into(mViewDataBinding.videoplayer.posterImageView); + mViewDataBinding.videoplayer.startVideoAfterPreloading(); + } + + + @Override + public void onBackPressed() { + if (Jzvd.backPress()) { + return; + } + super.onBackPressed(); + } + + @Override + protected void onPause() { + super.onPause(); + Jzvd.releaseAllVideos(); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + break; + default: + } + return super.onOptionsItemSelected(item); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + } + + public class BtnClick { + + } +} diff --git a/app/src/main/java/com/hainaos/vc/activity/preview/VideoPreviewViewModel.java b/app/src/main/java/com/hainaos/vc/activity/preview/VideoPreviewViewModel.java new file mode 100644 index 0000000..6fb8748 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/preview/VideoPreviewViewModel.java @@ -0,0 +1,18 @@ +package com.hainaos.vc.activity.preview; + +import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.databinding.ActivityVideoPreviewBinding; +import com.trello.rxlifecycle4.android.ActivityEvent; + +public class VideoPreviewViewModel extends BaseViewModel { + + @Override + public ActivityVideoPreviewBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } +} diff --git a/app/src/main/java/com/hainaos/vc/activity/tiktok/TikTokActivity.java b/app/src/main/java/com/hainaos/vc/activity/tiktok/TikTokActivity.java index c189d28..8702e61 100644 --- a/app/src/main/java/com/hainaos/vc/activity/tiktok/TikTokActivity.java +++ b/app/src/main/java/com/hainaos/vc/activity/tiktok/TikTokActivity.java @@ -14,11 +14,11 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.OrientationHelper; import androidx.recyclerview.widget.RecyclerView; -import com.hainaos.vc.CustomJzvd.JzvdStdAssert; import com.hainaos.vc.R; import com.hainaos.vc.adapter.TikTokRecyclerViewAdapter; import com.hainaos.vc.base.mvvm.BaseMvvmActivity; import com.hainaos.vc.bean.LocalVideoInfo; +import com.hainaos.vc.customjzvd.JzvdStdAssert; import com.hainaos.vc.databinding.ActivityTiktokBinding; import com.hainaos.vc.listener.OnViewPagerListener; import com.hainaos.vc.utils.SPUtils; @@ -229,6 +229,7 @@ public class TikTokActivity extends BaseMvvmActivity { + + private static final String TAG = "UserActivity"; + + @Override + protected int getLayoutId() { + return R.layout.activity_user; + } + + @Override + protected void initDataBinding() { + mViewModel.setCtx(this); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView() { + mViewDataBinding.setName(LoginUtils.getInstance().getName()); + mViewDataBinding.setPhoneNumber(LoginUtils.getInstance().getPhoneNumber()); + + } + + @Override + protected void initData() { + mViewModel.mUserInfoMutableLiveData.observe(this, new Observer>() { + @Override + public void onChanged(BaseResponse baseResponse) { + if (baseResponse.code == 200) { + UserInfo userInfo = baseResponse.data; + mViewDataBinding.setAvatar(userInfo.getAvatar()); + mViewDataBinding.setName(userInfo.getNickname()); + mViewDataBinding.setPhoneNumber(userInfo.getMobile()); + mViewDataBinding.tvLogin.setText("退出账号"); + LoginUtils.getInstance().updateUserInfo(userInfo); + } else { + Toaster.show(baseResponse.msg); + mViewDataBinding.tvLogin.setText("登录"); + LoginUtils.getInstance().clearLoginInfo(); + } + } + }); + + mViewModel.getUserInfo(); + } + + @Override + protected void onResume() { + super.onResume(); + mViewDataBinding.tvSn.setText(Utils.getSerial()); + mViewDataBinding.tvStorge.setText("已用" + Utils.getRemnantSize(this) + "/" + Utils.getDataTotalSize(this)); + } + + private ActivityResultLauncher mLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback() { + @Override + public void onActivityResult(ActivityResult result) { + Log.e(TAG, "onActivityResult: " + result); + if (result != null) { + Intent intent = result.getData(); + if (intent != null && result.getResultCode() == Activity.RESULT_OK) { + mViewModel.getUserInfo(); + } + } + } + }); + + public class BtnClick { + public void exit(View view) { + finish(); + } + + public void login(View view) { + if (LoginUtils.getInstance().isLogged()) { + + } else { + mLauncher.launch(new Intent(UserActivity.this, LoginActivity.class)); + } + } + + public void changePasswd(View view) { + if (LoginUtils.getInstance().isLogged()) { + startActivity(new Intent(UserActivity.this, PasswdActivity.class)); + } else { + Toaster.show("请先登录"); + mLauncher.launch(new Intent(UserActivity.this, LoginActivity.class)); + } + } + + public void changeLockPasswd(View view) { + if (LoginUtils.getInstance().isLogged()) { + startActivity(new Intent(UserActivity.this, LockPasswdActivity.class)); + } else { + Toaster.show("请先登录"); + mLauncher.launch(new Intent(UserActivity.this, LoginActivity.class)); + } + } + + public void modifyMobile(View view) { + if (LoginUtils.getInstance().isLogged()) { + mLauncher.launch(new Intent(UserActivity.this, ModifyActivity.class)); + } else { + Toaster.show("请先登录"); + mLauncher.launch(new Intent(UserActivity.this, LoginActivity.class)); + } + } + } +} diff --git a/app/src/main/java/com/hainaos/vc/activity/user/UserViewModel.java b/app/src/main/java/com/hainaos/vc/activity/user/UserViewModel.java new file mode 100644 index 0000000..c971f48 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/activity/user/UserViewModel.java @@ -0,0 +1,62 @@ +package com.hainaos.vc.activity.user; + +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.UserInfo; +import com.hainaos.vc.databinding.ActivityUserBinding; +import com.hainaos.vc.network.NetInterfaceManager; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; + +public class UserViewModel extends BaseViewModel { + + private static final String TAG = "UserViewModel"; + + @Override + public ActivityUserBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } + + public MutableLiveData> mUserInfoMutableLiveData = new MutableLiveData<>(); + + + public void getUserInfo() { + NetInterfaceManager.getInstance().getUserInfoObservable() + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getUserInfo", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("getUserInfo", "onNext: " + baseResponse); + mUserInfoMutableLiveData.setValue(baseResponse); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getUserInfo", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("getUserInfo", "onComplete: "); + } + }); + } +} diff --git a/app/src/main/java/com/hainaos/vc/activity/video/VideoActivity.java b/app/src/main/java/com/hainaos/vc/activity/video/VideoActivity.java index bf8af6e..588b904 100644 --- a/app/src/main/java/com/hainaos/vc/activity/video/VideoActivity.java +++ b/app/src/main/java/com/hainaos/vc/activity/video/VideoActivity.java @@ -31,6 +31,7 @@ import com.hainaos.vc.base.mvvm.BaseMvvmActivity; import com.hainaos.vc.bean.LocalVideoInfo; import com.hainaos.vc.databinding.ActivityVideoBinding; import com.hainaos.vc.gson.GsonUtils; +import com.hainaos.vc.utils.FileUtils; import com.hainaos.vc.utils.SPUtils; import com.hainaos.vc.utils.ToastUtil; import com.hainaos.vc.utils.VideoUtils; @@ -154,7 +155,7 @@ public class VideoActivity extends BaseMvvmActivity mCompleteData = new MutableLiveData<>(); public void getHomeVideo() { - NetInterfaceManager.getInstance().getHomeVideo(true, getLifecycle(), new NetInterfaceManager.onVideoPathCallback() { - @Override - public void setVideoList(ArrayList videoList) { - mPhotoInfosData.setValue(videoList); - } - @Override - public void onComplete() { - mCompleteData.setValue(true); - } - }); } } diff --git a/app/src/main/java/com/hainaos/vc/activity/vip/VipViewModel.java b/app/src/main/java/com/hainaos/vc/activity/vip/VipViewModel.java index 8180f50..b7eedf5 100644 --- a/app/src/main/java/com/hainaos/vc/activity/vip/VipViewModel.java +++ b/app/src/main/java/com/hainaos/vc/activity/vip/VipViewModel.java @@ -1,24 +1,12 @@ package com.hainaos.vc.activity.vip; -import android.util.Log; - import androidx.lifecycle.MutableLiveData; import com.hainaos.vc.base.mvvm.BaseViewModel; -import com.hainaos.vc.bean.ActivationInfo; -import com.hainaos.vc.bean.BaseResponse; import com.hainaos.vc.bean.SpaceInfo; import com.hainaos.vc.databinding.ActivityVipBinding; -import com.hainaos.vc.network.NetInterfaceManager; -import com.trello.rxlifecycle4.RxLifecycle; import com.trello.rxlifecycle4.android.ActivityEvent; -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; -import io.reactivex.rxjava3.annotations.NonNull; -import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.schedulers.Schedulers; - public class VipViewModel extends BaseViewModel { @Override public ActivityVipBinding getVDBinding() { @@ -33,65 +21,12 @@ public class VipViewModel extends BaseViewModel mSpaceInfoData = new MutableLiveData<>(); public void getHomeSpaceInfo() { - NetInterfaceManager.getInstance().getHomeSpaceInfoControl() - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) - .subscribe(new Observer>() { - @Override - public void onSubscribe(@NonNull Disposable d) { - Log.e("getHomeSpaceInfo", "onSubscribe: "); - } - @Override - public void onNext(@NonNull BaseResponse spaceInfoBaseResponse) { - Log.e("getHomeSpaceInfo", "onNext: " + spaceInfoBaseResponse); - if (spaceInfoBaseResponse.code == 200) { - SpaceInfo spaceInfo = spaceInfoBaseResponse.data; - mSpaceInfoData.setValue(spaceInfo); - } else { - mSpaceInfoData.setValue(null); - } - } - - @Override - public void onError(@NonNull Throwable e) { - Log.e("getHomeSpaceInfo", "onError: " + e.getMessage()); - onComplete(); - } - - @Override - public void onComplete() { - Log.e("getHomeSpaceInfo", "onComplete: "); - } - }); } public void getActivationInfo() { - NetInterfaceManager.getInstance() - .getActivationControl() - .subscribe(new Observer>() { - @Override - public void onSubscribe(@NonNull Disposable d) { - } - - @Override - public void onNext(@NonNull BaseResponse baseResponse) { - Log.e("getActivationInfo", "onNext: " + baseResponse); - } - - @Override - public void onError(@NonNull Throwable e) { - - } - - @Override - public void onComplete() { - - } - }); } } diff --git a/app/src/main/java/com/hainaos/vc/adapter/CategoryAdapter.java b/app/src/main/java/com/hainaos/vc/adapter/CategoryAdapter.java new file mode 100644 index 0000000..28a7131 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/adapter/CategoryAdapter.java @@ -0,0 +1,99 @@ +package com.hainaos.vc.adapter; + +import android.content.Intent; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.hainaos.vc.R; +import com.hainaos.vc.activity.category.online.CategoryVideoActivity; +import com.hainaos.vc.bean.CategoryInfo; +import com.hainaos.vc.fragment.passwd.PasswdDialogFragment; +import com.hainaos.vc.utils.GlideLoadUtils; + +import java.util.List; + +import me.jessyan.autosize.AutoSizeCompat; + +public class CategoryAdapter extends RecyclerView.Adapter { + private FragmentActivity mContext; + private FragmentManager mFragmentManager; + + private List mCategoryInfos; + + public void setCategoryInfos(List categoryInfos) { + mCategoryInfos = categoryInfos; + notifyDataSetChanged(); + } + + @NonNull + @Override + public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + mContext = (FragmentActivity) parent.getContext(); + mFragmentManager = mContext.getSupportFragmentManager(); + AutoSizeCompat.autoConvertDensityOfGlobal(mContext.getResources()); + Holder holder = new Holder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_category, parent, false)); + return holder; + } + + @Override + public void onBindViewHolder(@NonNull Holder holder, int position) { + AutoSizeCompat.autoConvertDensityOfGlobal(mContext.getResources()); + CategoryInfo categoryInfo = mCategoryInfos.get(position); + String name = categoryInfo.getCategory_name(); + if (!TextUtils.isEmpty(name)) { + holder.tv_app_name.setText(name); + } + + String uuid = categoryInfo.getUuid(); + String icon = categoryInfo.getIcon(); + GlideLoadUtils.getInstance().glideLoad(mContext, icon, holder.iv_icon, R.drawable.icon_category); + + holder.root.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (categoryInfo.getIs_free() == 1) { + openCategory(categoryInfo); + } else { + new PasswdDialogFragment(categoryInfo).show(mFragmentManager, "PasswdDialogFragment"); + } + } + }); + } + + private void openCategory(CategoryInfo categoryInfo) { + Intent intent = new Intent(mContext, CategoryVideoActivity.class); + intent.putExtra("CategoryInfo", categoryInfo); + mContext.startActivity(intent); + } + + @Override + public int getItemCount() { + return mCategoryInfos == null ? 0 : mCategoryInfos.size(); + } + + public class Holder extends RecyclerView.ViewHolder { + + ConstraintLayout root; + TextView tv_app_name; + ImageView iv_icon; + + public Holder(@NonNull View itemView) { + super(itemView); + + root = itemView.findViewById(R.id.root); + tv_app_name = itemView.findViewById(R.id.tv_app_name); + iv_icon = itemView.findViewById(R.id.iv_icon); + } + } + +} diff --git a/app/src/main/java/com/hainaos/vc/adapter/CategoryVideoAdapter.java b/app/src/main/java/com/hainaos/vc/adapter/CategoryVideoAdapter.java new file mode 100644 index 0000000..0caff0e --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/adapter/CategoryVideoAdapter.java @@ -0,0 +1,188 @@ +package com.hainaos.vc.adapter; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.media.MediaMetadataRetriever; +import android.os.AsyncTask; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; + +import com.arialyy.annotations.Download; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.task.DownloadTask; +import com.hainaos.vc.R; +import com.hainaos.vc.activity.preview.VideoPreviewActivity; +import com.hainaos.vc.bean.CategoryVideoInfo; +import com.hainaos.vc.utils.FileUtils; +import com.hainaos.vc.utils.GlideLoadUtils; +import com.hainaos.vc.utils.TimeUtils; +import com.shehuan.niv.NiceImageView; + +import java.io.File; +import java.util.List; + +import me.jessyan.autosize.AutoSizeCompat; + +public class CategoryVideoAdapter extends RecyclerView.Adapter { + private static final String TAG = "VideoAdapter"; + private Activity mContext; + private List mLocalVideoInfos; + private String mDirName = ""; + + public void setData(List paths) { + this.mLocalVideoInfos = paths; + notifyDataSetChanged(); + } + + public void setDirName(String dirName) { + if (!TextUtils.isEmpty(dirName)) { + mDirName = dirName; + } + notifyDataSetChanged(); + } + + @NonNull + @Override + public VideoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + mContext = (FragmentActivity) parent.getContext(); + AutoSizeCompat.autoConvertDensityOfGlobal(mContext.getResources()); + Aria.download(this).register(); + VideoHolder holder = new VideoHolder(LayoutInflater.from(mContext).inflate(R.layout.item_category_video, parent, false)); + return holder; + } + + @Override + public void onBindViewHolder(@NonNull final VideoHolder holder, final int position) { + AutoSizeCompat.autoConvertDensityOfGlobal(mContext.getResources()); + + CategoryVideoInfo categoryVideoInfo = mLocalVideoInfos.get(position); + String name = categoryVideoInfo.getName(); + if (!TextUtils.isEmpty(name)) { + holder.title.setText(name); + } + String url = categoryVideoInfo.getFile_url(); + String md5 = categoryVideoInfo.getMd5(); + String fileName = FileUtils.getFileNamefromURL(url); + File file = new File(FileUtils.getHainaVideoPath(mContext) + mDirName + File.separator + fileName); + if (file.exists()) { + holder.iv_status.setVisibility(View.GONE); + } else { + holder.iv_status.setVisibility(View.VISIBLE); + } + String cover = categoryVideoInfo.getCover(); + GlideLoadUtils.getInstance().glideLoad(mContext, cover, holder.video_image); + + holder.duration.setText(TimeUtils.TimeFormat(categoryVideoInfo.getDuration() * 1000)); + + holder.video_image.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (file.exists()) { + Intent intent = new Intent(mContext, VideoPreviewActivity.class); + intent.putExtra("cover", cover); + intent.putExtra("url", file.getAbsolutePath()); + mContext.startActivity(intent); + } else { + FileUtils.ariaDownload(mContext, mDirName, url, md5); + } + } + }); + } + + + public void removeItem(int position) { + if (null != mLocalVideoInfos.get(position)) { + mLocalVideoInfos.remove(position); + } + notifyDataSetChanged(); + } + + @Override + public int getItemCount() { + return mLocalVideoInfos == null ? 0 : mLocalVideoInfos.size(); + } + + + @Override + public int getItemViewType(int position) { + return position; + } + + public void unregister() { + Aria.download(this).unRegister(); + } + + static class VideoHolder extends RecyclerView.ViewHolder { + NiceImageView video_image, iv_status; + TextView title, duration; + ConstraintLayout root; + + public VideoHolder(@NonNull View itemView) { + super(itemView); + video_image = itemView.findViewById(R.id.video_image); + iv_status = itemView.findViewById(R.id.iv_status); + title = itemView.findViewById(R.id.title_text); + duration = itemView.findViewById(R.id.duration); + root = itemView.findViewById(R.id.root); + } + + } + + private BitmapRetultListener listener; + + class BitmapTask extends AsyncTask { + @Override + protected Bitmap doInBackground(String... strings) { + MediaMetadataRetriever mmr = new MediaMetadataRetriever(); + mmr.setDataSource(strings[0]); + Bitmap bitmap = mmr.getFrameAtTime();//获得视频第一帧的Bitmap对象 + return bitmap; + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + listener.onScanCompleted(bitmap); + } + + } + + + interface BitmapRetultListener { + void onScanCompleted(Bitmap bitmap); + } + + //在这里处理任务执行中的状态,如进度进度条的刷新 + @Download.onTaskRunning + void running(DownloadTask task) { + Log.e(TAG, "running: " + "正在下载:" + task.getState() + "-" + task.getPercent() + "--" + task.getExtendField()); + notifyDataSetChanged(); + } + + @Download.onTaskComplete + void taskComplete(DownloadTask task) { + //在这里处理任务完成的状态 + Log.e(TAG, "taskComplete: " + task.getFilePath()); + notifyDataSetChanged(); + } + + @Download.onTaskFail + void taskFail(DownloadTask task, Exception e) { + try { + Log.e(TAG, "taskFail: e " + e.getMessage()); + } catch (Exception ex) { + Log.e(TAG, "taskFail: ex " + e.getMessage()); + } + + notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/com/hainaos/vc/adapter/HomeAppAdapter.java b/app/src/main/java/com/hainaos/vc/adapter/HomeAppAdapter.java new file mode 100644 index 0000000..b983dcb --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/adapter/HomeAppAdapter.java @@ -0,0 +1,156 @@ +package com.hainaos.vc.adapter; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; + +import com.hainaos.vc.R; +import com.hainaos.vc.activity.category.list.CategoryListActivity; +import com.hainaos.vc.activity.category.local.LocalCategoryActivity; +import com.hainaos.vc.activity.user.UserActivity; +import com.hainaos.vc.bean.HomeAppInfo; +import com.hainaos.vc.utils.ApkUtils; + +import java.util.List; + +import me.jessyan.autosize.AutoSizeCompat; + +public class HomeAppAdapter extends RecyclerView.Adapter { + public static final String USER_CENTER = "user_center"; + public static final String DOWNLOAD_CENTER = "download_center"; + + private FragmentActivity mContext; + + private List mHomeAppInfos; + + public void setHomeAppInfos(List homeAppInfos) { + mHomeAppInfos = homeAppInfos; + notifyDataSetChanged(); + } + + + @NonNull + @Override + public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + mContext = (FragmentActivity) parent.getContext(); + AutoSizeCompat.autoConvertDensityOfGlobal(mContext.getResources()); + Holder holder = new Holder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app, parent, false)); + return holder; + } + + @Override + public void onBindViewHolder(@NonNull Holder holder, int position) { + AutoSizeCompat.autoConvertDensityOfGlobal(mContext.getResources()); + HomeAppInfo homeAppInfo = mHomeAppInfos.get(position); + String name = homeAppInfo.getName(); + String dirName = homeAppInfo.getDirName(); + String packageName = homeAppInfo.getPackageName(); + String className = homeAppInfo.getClassName(); + if (!TextUtils.isEmpty(name)) { + holder.tv_app_name.setText(name); + } + + boolean dir = homeAppInfo.isDir(); + if (dir) { + switch (packageName) { + case USER_CENTER: + holder.iv_icon.setImageDrawable(mContext.getDrawable(R.drawable.icon_user_center)); + break; + case DOWNLOAD_CENTER: + holder.iv_icon.setImageDrawable(mContext.getDrawable(R.drawable.icon_download)); + break; + default: + holder.iv_icon.setImageDrawable(mContext.getDrawable(R.drawable.icon_category)); + break; + } + } else { + holder.iv_icon.setImageDrawable(getIconByPackageNameAndClassName(mContext, packageName, className)); + } + + + holder.root.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (dir) { + switch (packageName) { + case USER_CENTER: + mContext.startActivity(new Intent(mContext, UserActivity.class)); + break; + case DOWNLOAD_CENTER: + mContext.startActivity(new Intent(mContext, CategoryListActivity.class)); + break; + default: + Intent intent = new Intent(mContext, LocalCategoryActivity.class); + intent.putExtra("title", name); + intent.putExtra("dir", dirName); + mContext.startActivity(intent); + break; + } + } else { + if (TextUtils.isEmpty(className)) { + ApkUtils.openPackage(mContext, packageName); + } else { + ApkUtils.openPackage(mContext, packageName, className); + } + } + } + }); + } + + public Drawable getIconByPackageNameAndClassName(Context context, String packageName, String className) { + PackageManager pm = context.getPackageManager(); + ComponentName cn = new ComponentName(packageName, className); + try { + ActivityInfo activityInfo = pm.getActivityInfo(cn, 0); + return activityInfo.loadIcon(pm); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + // 可以返回一个默认图标或者null + ApplicationInfo applicationInfo = null; + try { + applicationInfo = pm.getApplicationInfo(packageName, 0); + } catch (PackageManager.NameNotFoundException ex) { + ex.printStackTrace(); + } + if (applicationInfo != null) { + return applicationInfo.loadLogo(pm); + } + return context.getDrawable(R.mipmap.ic_launcher); + } + } + + + @Override + public int getItemCount() { + return mHomeAppInfos == null ? 0 : mHomeAppInfos.size(); + } + + public class Holder extends RecyclerView.ViewHolder { + ConstraintLayout root; + TextView tv_app_name; + ImageView iv_icon; + + public Holder(@NonNull View itemView) { + super(itemView); + + root = itemView.findViewById(R.id.root); + tv_app_name = itemView.findViewById(R.id.tv_app_name); + iv_icon = itemView.findViewById(R.id.iv_icon); + } + } +} diff --git a/app/src/main/java/com/hainaos/vc/adapter/HomeCategoryAdapter.java b/app/src/main/java/com/hainaos/vc/adapter/HomeCategoryAdapter.java new file mode 100644 index 0000000..297c151 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/adapter/HomeCategoryAdapter.java @@ -0,0 +1,134 @@ +package com.hainaos.vc.adapter; + +import android.content.Intent; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.hainaos.vc.R; +import com.hainaos.vc.activity.category.list.CategoryListActivity; +import com.hainaos.vc.activity.category.local.LocalCategoryActivity; +import com.hainaos.vc.activity.user.UserActivity; +import com.hainaos.vc.bean.CategoryInfo; +import com.hainaos.vc.fragment.passwd.PasswdDialogFragment; +import com.hainaos.vc.utils.GlideLoadUtils; + +import java.util.List; + +import me.jessyan.autosize.AutoSizeCompat; + +public class HomeCategoryAdapter extends RecyclerView.Adapter { + public static final String USER_CENTER = "user_center"; + public static final String DOWNLOAD_CENTER = "download_center"; + + private FragmentActivity mContext; + private FragmentManager mFragmentManager; + private PasswdDialogFragment mPasswdDialogFragment; + private List mCategoryInfos; + + public void setCategoryInfos(List categoryInfos) { + mCategoryInfos = categoryInfos; + notifyDataSetChanged(); + } + + @NonNull + @Override + public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + mContext = (FragmentActivity) parent.getContext(); + mFragmentManager = mContext.getSupportFragmentManager(); + AutoSizeCompat.autoConvertDensityOfGlobal(mContext.getResources()); + Holder holder = new Holder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_category, parent, false)); + return holder; + } + + @Override + public void onBindViewHolder(@NonNull Holder holder, int position) { + AutoSizeCompat.autoConvertDensityOfGlobal(mContext.getResources()); + CategoryInfo categoryInfo = mCategoryInfos.get(position); + String name = categoryInfo.getCategory_name(); + if (!TextUtils.isEmpty(name)) { + holder.tv_app_name.setText(name); + } + + String uuid = categoryInfo.getUuid(); + String icon = categoryInfo.getIcon(); + + switch (uuid) { + case USER_CENTER: + holder.iv_icon.setImageDrawable(mContext.getDrawable(R.drawable.icon_user_center)); + break; + case DOWNLOAD_CENTER: + holder.iv_icon.setImageDrawable(mContext.getDrawable(R.drawable.icon_download)); + break; + default: + GlideLoadUtils.getInstance().glideLoad(mContext, icon, holder.iv_icon, R.drawable.icon_category); + break; + } + + + holder.root.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + switch (uuid) { + case USER_CENTER: + mContext.startActivity(new Intent(mContext, UserActivity.class)); + break; + case DOWNLOAD_CENTER: + mContext.startActivity(new Intent(mContext, CategoryListActivity.class)); + break; + default: + if (categoryInfo.getIs_free() == 1) { + openCategory(categoryInfo); + } else { + mPasswdDialogFragment = new PasswdDialogFragment(categoryInfo); + mPasswdDialogFragment.setConfimCallback(new PasswdDialogFragment.ConfimCallback() { + @Override + public void onConfig(String passwd) { + openCategory(categoryInfo); + } + }); + mPasswdDialogFragment.show(mFragmentManager, "PasswdDialogFragment"); + } + break; + } + } + }); + } + + private void openCategory(CategoryInfo categoryInfo) { + Intent intent = new Intent(mContext, LocalCategoryActivity.class); + intent.putExtra("title", categoryInfo.getCategory_name()); + intent.putExtra("dir", categoryInfo.getFolder()); + mContext.startActivity(intent); + } + + @Override + public int getItemCount() { + return mCategoryInfos == null ? 0 : mCategoryInfos.size(); + } + + public class Holder extends RecyclerView.ViewHolder { + + ConstraintLayout root; + TextView tv_app_name; + ImageView iv_icon; + + public Holder(@NonNull View itemView) { + super(itemView); + + root = itemView.findViewById(R.id.root); + tv_app_name = itemView.findViewById(R.id.tv_app_name); + iv_icon = itemView.findViewById(R.id.iv_icon); + } + } + +} diff --git a/app/src/main/java/com/hainaos/vc/adapter/PicAdapter.java b/app/src/main/java/com/hainaos/vc/adapter/PicAdapter.java index 8b7adf1..25c9737 100644 --- a/app/src/main/java/com/hainaos/vc/adapter/PicAdapter.java +++ b/app/src/main/java/com/hainaos/vc/adapter/PicAdapter.java @@ -26,9 +26,9 @@ import com.bumptech.glide.request.transition.Transition; import com.hainaos.vc.R; import com.hainaos.vc.activity.preview.PreviewActivity; import com.hainaos.vc.bean.PhotoInfo; +import com.hainaos.vc.utils.FileUtils; import com.hainaos.vc.utils.JgyUtils; import com.hainaos.vc.utils.ScreenUtils; -import com.hainaos.vc.utils.VideoUtils; import com.shehuan.niv.NiceImageView; import java.util.ArrayList; @@ -64,7 +64,7 @@ public class PicAdapter extends RecyclerView.Adapter { String fileName = photoInfo.getFile_name(); String fileUrl = photoInfo.getFile(); if (TextUtils.isEmpty(fileName)) { - holder.tv_name.setText(VideoUtils.getFileNameWithoutExtension(fileUrl)); + holder.tv_name.setText(FileUtils.getFileNameWithoutExtension(fileUrl)); } else { holder.tv_name.setText(fileName); } diff --git a/app/src/main/java/com/hainaos/vc/adapter/TikTokRecyclerViewAdapter.java b/app/src/main/java/com/hainaos/vc/adapter/TikTokRecyclerViewAdapter.java index 974aedb..9c47aba 100644 --- a/app/src/main/java/com/hainaos/vc/adapter/TikTokRecyclerViewAdapter.java +++ b/app/src/main/java/com/hainaos/vc/adapter/TikTokRecyclerViewAdapter.java @@ -18,13 +18,13 @@ import com.arialyy.aria.core.task.DownloadTask; import com.bumptech.glide.Glide; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import com.hainaos.vc.CustomJzvd.JzvdStdAssert; import com.hainaos.vc.R; import com.hainaos.vc.bean.LocalVideoInfo; +import com.hainaos.vc.customjzvd.JzvdStdAssert; import com.hainaos.vc.gson.GsonUtils; +import com.hainaos.vc.utils.FileUtils; import com.hainaos.vc.utils.JgyUtils; import com.hainaos.vc.utils.SPUtils; -import com.hainaos.vc.utils.VideoUtils; import com.shehuan.niv.NiceImageView; import java.lang.reflect.Type; @@ -104,7 +104,7 @@ public class TikTokRecyclerViewAdapter extends RecyclerView.Adapter public void onBindViewHolder(@NonNull final VideoHolder holder, final int position) { LocalVideoInfo localVideoInfo = mLocalVideoInfos.get(position); final String localPath = localVideoInfo.getLocalPath(); - String url = localVideoInfo.getFile(); Log.e(TAG, "onBindViewHolder: " + localPath); - if (TextUtils.isEmpty(localPath)) { - holder.iv_status.setVisibility(View.VISIBLE); - if (!TextUtils.isEmpty(url)) { - Glide.with(mContext).load(url + "?x-oss-process=video/snapshot,t_0,f_jpg").error(R.mipmap.ic_launcher).into(holder.video_image); - String fileName = localVideoInfo.getFile_name(); - if (TextUtils.isEmpty(fileName)) { - holder.title.setText(VideoUtils.getFileNameWithoutExtension(url)); - } else { - holder.title.setText(fileName); - } - holder.duration.setText(TimeUtils.TimeFormat(localVideoInfo.getDuration() * 1000)); - } - } else { - holder.title.setText(VideoUtils.getFileNameWithoutExtension(localPath)); - File file = new File(localPath); - if (file.exists()) { - holder.iv_status.setVisibility(View.GONE); - Glide.with(mContext).load(file).error(R.mipmap.ic_launcher).into(holder.video_image); - holder.duration.setText(TimeUtils.TimeFormat(localVideoInfo.getDuration() * 1000)); -// Observable.create(new ObservableOnSubscribe() { -// @Override -// public void subscribe(ObservableEmitter emitter) throws Exception { -// FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever(); -// mmr.setDataSource(localPath); -// String duration = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION); -// Bitmap bitmap = mmr.getFrameAtTime();//获得视频第一帧的Bitmap对象. -// Long time = Long.valueOf(duration); -// -// mmr.release(); -// VideoResult result = new VideoResult(); -// result.frame = bitmap; -// result.time = time; -// emitter.onNext(result); -// } -// }).subscribeOn(Schedulers.newThread()) -// .observeOn(AndroidSchedulers.mainThread()) -// .subscribe(new Observer() { -// @Override -// public void onSubscribe(Disposable d) { -// Log.e("VideoResult", "onSubscribe: "); -// } -// -// @Override -// public void onNext(VideoResult result) { -// Log.e("VideoResult", "onNext: " + result); -// try { -// Glide.with(holder.video_image).load(result.frame).skipMemoryCache(false).into(new SimpleTarget() { -// @Override -// public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { -// holder.video_image.setImageDrawable(resource); -// } -// }); -// holder.duration.setText(Utils.TimeFormat(result.time)); -// } catch (Exception e) { -// -// } -// } -// -// @Override -// public void onError(Throwable e) { -// Log.e("VideoResult", "onError: " + e.getMessage()); -// } -// -// @Override -// public void onComplete() { -// Log.e("VideoResult", "onComplete: "); -// } -// }); - } else { - holder.iv_status.setVisibility(View.VISIBLE); + holder.title.setText(FileUtils.getFileName(localPath)); + + File file = new File(localPath); + if (file.exists()) { + holder.iv_status.setVisibility(View.GONE); + Glide.with(mContext).load(file).error(R.mipmap.ic_launcher).into(holder.video_image); + holder.duration.setText(TimeUtils.TimeFormat(localVideoInfo.getDuration() * 1000)); + } else { + holder.iv_status.setVisibility(View.VISIBLE); - } } holder.iv_status.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (TextUtils.isEmpty(localPath)) { - if (JgyUtils.getInstance().fileExists(url)) { - Intent intent = new Intent(mContext, TikTokActivity.class); - intent.putExtra("position", position); - intent.putExtra("list", mLocalVideoInfos); - mContext.startActivity(intent); - } else { - JgyUtils.getInstance().ariaDownload(url, GsonUtils.getJsonObject(GsonUtils.toJSONString(localVideoInfo))); - ToastUtil.show(String.format(mContext.getString(R.string.download_now), VideoUtils.getFileNameWithoutExtension(url))); - } - } else { - Intent intent = new Intent(mContext, TikTokActivity.class); - intent.putExtra("position", position); - intent.putParcelableArrayListExtra("list", mLocalVideoInfos); - mContext.startActivity(intent); - } + playVideo(position); } }); Log.e("title:", holder.title.getText().toString()); -// } holder.root.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - if (TextUtils.isEmpty(localPath)) { - if (JgyUtils.getInstance().fileExists(url)) { - Intent intent = new Intent(mContext, TikTokActivity.class); - intent.putExtra("position", position); - intent.putParcelableArrayListExtra("list", mLocalVideoInfos); - mContext.startActivity(intent); - } else { - JgyUtils.getInstance().ariaDownload(url, GsonUtils.getJsonObject(GsonUtils.toJSONString(localVideoInfo))); - ToastUtil.show(String.format(mContext.getString(R.string.download_now), VideoUtils.getFileNameWithoutExtension(url))); - } - } else { - Intent intent = new Intent(mContext, TikTokActivity.class); - intent.putExtra("position", position); - intent.putParcelableArrayListExtra("list", mLocalVideoInfos); - mContext.startActivity(intent); - } + playVideo(position); } }); holder.root.setOnLongClickListener(view -> { @@ -209,6 +111,13 @@ public class VideoAdapter extends RecyclerView.Adapter }); } + public void playVideo(int position) { + Intent intent = new Intent(mContext, TikTokActivity.class); + intent.putExtra("position", position); + intent.putParcelableArrayListExtra("list", mLocalVideoInfos); + mContext.startActivity(intent); + } + public interface onItemLongClickListener { void onItemLongClick(String path, int position); } diff --git a/app/src/main/java/com/hainaos/vc/base/BaseApplication.java b/app/src/main/java/com/hainaos/vc/base/BaseApplication.java index 229c862..a885c0b 100644 --- a/app/src/main/java/com/hainaos/vc/base/BaseApplication.java +++ b/app/src/main/java/com/hainaos/vc/base/BaseApplication.java @@ -7,7 +7,9 @@ import com.arialyy.aria.core.Aria; import com.hainaos.vc.manager.ConnectManager; import com.hainaos.vc.network.NetInterfaceManager; import com.hainaos.vc.utils.JgyUtils; +import com.hainaos.vc.utils.LoginUtils; import com.hainaos.vc.utils.ToastUtil; +import com.hjq.toast.Toaster; import com.tencent.mmkv.MMKV; public class BaseApplication extends Application { @@ -23,7 +25,8 @@ public class BaseApplication extends Application { Aria.init(this); ConnectManager.init(this); ToastUtil.init(this); + LoginUtils.init(this); NetInterfaceManager.init(this); - + Toaster.init(this); } } diff --git a/app/src/main/java/com/hainaos/vc/base/BaseDialogFragment.java b/app/src/main/java/com/hainaos/vc/base/BaseDialogFragment.java new file mode 100644 index 0000000..a5567b1 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/base/BaseDialogFragment.java @@ -0,0 +1,44 @@ +package com.hainaos.vc.base; + +import android.os.Bundle; + +import com.hainaos.vc.base.rx.BaseRxDialogFragment; + +public abstract class BaseDialogFragment extends BaseRxDialogFragment { + + protected boolean isViewInitiated; + protected boolean isVisibleToUser; + protected boolean isDataInitiated; + + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + isViewInitiated = true; + prepareFetchData(); + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + this.isVisibleToUser = isVisibleToUser; + prepareFetchData(); + } + + public abstract void fetchData(); + + public boolean prepareFetchData() { + return prepareFetchData(false); + } + + public boolean prepareFetchData(boolean forceUpdate) { + if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) { + fetchData(); + //注释掉保证每次都更新数据 +// isDataInitiated = true; + return true; + } + return false; + } + +} diff --git a/app/src/main/java/com/hainaos/vc/base/mvvm/BaseMvvmActivity.java b/app/src/main/java/com/hainaos/vc/base/mvvm/BaseMvvmActivity.java index 75e7601..bc6c3cc 100644 --- a/app/src/main/java/com/hainaos/vc/base/mvvm/BaseMvvmActivity.java +++ b/app/src/main/java/com/hainaos/vc/base/mvvm/BaseMvvmActivity.java @@ -31,7 +31,7 @@ public abstract class BaseMvvmActivity) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; boolean isAbstract = Modifier.isAbstract(vmClass.getModifiers()); - Log.e(TAG, "isLocalClass:" + vmClass.getSimpleName().equals(ViewModel.class.getSimpleName()) + " isAbstract:" + isAbstract); + Log.d(TAG, "isLocalClass:" + vmClass.getSimpleName().equals(ViewModel.class.getSimpleName()) + " isAbstract:" + isAbstract); if (!isAbstract) {//不是一个抽象类 mViewModel = new ViewModelProvider(this).get(vmClass); } diff --git a/app/src/main/java/com/hainaos/vc/base/mvvm/fragment/BaseMvvmDialogFragment.java b/app/src/main/java/com/hainaos/vc/base/mvvm/fragment/BaseMvvmDialogFragment.java new file mode 100644 index 0000000..116844f --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/base/mvvm/fragment/BaseMvvmDialogFragment.java @@ -0,0 +1,184 @@ +package com.hainaos.vc.base.mvvm.fragment; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; + +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ViewDataBinding; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; + +import com.hainaos.vc.base.BaseDialogFragment; + +import java.lang.ref.WeakReference; +import java.lang.reflect.ParameterizedType; + +/** + * @author: lml + * @date: 2021/12/15 + */ +public abstract class BaseMvvmDialogFragment extends BaseDialogFragment { + protected String mTag = this.getClass().getSimpleName(); + /** + * 是否顯示了 + */ + protected boolean mIsVisible; + /** + * 是否準備好了-Created + */ + protected boolean mHasPrepare; + + + protected VM mViewModel; + protected VDB mViewDataBinding; + protected Class vmClass; + // +// protected Toolbar toolbar; +// protected View statusBarView; + // + protected Bundle bundle;//来自getArguments() + protected Bundle savedInstanceState; + +// protected Context context; + + /** + * 上下文 + */ + private WeakReference ctx; + + public Context getCtx() { + return ctx == null ? null : ctx.get(); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); +// this.context = context; + ctx = new WeakReference<>(context); + } + + /** + * onCreate、onResume里不能调用 + * + * @return + */ + public boolean isAttached() { + boolean flag = getCtx() != null && isAdded(); + Log.e(" >> isAttached >>", "flag = " + flag); + return flag; + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + //ViewDataBinding + mViewDataBinding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false); + mViewDataBinding.setLifecycleOwner(this); + + //ViewModel + vmClass = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + mViewModel = new ViewModelProvider(this).get(vmClass); + + return mViewDataBinding.getRoot(); + } + + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + initDataBinding(); + initView(bundle = getArguments()); + + initData(this.savedInstanceState = savedInstanceState); + + if (mIsVisible) { + onEnter(); + } + mHasPrepare = true; + + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mHasPrepare = false; + mViewDataBinding = null; + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (mIsVisible == getUserVisibleHint()) + return; + mIsVisible = getUserVisibleHint(); + if (mIsVisible) { + if (!mHasPrepare) + return; + onEnter(); + } else { + onExit(); + } + } + + @LayoutRes + protected abstract int getLayoutId(); + + protected abstract void initDataBinding(); + + protected abstract void initView(Bundle bundle); + + protected abstract void initData(Bundle savedInstanceState); + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + } + + protected void hideInputMethod(Activity activity) { + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); + View view = activity.getCurrentFocus(); + if (view != null) { + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + } + + protected void hideInputMethod(Activity activity, EditText editText) { + InputMethodManager imm = (InputMethodManager) editText.getContext().getSystemService(Activity.INPUT_METHOD_SERVICE); + View view = activity.getCurrentFocus(); + if (view != null) { + imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } + } + + protected void showInputMethod(EditText editText) { + InputMethodManager imm = (InputMethodManager) editText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED); + } + + /** + * 進入界面 + */ + protected void onEnter() { + + } + + /** + * 離開界面 + */ + protected void onExit() { + + } + +} diff --git a/app/src/main/java/com/hainaos/vc/base/rx/BaseRxDialogFragment.java b/app/src/main/java/com/hainaos/vc/base/rx/BaseRxDialogFragment.java new file mode 100644 index 0000000..c6b14d6 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/base/rx/BaseRxDialogFragment.java @@ -0,0 +1,123 @@ +package com.hainaos.vc.base.rx; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.CallSuper; +import androidx.annotation.CheckResult; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.FragmentEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * {@link com.trello.rxlifecycle4.components.RxFragment} + * copied form RxFragment} + */ +public class BaseRxDialogFragment extends DialogFragment implements LifecycleProvider { + private final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BehaviorSubject getLifecycleSubject() { + return lifecycleSubject; + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull FragmentEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindFragment(lifecycleSubject); + } + + @Override + @CallSuper + public void onAttach(android.app.Activity activity) { + super.onAttach(activity); + lifecycleSubject.onNext(FragmentEvent.ATTACH); + } + + @Override + @CallSuper + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE); + } + + @Override + @CallSuper + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + lifecycleSubject.onNext(FragmentEvent.CREATE_VIEW); + } + + @Override + @CallSuper + public void onStart() { + super.onStart(); + lifecycleSubject.onNext(FragmentEvent.START); + } + + @Override + @CallSuper + public void onResume() { + super.onResume(); + lifecycleSubject.onNext(FragmentEvent.RESUME); + } + + @Override + @CallSuper + public void onPause() { + lifecycleSubject.onNext(FragmentEvent.PAUSE); + super.onPause(); + } + + @Override + @CallSuper + public void onStop() { + lifecycleSubject.onNext(FragmentEvent.STOP); + super.onStop(); + } + + @Override + @CallSuper + public void onDestroyView() { + lifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW); + super.onDestroyView(); + } + + @Override + @CallSuper + public void onDestroy() { + lifecycleSubject.onNext(FragmentEvent.DESTROY); + super.onDestroy(); + } + + @Override + @CallSuper + public void onDetach() { + lifecycleSubject.onNext(FragmentEvent.DETACH); + super.onDetach(); + } +} + diff --git a/app/src/main/java/com/hainaos/vc/bean/CategoryInfo.java b/app/src/main/java/com/hainaos/vc/bean/CategoryInfo.java new file mode 100644 index 0000000..4630623 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/CategoryInfo.java @@ -0,0 +1,67 @@ +package com.hainaos.vc.bean; + +import java.io.Serializable; + +public class CategoryInfo implements Serializable { + private static final long serialVersionUID = -8183863617328255951L; + + String category_name; + String uuid; + int is_free; + int sort; + String folder; + String icon; + + public CategoryInfo(String category_name, String uuid) { + this.category_name = category_name; + this.uuid = uuid; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public int getIs_free() { + return is_free; + } + + public void setIs_free(int is_free) { + this.is_free = is_free; + } + + public String getCategory_name() { + return category_name; + } + + public void setCategory_name(String category_name) { + this.category_name = category_name; + } + + public int getSort() { + return sort; + } + + public void setSort(int sort) { + this.sort = sort; + } + + public String getFolder() { + return folder; + } + + public void setFolder(String folder) { + this.folder = folder; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } +} diff --git a/app/src/main/java/com/hainaos/vc/bean/CategoryVideoInfo.java b/app/src/main/java/com/hainaos/vc/bean/CategoryVideoInfo.java new file mode 100644 index 0000000..9e463fd --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/CategoryVideoInfo.java @@ -0,0 +1,125 @@ +package com.hainaos.vc.bean; + +import java.io.Serializable; + +public class CategoryVideoInfo implements Serializable { + private static final long serialVersionUID = 1070514810251550984L; + + String uuid; + int category_id; + String file_url; + String category_uuid; + String name; + String cover; + long duration; + long file_size; + String md5; + int status; + int download; + String created_at; + String updated_at; + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public int getCategory_id() { + return category_id; + } + + public void setCategory_id(int category_id) { + this.category_id = category_id; + } + + public String getFile_url() { + return file_url; + } + + public void setFile_url(String file_url) { + this.file_url = file_url; + } + + public String getCategory_uuid() { + return category_uuid; + } + + public void setCategory_uuid(String category_uuid) { + this.category_uuid = category_uuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCover() { + return cover; + } + + public void setCover(String cover) { + this.cover = cover; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public long getFile_size() { + return file_size; + } + + public void setFile_size(long file_size) { + this.file_size = file_size; + } + + public String getMd5() { + return md5; + } + + public void setMd5(String md5) { + this.md5 = md5; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getDownload() { + return download; + } + + public void setDownload(int download) { + this.download = download; + } + + public String getCreated_at() { + return created_at; + } + + public void setCreated_at(String created_at) { + this.created_at = created_at; + } + + public String getUpdated_at() { + return updated_at; + } + + public void setUpdated_at(String updated_at) { + this.updated_at = updated_at; + } +} diff --git a/app/src/main/java/com/hainaos/vc/bean/CodeInfo.java b/app/src/main/java/com/hainaos/vc/bean/CodeInfo.java new file mode 100644 index 0000000..3971432 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/CodeInfo.java @@ -0,0 +1,26 @@ +package com.hainaos.vc.bean; + +import java.io.Serializable; + +public class CodeInfo implements Serializable { + private static final long serialVersionUID = -1338653649997451619L; + + int ttl; + String verify_key; + + public int getTtl() { + return ttl; + } + + public void setTtl(int ttl) { + this.ttl = ttl; + } + + public String getVerify_key() { + return verify_key; + } + + public void setVerify_key(String verify_key) { + this.verify_key = verify_key; + } +} diff --git a/app/src/main/java/com/hainaos/vc/bean/HomeAppInfo.java b/app/src/main/java/com/hainaos/vc/bean/HomeAppInfo.java new file mode 100644 index 0000000..3559e94 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/HomeAppInfo.java @@ -0,0 +1,60 @@ +package com.hainaos.vc.bean; + +import java.io.Serializable; + +public class HomeAppInfo implements Serializable { + + String name; + String packageName; + String className; + String dirName; + boolean isDir; + + public HomeAppInfo(String name, String packageName, String className, String dirName, boolean isDir) { + this.name = name; + this.packageName = packageName; + this.className = className; + this.dirName = dirName; + this.isDir = isDir; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public String getDirName() { + return dirName; + } + + public void setDirName(String dirName) { + this.dirName = dirName; + } + + public boolean isDir() { + return isDir; + } + + public void setDir(boolean dir) { + isDir = dir; + } +} diff --git a/app/src/main/java/com/hainaos/vc/bean/LoginInfo.java b/app/src/main/java/com/hainaos/vc/bean/LoginInfo.java new file mode 100644 index 0000000..3e8ec66 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/LoginInfo.java @@ -0,0 +1,26 @@ +package com.hainaos.vc.bean; + +import java.io.Serializable; + +public class LoginInfo implements Serializable { + private static final long serialVersionUID = -3479591828073888872L; + + LoginUserInfo user_info; + String token; + + public LoginUserInfo getUser_info() { + return user_info; + } + + public void setUser_info(LoginUserInfo user_info) { + this.user_info = user_info; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } +} diff --git a/app/src/main/java/com/hainaos/vc/bean/LoginUserInfo.java b/app/src/main/java/com/hainaos/vc/bean/LoginUserInfo.java new file mode 100644 index 0000000..5124a43 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/LoginUserInfo.java @@ -0,0 +1,53 @@ +package com.hainaos.vc.bean; + +import java.io.Serializable; + +public class LoginUserInfo implements Serializable { + private static final long serialVersionUID = -2982716451740455816L; + + int id; + String mobile; + String nickname; + String vip_level; + String expire_at; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public String getVip_level() { + return vip_level; + } + + public void setVip_level(String vip_level) { + this.vip_level = vip_level; + } + + public String getExpire_at() { + return expire_at; + } + + public void setExpire_at(String expire_at) { + this.expire_at = expire_at; + } +} diff --git a/app/src/main/java/com/hainaos/vc/bean/UserInfo.java b/app/src/main/java/com/hainaos/vc/bean/UserInfo.java new file mode 100644 index 0000000..cf0272b --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/UserInfo.java @@ -0,0 +1,98 @@ +package com.hainaos.vc.bean; + +import java.io.Serializable; + +public class UserInfo implements Serializable { + private static final long serialVersionUID = -2982716451740455816L; + + int id; + String mobile; + String nickname; + String avatar; + int status; + int vip_level_id; + String expire_at; + String last_login_at; + String created_at; + VipLevel vip_level; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public int getVip_level_id() { + return vip_level_id; + } + + public void setVip_level_id(int vip_level_id) { + this.vip_level_id = vip_level_id; + } + + public String getExpire_at() { + return expire_at; + } + + public void setExpire_at(String expire_at) { + this.expire_at = expire_at; + } + + public String getLast_login_at() { + return last_login_at; + } + + public void setLast_login_at(String last_login_at) { + this.last_login_at = last_login_at; + } + + public String getCreated_at() { + return created_at; + } + + public void setCreated_at(String created_at) { + this.created_at = created_at; + } + + public VipLevel getVip_level() { + return vip_level; + } + + public void setVip_level(VipLevel vip_level) { + this.vip_level = vip_level; + } +} diff --git a/app/src/main/java/com/hainaos/vc/bean/VideoInfo.java b/app/src/main/java/com/hainaos/vc/bean/VideoInfo.java index e6be0b9..19fd48a 100644 --- a/app/src/main/java/com/hainaos/vc/bean/VideoInfo.java +++ b/app/src/main/java/com/hainaos/vc/bean/VideoInfo.java @@ -10,42 +10,54 @@ import java.io.Serializable; public class VideoInfo implements Serializable { private static final long serialVersionUID = 7211429309866156084L; - String file; - String file_name; - String file_md5; - long file_size; + String uuid; + String file_url; + String category_uuid; + String name; + String cover; long duration; + long file_size; + long download; + String updated_at; - public String getFile() { - return file; + public String getUuid() { + return uuid; } - public void setFile(String file) { - this.file = file; + public void setUuid(String uuid) { + this.uuid = uuid; } - public String getFile_name() { - return file_name; + public String getFile_url() { + return file_url; } - public void setFile_name(String file_name) { - this.file_name = file_name; + public void setFile_url(String file_url) { + this.file_url = file_url; } - public String getFile_md5() { - return file_md5; + public String getCategory_uuid() { + return category_uuid; } - public void setFile_md5(String file_md5) { - this.file_md5 = file_md5; + public void setCategory_uuid(String category_uuid) { + this.category_uuid = category_uuid; } - public long getFile_size() { - return file_size; + public String getName() { + return name; } - public void setFile_size(long file_size) { - this.file_size = file_size; + public void setName(String name) { + this.name = name; + } + + public String getCover() { + return cover; + } + + public void setCover(String cover) { + this.cover = cover; } public long getDuration() { @@ -56,6 +68,30 @@ public class VideoInfo implements Serializable { this.duration = duration; } + public long getFile_size() { + return file_size; + } + + public void setFile_size(long file_size) { + this.file_size = file_size; + } + + public long getDownload() { + return download; + } + + public void setDownload(long download) { + this.download = download; + } + + public String getUpdated_at() { + return updated_at; + } + + public void setUpdated_at(String updated_at) { + this.updated_at = updated_at; + } + @NonNull @Override public String toString() { diff --git a/app/src/main/java/com/hainaos/vc/bean/VideoListData.java b/app/src/main/java/com/hainaos/vc/bean/VideoListData.java new file mode 100644 index 0000000..9c66b04 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/VideoListData.java @@ -0,0 +1,20 @@ +package com.hainaos.vc.bean; + +import java.io.Serializable; +import java.util.List; + +public class VideoListData implements Serializable { + private static final long serialVersionUID = 1883761524815418137L; + + List data; + int current_page; + long timestamps; + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } +} diff --git a/app/src/main/java/com/hainaos/vc/bean/VipLevel.java b/app/src/main/java/com/hainaos/vc/bean/VipLevel.java new file mode 100644 index 0000000..c3e8e85 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/VipLevel.java @@ -0,0 +1,26 @@ +package com.hainaos.vc.bean; + +import java.io.Serializable; + +public class VipLevel implements Serializable { + private static final long serialVersionUID = -6123347697778104684L; + + int id; + String name; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/app/src/main/java/com/hainaos/vc/bean/uiuios/AppBase.java b/app/src/main/java/com/hainaos/vc/bean/uiuios/AppBase.java new file mode 100644 index 0000000..8263be2 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/uiuios/AppBase.java @@ -0,0 +1,58 @@ +package com.hainaos.vc.bean.uiuios; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; + +public class AppBase implements Serializable { + private static final long serialVersionUID = -1084612101570534997L; + + int id; + String app_name; + String app_package; + // @SerializedName(value = "icon", alternate = "app_icon") + String icon; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getApp_name() { + return app_name; + } + + public void setApp_name(String app_name) { + this.app_name = app_name; + } + + public String getApp_package() { + return app_package; + } + + public void setApp_package(String app_package) { + this.app_package = app_package; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } + +} diff --git a/app/src/main/java/com/hainaos/vc/bean/uiuios/AppUpdateInfo.java b/app/src/main/java/com/hainaos/vc/bean/uiuios/AppUpdateInfo.java new file mode 100644 index 0000000..f91f25a --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/uiuios/AppUpdateInfo.java @@ -0,0 +1,109 @@ +package com.hainaos.vc.bean.uiuios; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; + +public class AppUpdateInfo implements Serializable { + private static final long serialVersionUID = -683006285701880863L; + + int id; + int app_id; + String app_version_name; + long app_version_code; + long app_size; + String app_desc; + String app_md5; + String app_url; + String is_forcedown; + AppBase app; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getApp_id() { + return app_id; + } + + public void setApp_id(int app_id) { + this.app_id = app_id; + } + + public String getApp_version_name() { + return app_version_name; + } + + public void setApp_version_name(String app_version_name) { + this.app_version_name = app_version_name; + } + + public long getApp_version_code() { + return app_version_code; + } + + public void setApp_version_code(long app_version_code) { + this.app_version_code = app_version_code; + } + + public long getApp_size() { + return app_size; + } + + public void setApp_size(long app_size) { + this.app_size = app_size; + } + + public String getApp_desc() { + return app_desc; + } + + public void setApp_desc(String app_desc) { + this.app_desc = app_desc; + } + + public String getApp_md5() { + return app_md5; + } + + public void setApp_md5(String app_md5) { + this.app_md5 = app_md5; + } + + public String getApp_url() { + return app_url; + } + + public void setApp_url(String app_url) { + this.app_url = app_url; + } + + public String getIs_forcedown() { + return is_forcedown; + } + + public void setIs_forcedown(String is_forcedown) { + this.is_forcedown = is_forcedown; + } + + public AppBase getApp() { + return app; + } + + public void setApp(AppBase app) { + this.app = app; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } +} diff --git a/app/src/main/java/com/hainaos/vc/bean/uiuios/AriaDownloadInfo.java b/app/src/main/java/com/hainaos/vc/bean/uiuios/AriaDownloadInfo.java new file mode 100644 index 0000000..be7c061 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/bean/uiuios/AriaDownloadInfo.java @@ -0,0 +1,165 @@ +package com.hainaos.vc.bean.uiuios; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; + +public class AriaDownloadInfo implements Serializable { + private static final long serialVersionUID = -2835281454196323431L; + + @SerializedName(value = "appId", alternate = {"app_id"}) + int appId; + @SerializedName(value = "appName", alternate = {"app_name"}) + String appName; + @SerializedName(value = "appPackage", alternate = {"app_package", "package"}) + String appPackage; + @SerializedName(value = "appVersionName", alternate = {"app_version_name"}) + String appVersionName; + @SerializedName(value = "appVersionCode", alternate = {"app_version_code"}) + long appVersionCode; + @SerializedName(value = "appUrl", alternate = {"app_url", "url"}) + String appUrl; + @SerializedName(value = "appIcon", alternate = {"app_img"}) + String appIcon; + @SerializedName(value = "appSize", alternate = {"app_size"}) + long appSize; + @SerializedName(value = "appMd5", alternate = {"app_md5"}) + String appMd5; + + public AriaDownloadInfo(int appId, String appName, String appPackage, String appVersionName, long appVersionCode, String appUrl, String appIcon, long appSize, String appMd5) { + this.appId = appId; + this.appName = appName; + this.appPackage = appPackage; + this.appVersionName = appVersionName; + this.appVersionCode = appVersionCode; + this.appUrl = appUrl; + this.appIcon = appIcon; + this.appSize = appSize; + this.appMd5 = appMd5; + } + + public int getAppId() { + return appId; + } + + public void setAppId(int appId) { + this.appId = appId; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getAppPackage() { + return appPackage; + } + + public void setAppPackage(String appPackage) { + this.appPackage = appPackage; + } + + public String getAppVersionName() { + return appVersionName; + } + + public void setAppVersionName(String appVersionName) { + this.appVersionName = appVersionName; + } + + public long getAppVersionCode() { + return appVersionCode; + } + + public void setAppVersionCode(long appVersionCode) { + this.appVersionCode = appVersionCode; + } + + public String getAppUrl() { + return appUrl; + } + + public void setAppUrl(String appUrl) { + this.appUrl = appUrl; + } + + public String getAppIcon() { + return appIcon; + } + + public void setAppIcon(String appIcon) { + this.appIcon = appIcon; + } + + public long getAppSize() { + return appSize; + } + + public void setAppSize(long appSize) { + this.appSize = appSize; + } + + public String getAppMd5() { + return appMd5; + } + + public void setAppMd5(String appMd5) { + this.appMd5 = appMd5; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } + + public static AriaDownloadInfo toAriaDownloadInfo(AppUpdateInfo appUpdateInfo) { + return new AriaDownloadInfo( + appUpdateInfo.getApp_id(), + appUpdateInfo.getApp().getApp_name(), + appUpdateInfo.getApp().getApp_package(), + appUpdateInfo.getApp_version_name(), + appUpdateInfo.getApp_version_code(), + appUpdateInfo.getApp_url(), + appUpdateInfo.getApp().getIcon(), + appUpdateInfo.getApp_size(), + appUpdateInfo.getApp_md5() + ); + } + +// public static AriaDownloadInfo toAriaDownloadInfo(AppInfo appInfo) { +// return new AriaDownloadInfo( +// appInfo.getId(), +// appInfo.getApp_name(), +// appInfo.getApp_package(), +// appInfo.getApp_version_name(), +// appInfo.getApp_version_code(), +// appInfo.getApp_url(), +// appInfo.getApp_img(), +// appInfo.getApp_size(), +// appInfo.getApp_md5() +// ); +// } + +// +// public static AriaDownloadInfo toAriaDownloadInfo(AppDetails appDetails) { +// return new AriaDownloadInfo( +// appDetails.getId(), +// appDetails.getApp_name(), +// appDetails.getApp_package(), +// appDetails.getApp_version_name(), +// appDetails.getApp_version_code(), +// appDetails.getApp_url(), +// appDetails.getApp_icon(), +// appDetails.getApp_size(), +// appDetails.getApp_md5() +// ); +// } +} diff --git a/app/src/main/java/com/hainaos/vc/CustomJzvd/JzvdStdAssert.java b/app/src/main/java/com/hainaos/vc/customjzvd/JzvdStdAssert.java similarity index 98% rename from app/src/main/java/com/hainaos/vc/CustomJzvd/JzvdStdAssert.java rename to app/src/main/java/com/hainaos/vc/customjzvd/JzvdStdAssert.java index 6af33ac..68a5949 100644 --- a/app/src/main/java/com/hainaos/vc/CustomJzvd/JzvdStdAssert.java +++ b/app/src/main/java/com/hainaos/vc/customjzvd/JzvdStdAssert.java @@ -1,4 +1,4 @@ -package com.hainaos.vc.CustomJzvd; +package com.hainaos.vc.customjzvd; import android.content.Context; import android.util.AttributeSet; diff --git a/app/src/main/java/com/hainaos/vc/CustomJzvd/JzvdStdTikTok.java b/app/src/main/java/com/hainaos/vc/customjzvd/JzvdStdTikTok.java similarity index 98% rename from app/src/main/java/com/hainaos/vc/CustomJzvd/JzvdStdTikTok.java rename to app/src/main/java/com/hainaos/vc/customjzvd/JzvdStdTikTok.java index 29378a1..c178325 100644 --- a/app/src/main/java/com/hainaos/vc/CustomJzvd/JzvdStdTikTok.java +++ b/app/src/main/java/com/hainaos/vc/customjzvd/JzvdStdTikTok.java @@ -1,4 +1,4 @@ -package com.hainaos.vc.CustomJzvd; +package com.hainaos.vc.customjzvd; import android.content.Context; import android.util.AttributeSet; diff --git a/app/src/main/java/com/hainaos/vc/CustomJzvd/MyJzvdStd.java b/app/src/main/java/com/hainaos/vc/customjzvd/MyJzvdStd.java similarity index 99% rename from app/src/main/java/com/hainaos/vc/CustomJzvd/MyJzvdStd.java rename to app/src/main/java/com/hainaos/vc/customjzvd/MyJzvdStd.java index d0c9f81..ad8c8d5 100644 --- a/app/src/main/java/com/hainaos/vc/CustomJzvd/MyJzvdStd.java +++ b/app/src/main/java/com/hainaos/vc/customjzvd/MyJzvdStd.java @@ -1,4 +1,4 @@ -package com.hainaos.vc.CustomJzvd; +package com.hainaos.vc.customjzvd; import android.content.Context; import android.util.AttributeSet; diff --git a/app/src/main/java/com/hainaos/vc/fragment/app/AppFragment.java b/app/src/main/java/com/hainaos/vc/fragment/app/AppFragment.java new file mode 100644 index 0000000..245cea8 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/fragment/app/AppFragment.java @@ -0,0 +1,65 @@ +package com.hainaos.vc.fragment.app; + +import android.app.Activity; +import android.os.Bundle; + +import androidx.lifecycle.Observer; +import androidx.recyclerview.widget.GridLayoutManager; + +import com.hainaos.vc.R; +import com.hainaos.vc.adapter.HomeAppAdapter; +import com.hainaos.vc.base.mvvm.fragment.BaseMvvmFragment; +import com.hainaos.vc.bean.HomeAppInfo; +import com.hainaos.vc.databinding.FragmentAppBinding; + +import java.util.List; + +public class AppFragment extends BaseMvvmFragment { + + private Activity mContext; + private HomeAppAdapter mHomeAppAdapter; + + + @Override + protected int getLayoutId() { + return R.layout.fragment_app; + } + + @Override + protected void initDataBinding() { + mContext = getActivity(); + mViewModel.setCtx(getCtx()); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewModel.setVDBinding(mViewDataBinding); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView(Bundle bundle) { + mHomeAppAdapter = new HomeAppAdapter(); + mViewDataBinding.rvApp.setLayoutManager(new GridLayoutManager(mContext, 5)); + mViewDataBinding.rvApp.setAdapter(mHomeAppAdapter); + + + } + + @Override + protected void initData(Bundle savedInstanceState) { + mViewModel.mHomeAppInfoListData.observe(this, new Observer>() { + @Override + public void onChanged(List homeAppInfos) { + mHomeAppAdapter.setHomeAppInfos(homeAppInfos); + } + }); + mViewModel.getAppList(); + } + + @Override + public void fetchData() { + mViewModel.getAppList(); + } + + public class BtnClick { + + } +} diff --git a/app/src/main/java/com/hainaos/vc/fragment/app/AppViewModel.java b/app/src/main/java/com/hainaos/vc/fragment/app/AppViewModel.java new file mode 100644 index 0000000..973bca6 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/fragment/app/AppViewModel.java @@ -0,0 +1,154 @@ +package com.hainaos.vc.fragment.app; + +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.hainaos.vc.BuildConfig; +import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.bean.HomeAppInfo; +import com.hainaos.vc.databinding.FragmentAppBinding; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.FragmentEvent; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.Callable; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.schedulers.Schedulers; + +public class AppViewModel extends BaseViewModel { + @Override + public void onDestroy() { + + } + + private static final List mExcludePackages = new ArrayList() {{ + this.add(BuildConfig.APPLICATION_ID); + }}; + + public MutableLiveData> mHomeAppInfoListData = new MutableLiveData<>(); + + public void getDirList() { + List homeAppInfos = new ArrayList<>(); + homeAppInfos.add(new HomeAppInfo("分类1", "", "", "1", true)); + homeAppInfos.add(new HomeAppInfo("分类2", "", "", "2", true)); + homeAppInfos.add(new HomeAppInfo("分类3", "", "", "3", true)); + homeAppInfos.add(new HomeAppInfo("分类4", "", "", "4", true)); + homeAppInfos.add(new HomeAppInfo("分类5", "", "", "5", true)); + homeAppInfos.add(new HomeAppInfo("分类6", "", "", "6", true)); + homeAppInfos.add(new HomeAppInfo("分类7", "", "", "7", true)); + homeAppInfos.add(new HomeAppInfo("分类8", "", "", "8", true)); + homeAppInfos.add(new HomeAppInfo("分类9", "", "", "9", true)); + homeAppInfos.add(new HomeAppInfo("分类10", "", "", "10", true)); + + homeAppInfos.add(new HomeAppInfo("用户中心", "user_center", "", "", true)); + + mHomeAppInfoListData.setValue(homeAppInfos); + } + + public void getAppList() { + Observable.fromCallable(new Callable>() { + @Override + public List call() throws Exception { + List homeAppInfos = new ArrayList<>(); +// homeAppInfos.add(new HomeAppInfo("分类1", "", "", "1", true)); +// homeAppInfos.add(new HomeAppInfo("分类2", "", "", "2", true)); +// homeAppInfos.add(new HomeAppInfo("分类3", "", "", "3", true)); +// homeAppInfos.add(new HomeAppInfo("分类4", "", "", "4", true)); +// homeAppInfos.add(new HomeAppInfo("分类5", "", "", "5", true)); +// homeAppInfos.add(new HomeAppInfo("分类6", "", "", "6", true)); +// homeAppInfos.add(new HomeAppInfo("分类7", "", "", "7", true)); +// homeAppInfos.add(new HomeAppInfo("分类8", "", "", "8", true)); +// homeAppInfos.add(new HomeAppInfo("分类9", "", "", "9", true)); +// homeAppInfos.add(new HomeAppInfo("分类10", "", "", "10", true)); +// +// homeAppInfos.add(new HomeAppInfo("用户中心", "user_center", "", "", true)); + + PackageManager packageManager = getCtx().getPackageManager(); + // 创建一个类别为CATEGORY_LAUNCHER的该包名的Intent + Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null); + resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER); + + // 通过getPackageManager()的queryIntentActivities方法遍历,得到所有能打开的app的packageName + List resolveinfoList = packageManager.queryIntentActivities(resolveIntent, 0); + List appInfos = resolveinfoList + .stream() + .filter(new Predicate() { + @Override + public boolean test(ResolveInfo resolveInfo) { + return !mExcludePackages.contains(resolveInfo.activityInfo.packageName); + } + }) + .sorted(new Comparator() { + @Override + public int compare(ResolveInfo o1, ResolveInfo o2) { + if ((o1.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) <= (o2.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)) { + return 1; + } else { + return -1; + } + } + }) + .map(new Function() { + @Override + public HomeAppInfo apply(ResolveInfo resolveInfo) { + return new HomeAppInfo(resolveInfo.loadLabel(packageManager).toString(), resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name, "", false); + } + }) + .sorted(new Comparator() { + @Override + public int compare(HomeAppInfo o1, HomeAppInfo o2) { + return Collator.getInstance(Locale.CHINESE).compare(o1.getName(), o2.getName()); + } + }) + + .collect(Collectors.toList()); + + homeAppInfos.addAll(appInfos); + + return homeAppInfos; + } + }).subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY)) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getAppList", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull List homeAppInfos) { + Log.e("getAppList", "onNext: " + homeAppInfos.size()); + mHomeAppInfoListData.setValue(homeAppInfos); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getAppList", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("getAppList", "onComplete: "); + } + }); + + } +} diff --git a/app/src/main/java/com/hainaos/vc/fragment/category/CategoryFragment.java b/app/src/main/java/com/hainaos/vc/fragment/category/CategoryFragment.java new file mode 100644 index 0000000..13a4cc6 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/fragment/category/CategoryFragment.java @@ -0,0 +1,76 @@ +package com.hainaos.vc.fragment.category; + +import android.app.Activity; +import android.os.Bundle; + +import androidx.lifecycle.Observer; +import androidx.recyclerview.widget.GridLayoutManager; + +import com.hainaos.vc.R; +import com.hainaos.vc.adapter.HomeCategoryAdapter; +import com.hainaos.vc.base.mvvm.fragment.BaseMvvmFragment; +import com.hainaos.vc.bean.CategoryInfo; +import com.hainaos.vc.bean.HomeAppInfo; +import com.hainaos.vc.databinding.FragmentCategoryBinding; + +import java.util.List; + +public class CategoryFragment extends BaseMvvmFragment { + + private Activity mContext; + // private HomeAppAdapter mHomeAppAdapter; + private HomeCategoryAdapter mCategoryAdapter; + + @Override + protected int getLayoutId() { + return R.layout.fragment_category; + } + + @Override + protected void initDataBinding() { + mContext = getActivity(); + mViewModel.setCtx(getCtx()); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewModel.setVDBinding(mViewDataBinding); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView(Bundle bundle) { +// mHomeAppAdapter = new HomeAppAdapter(); + mCategoryAdapter = new HomeCategoryAdapter(); + mViewDataBinding.rvApp.setLayoutManager(new GridLayoutManager(mContext, 5)); +// mViewDataBinding.rvApp.setAdapter(mHomeAppAdapter); + mViewDataBinding.rvApp.setAdapter(mCategoryAdapter); + } + + @Override + protected void initData(Bundle savedInstanceState) { + mViewModel.mHomeAppInfoListData.observe(this, new Observer>() { + @Override + public void onChanged(List homeAppInfos) { +// mHomeAppAdapter.setHomeAppInfos(homeAppInfos); + } + }); +// mViewModel.getDirList(); + mViewModel.mCategoryInfoListData.observe(this, new Observer>() { + @Override + public void onChanged(List categoryInfos) { + categoryInfos.add(new CategoryInfo("下载视频", HomeCategoryAdapter.DOWNLOAD_CENTER)); + categoryInfos.add(new CategoryInfo("用户中心", HomeCategoryAdapter.USER_CENTER)); + mCategoryAdapter.setCategoryInfos(categoryInfos); + } + }); + mViewModel.getCategoryList(); + } + + @Override + public void fetchData() { +// mViewModel.getDirList(); + mViewModel.getCategoryList(); + } + + public class BtnClick { + + } +} diff --git a/app/src/main/java/com/hainaos/vc/fragment/category/CategoryViewModel.java b/app/src/main/java/com/hainaos/vc/fragment/category/CategoryViewModel.java new file mode 100644 index 0000000..9d63788 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/fragment/category/CategoryViewModel.java @@ -0,0 +1,95 @@ +package com.hainaos.vc.fragment.category; + +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.hainaos.vc.BuildConfig; +import com.hainaos.vc.adapter.HomeAppAdapter; +import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CategoryInfo; +import com.hainaos.vc.bean.HomeAppInfo; +import com.hainaos.vc.databinding.FragmentCategoryBinding; +import com.hainaos.vc.network.NetInterfaceManager; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.FragmentEvent; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.rxjava3.annotations.NonNull; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; + +public class CategoryViewModel extends BaseViewModel { + + @Override + public FragmentCategoryBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } + + private static final List mExcludePackages = new ArrayList() {{ + this.add(BuildConfig.APPLICATION_ID); + }}; + + @Deprecated + public MutableLiveData> mHomeAppInfoListData = new MutableLiveData<>(); + + @Deprecated + public void getDirList() { + List homeAppInfos = new ArrayList<>(); + homeAppInfos.add(new HomeAppInfo("分类1", "", "", "1", true)); + homeAppInfos.add(new HomeAppInfo("分类2", "", "", "2", true)); + homeAppInfos.add(new HomeAppInfo("分类3", "", "", "3", true)); + homeAppInfos.add(new HomeAppInfo("分类4", "", "", "4", true)); + homeAppInfos.add(new HomeAppInfo("分类5", "", "", "5", true)); + homeAppInfos.add(new HomeAppInfo("分类6", "", "", "6", true)); + homeAppInfos.add(new HomeAppInfo("分类7", "", "", "7", true)); + homeAppInfos.add(new HomeAppInfo("分类8", "", "", "8", true)); + homeAppInfos.add(new HomeAppInfo("分类9", "", "", "9", true)); + homeAppInfos.add(new HomeAppInfo("分类10", "", "", "10", true)); + + homeAppInfos.add(new HomeAppInfo("下载视频", HomeAppAdapter.DOWNLOAD_CENTER, "", "", true)); + homeAppInfos.add(new HomeAppInfo("用户中心", HomeAppAdapter.USER_CENTER, "", "", true)); + + mHomeAppInfoListData.setValue(homeAppInfos); + } + + public MutableLiveData> mCategoryInfoListData = new MutableLiveData<>(); + + public void getCategoryList() { + NetInterfaceManager.getInstance().getCategoryListObservable() + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY)) + .subscribe(new Observer>>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getCategoryList", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse> baseResponse) { + Log.e("getCategoryList", "onNext: " + baseResponse); + if (baseResponse.code == 200) { + List categoryInfos = baseResponse.data; + mCategoryInfoListData.setValue(categoryInfos); + } + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getCategoryList", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("getCategoryList", "onComplete: "); + } + }); + } +} diff --git a/app/src/main/java/com/hainaos/vc/fragment/passwd/PasswdDialogFragment.java b/app/src/main/java/com/hainaos/vc/fragment/passwd/PasswdDialogFragment.java new file mode 100644 index 0000000..7421a04 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/fragment/passwd/PasswdDialogFragment.java @@ -0,0 +1,133 @@ +package com.hainaos.vc.fragment.passwd; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; + +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +import com.hainaos.vc.R; +import com.hainaos.vc.activity.category.online.CategoryVideoActivity; +import com.hainaos.vc.base.mvvm.fragment.BaseMvvmDialogFragment; +import com.hainaos.vc.bean.CategoryInfo; +import com.hainaos.vc.databinding.FragmentDialogPasswdBinding; +import com.hjq.toast.Toaster; + +public class PasswdDialogFragment extends BaseMvvmDialogFragment { + private static final String TAG = "PasswdDialogFragment"; + private Activity mContext; + + private CategoryInfo mCategoryInfo; + + public PasswdDialogFragment(CategoryInfo categoryInfo) { + mCategoryInfo = categoryInfo; + } + + public interface ConfimCallback { + void onConfig(String passwd); + } + + private ConfimCallback mConfimCallback; + + public void setConfimCallback(ConfimCallback confimCallback) { + mConfimCallback = confimCallback; + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_dialog_passwd; + } + + @Override + protected void initDataBinding() { + mContext = getActivity(); + mViewModel.setCtx(getCtx()); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewModel.setVDBinding(mViewDataBinding); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView(Bundle bundle) { + + } + + @Override + protected void initData(Bundle savedInstanceState) { + + } + + @Override + public void fetchData() { + + } + + @Override + public void onStart() { + super.onStart(); + if (getDialog() != null) { + Window window = getDialog().getWindow(); + if (window == null) return; + WindowManager.LayoutParams params = window.getAttributes(); + params.width = WindowManager.LayoutParams.MATCH_PARENT; + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + params.gravity = Gravity.CENTER; + window.setAttributes(params); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + getDialog().setCancelable(true); + getDialog().setCanceledOnTouchOutside(true); + } + } + + @Override + public void show(FragmentManager manager, String tag) { + DialogFragment fragment = (DialogFragment) manager.findFragmentByTag(tag); + if (fragment != null && fragment.isAdded() + && fragment.getDialog() != null && fragment.getDialog().isShowing()) { + return; + } + + try { + FragmentTransaction ft = manager.beginTransaction(); + ft.add(this, tag); + ft.commitAllowingStateLoss(); + } catch (Exception e) { + Log.e(TAG, "show: " + e.getMessage()); + } + } + + private void openCategory(CategoryInfo categoryInfo, String passwd) { + Intent intent = new Intent(mContext, CategoryVideoActivity.class); + intent.putExtra("CategoryInfo", categoryInfo); + intent.putExtra("Password", passwd); + mContext.startActivity(intent); + } + + public class BtnClick { + public void confim(View view) { + Editable editable = mViewDataBinding.etPasswd.getText(); + if (TextUtils.isEmpty(editable)) { + Toaster.show("请输入密码"); + return; + } + String passwd = editable.toString(); + if (mConfimCallback == null) { + openCategory(mCategoryInfo, passwd); + } else { + mConfimCallback.onConfig(passwd); + } + dismiss(); + } + } +} diff --git a/app/src/main/java/com/hainaos/vc/fragment/passwd/PasswdViewModel.java b/app/src/main/java/com/hainaos/vc/fragment/passwd/PasswdViewModel.java new file mode 100644 index 0000000..f1764c7 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/fragment/passwd/PasswdViewModel.java @@ -0,0 +1,18 @@ +package com.hainaos.vc.fragment.passwd; + +import com.hainaos.vc.base.mvvm.BaseViewModel; +import com.hainaos.vc.databinding.FragmentDialogPasswdBinding; +import com.trello.rxlifecycle4.android.FragmentEvent; + +public class PasswdViewModel extends BaseViewModel { + + @Override + public FragmentDialogPasswdBinding getVDBinding() { + return binding; + } + + @Override + public void onDestroy() { + + } +} diff --git a/app/src/main/java/com/hainaos/vc/fragment/pic/PictureViewModel.java b/app/src/main/java/com/hainaos/vc/fragment/pic/PictureViewModel.java index b3b2f69..dc56fec 100644 --- a/app/src/main/java/com/hainaos/vc/fragment/pic/PictureViewModel.java +++ b/app/src/main/java/com/hainaos/vc/fragment/pic/PictureViewModel.java @@ -5,7 +5,6 @@ import androidx.lifecycle.MutableLiveData; import com.hainaos.vc.base.mvvm.BaseViewModel; import com.hainaos.vc.bean.PhotoInfo; import com.hainaos.vc.databinding.FragmentPictureBinding; -import com.hainaos.vc.network.NetInterfaceManager; import com.trello.rxlifecycle4.android.FragmentEvent; import java.util.ArrayList; @@ -27,16 +26,6 @@ public class PictureViewModel extends BaseViewModel mCompleteData = new MutableLiveData<>(); public void getHomePhoto() { - NetInterfaceManager.getInstance().getHomePhotoFragment(getLifecycle(), new NetInterfaceManager.onPhotoCallback() { - @Override - public void setPhotoList(ArrayList photoList) { - mPhotoInfosData.setValue(photoList); - } - @Override - public void onComplete() { - mCompleteData.setValue(true); - } - }); } } diff --git a/app/src/main/java/com/hainaos/vc/fragment/video/VideoFragment.java b/app/src/main/java/com/hainaos/vc/fragment/video/VideoFragment.java index 9249afc..c84280c 100644 --- a/app/src/main/java/com/hainaos/vc/fragment/video/VideoFragment.java +++ b/app/src/main/java/com/hainaos/vc/fragment/video/VideoFragment.java @@ -20,9 +20,9 @@ import com.hainaos.vc.base.mvvm.fragment.BaseMvvmFragment; import com.hainaos.vc.bean.LocalVideoInfo; import com.hainaos.vc.databinding.FragmentVideoBinding; import com.hainaos.vc.gson.GsonUtils; +import com.hainaos.vc.utils.FileUtils; import com.hainaos.vc.utils.ScreenUtils; import com.hainaos.vc.utils.ToastUtil; -import com.hainaos.vc.utils.VideoUtils; import com.hainaos.vc.view.CustomDialog; import com.hainaos.vc.view.EquallyDividedItemDecoration; import com.hainaos.vc.view.RecycleGridLayoutManager; @@ -163,7 +163,7 @@ public class VideoFragment extends BaseMvvmFragment mCompleteData = new MutableLiveData<>(); public void getHomeVideo() { - NetInterfaceManager.getInstance().getHomeVideoFragment(getLifecycle(), new NetInterfaceManager.onVideoPathCallback() { - @Override - public void setVideoList(ArrayList videoList) { - mPhotoInfosData.setValue(videoList); - } - @Override - public void onComplete() { - mCompleteData.setValue(true); - } - }); } } diff --git a/app/src/main/java/com/hainaos/vc/network/NetInterfaceManager.java b/app/src/main/java/com/hainaos/vc/network/NetInterfaceManager.java index b8442d1..25b1a31 100644 --- a/app/src/main/java/com/hainaos/vc/network/NetInterfaceManager.java +++ b/app/src/main/java/com/hainaos/vc/network/NetInterfaceManager.java @@ -1,54 +1,36 @@ package com.hainaos.vc.network; import android.annotation.SuppressLint; -import android.content.ContentResolver; import android.content.Context; -import android.os.Environment; -import android.util.Log; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -import com.hainaos.vc.bean.ActivationInfo; +import com.hainaos.vc.BuildConfig; import com.hainaos.vc.bean.BaseResponse; -import com.hainaos.vc.bean.LocalVideoInfo; -import com.hainaos.vc.bean.PhotoInfo; -import com.hainaos.vc.bean.SpaceInfo; -import com.hainaos.vc.bean.VideoInfo; +import com.hainaos.vc.bean.CategoryInfo; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.bean.LoginInfo; +import com.hainaos.vc.bean.UserInfo; +import com.hainaos.vc.bean.VideoListData; +import com.hainaos.vc.bean.uiuios.AppUpdateInfo; import com.hainaos.vc.config.CommonConfig; -import com.hainaos.vc.disklrucache.CacheHelper; -import com.hainaos.vc.gson.GsonUtils; -import com.hainaos.vc.manager.ConnectManager; -import com.hainaos.vc.manager.ConnectMode; -import com.hainaos.vc.network.api.ActivationApi; -import com.hainaos.vc.network.api.FileApi; +import com.hainaos.vc.network.api.AppApi; +import com.hainaos.vc.network.api.LoginApi; +import com.hainaos.vc.network.api.UserApi; +import com.hainaos.vc.network.api.VideoApi; +import com.hainaos.vc.network.api.uiuios.CheckUpdateApi; import com.hainaos.vc.network.interceptor.RepeatRequestInterceptor; -import com.hainaos.vc.utils.JgyUtils; -import com.hainaos.vc.utils.ToastUtil; +import com.hainaos.vc.utils.FileUtils; +import com.hainaos.vc.utils.LoginUtils; import com.hainaos.vc.utils.Utils; -import com.hainaos.vc.utils.VideoUtils; import com.tencent.mmkv.MMKV; -import com.trello.rxlifecycle4.RxLifecycle; -import com.trello.rxlifecycle4.android.ActivityEvent; -import com.trello.rxlifecycle4.android.FragmentEvent; import java.io.File; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; -import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.core.ObservableEmitter; -import io.reactivex.rxjava3.core.ObservableOnSubscribe; -import io.reactivex.rxjava3.core.Observer; -import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.functions.BiFunction; import io.reactivex.rxjava3.schedulers.Schedulers; -import io.reactivex.rxjava3.subjects.BehaviorSubject; import okhttp3.Cache; import okhttp3.OkHttpClient; import retrofit2.Retrofit; @@ -61,18 +43,20 @@ public class NetInterfaceManager { @SuppressLint("StaticFieldLeak") private static NetInterfaceManager INSTANCE; private Context mContext; - private ContentResolver crv; + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + private Retrofit mRetrofit; - private OkHttpClient okHttpClient; - private CacheHelper mCacheHelper; + private OkHttpClient mOkHttpClient; + private Retrofit mUiuiosRetrofit; + private OkHttpClient mUiuiosOkHttpClient; private final ConcurrentHashMap requestIdsMap = new ConcurrentHashMap<>(); //超时时间 - private static final int timeOut = 5; + private static final int TIME_OUT = 5; // 缓存文件最大限制大小20M - private static final long cacheSize = 1024 * 1024 * 64; + private static final long CACHE_SIZE = 1024 * 1024 * 64; public static final String CUSTOM_REPEAT_REQ_PROTOCOL = "MY_CUSTOM_REPEAT_REQ_PROTOCOL"; private NetInterfaceManager(Context context) { @@ -80,50 +64,56 @@ public class NetInterfaceManager { throw new RuntimeException("Context is NULL"); } this.mContext = context; - this.crv = mContext.getContentResolver(); - this.mCacheHelper = new CacheHelper(mContext); - if (null == mRetrofit) { - if (okHttpClient == null) { - //如果无法生存缓存文件目录,检测权限使用已经加上,检测手机是否把文件读写权限禁止了 - OkHttpClient.Builder builder = new OkHttpClient.Builder(); - builder.connectTimeout(timeOut, TimeUnit.SECONDS); // 设置连接超时时间 - builder.writeTimeout(timeOut, TimeUnit.SECONDS);// 设置写入超时时间 - builder.readTimeout(timeOut, TimeUnit.SECONDS);// 设置读取数据超时时间 - builder.retryOnConnectionFailure(true);// 设置进行连接失败重试 - builder.addInterceptor(new RepeatRequestInterceptor()); + if (mOkHttpClient == null) { + //如果无法生存缓存文件目录,检测权限使用已经加上,检测手机是否把文件读写权限禁止了 + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.connectTimeout(TIME_OUT, TimeUnit.SECONDS); // 设置连接超时时间 + builder.writeTimeout(TIME_OUT, TimeUnit.SECONDS);// 设置写入超时时间 + builder.readTimeout(TIME_OUT, TimeUnit.SECONDS);// 设置读取数据超时时间 + builder.retryOnConnectionFailure(true);// 设置进行连接失败重试 + builder.addInterceptor(new RepeatRequestInterceptor()); - // 设置缓存文件路径 - String cacheDirectory = getCacheDir() + "/OkHttpCache"; - Cache cache = new Cache(new File(cacheDirectory), cacheSize); - builder.cache(cache);// 设置缓存 - okHttpClient = builder.build(); - } + // 设置缓存文件路径 + String cacheDirectory = FileUtils.getCacheDir(mContext) + "/OkHttpCache"; + Cache cache = new Cache(new File(cacheDirectory), CACHE_SIZE); + builder.cache(cache);// 设置缓存 + mOkHttpClient = builder.build(); + } + if (mRetrofit == null) { mRetrofit = new Retrofit.Builder() - .client(okHttpClient) + .client(mOkHttpClient) .baseUrl(UrlAddress.ROOT_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) .build(); } - } - private String getCacheDir() { - String cachePath; - if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) - || !Environment.isExternalStorageRemovable()) { - if (mContext.getExternalCacheDir() != null) { - cachePath = mContext.getExternalCacheDir().getPath(); - } else if (mContext.getExternalFilesDir("cache") != null) { - cachePath = mContext.getExternalFilesDir("cache").getPath(); - } else { - cachePath = mContext.getCacheDir().getPath(); - } - } else { - cachePath = mContext.getCacheDir().getPath(); + if (mUiuiosOkHttpClient == null) { + //如果无法生存缓存文件目录,检测权限使用已经加上,检测手机是否把文件读写权限禁止了 + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.connectTimeout(TIME_OUT, TimeUnit.SECONDS); // 设置连接超时时间 + builder.writeTimeout(TIME_OUT, TimeUnit.SECONDS);// 设置写入超时时间 + builder.readTimeout(TIME_OUT, TimeUnit.SECONDS);// 设置读取数据超时时间 + builder.retryOnConnectionFailure(true);// 设置进行连接失败重试 + builder.addInterceptor(new RepeatRequestInterceptor()); + + // 设置缓存文件路径 + Cache cache = new Cache(new File(FileUtils.getCacheDir(mContext) + "/OkHttpCache"), CACHE_SIZE); + builder.cache(cache);// 设置缓存 + mUiuiosOkHttpClient = builder.build(); } - return cachePath; + + if (mUiuiosRetrofit == null) { + mUiuiosRetrofit = new Retrofit.Builder() + .client(mUiuiosOkHttpClient) + .baseUrl(UrlAddress.UIUIOS_ROOT_URL) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) + .build(); + } + } public static void init(Context context) { @@ -143,7 +133,19 @@ public class NetInterfaceManager { } public OkHttpClient getOkHttpClient() { - return okHttpClient; + return mOkHttpClient; + } + + public LoginApi getLoginApi() { + return mRetrofit.create(LoginApi.class); + } + + public UserApi getUserApi() { + return mRetrofit.create(UserApi.class); + } + + public VideoApi getVideoApi() { + return mRetrofit.create(VideoApi.class); } /* @@ -152,384 +154,111 @@ public class NetInterfaceManager { * * */ - public Observable>> getHomeVideoControl() { - return mRetrofit.create(FileApi.class) - .getHomeVideo(Utils.getSerial()) + public Observable getLoginObservable(String mobile, String password) { + return getLoginApi() + .login(Utils.getSerial(), mobile, password) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } - public Observable>> getHomePhotoControl() { - return mRetrofit.create(FileApi.class) - .getHomePhoto(Utils.getSerial()) + public Observable> getPhoneLoginObservable(String verify_key, String mobile, String captcha) { + return getLoginApi() + .mobileLogin(Utils.getSerial(), mobile, captcha, verify_key) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } - public Observable> getHomeSpaceInfoControl() { - return mRetrofit.create(FileApi.class) - .getHomeSpaceInfo(Utils.getSerial()) + public Observable> getSendCodeObservable(String mobile) { + return getLoginApi() + .sendCode(mobile) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } - public Observable> getActivationControl() { - return mRetrofit.create(ActivationApi.class) - .getActivation(Utils.getSerial()) + public Observable> getResetCodeObservable() { + String bearerToken = LoginUtils.getInstance().getBearerToken(); + return getUserApi() + .getResetCode(bearerToken) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } - public interface onVideoPathCallback { - void setVideoList(ArrayList videoList); - - void onComplete(); - } - - public void getHomeVideo(boolean refresh, BehaviorSubject lifecycle, onVideoPathCallback callback) { - ConnectMode connectMode = ConnectMode.ONE_MINUTE; - if (refresh) { - connectMode = ConnectMode.DEFAULT; - } - if (ConnectManager.getInstance().isNeedConnect(UrlAddress.HOME_VIDEO, connectMode)) { - getHomeVideo(lifecycle, callback); - } else { - String jsonString = mCacheHelper.getAsString(UrlAddress.HOME_VIDEO); - //为 "" 是已经请求成功的 - if (jsonString == null) { - getHomeVideo(lifecycle, callback); - } else { - getHomeVideoCache(jsonString, callback); - } - } - } - - public void getHomeVideoCache(String jsonString, onVideoPathCallback callback) { - Gson gson = new Gson(); - Type type = new TypeToken>() { - }.getType(); - try { - List videoInfos = gson.fromJson(jsonString, type); - ArrayList LocalVideoInfos = new ArrayList<>(); - for (VideoInfo videoInfo : videoInfos) { - LocalVideoInfo localVideoInfo = new LocalVideoInfo(); - localVideoInfo.setFile(videoInfo.getFile()); - localVideoInfo.setFile_name(videoInfo.getFile_name()); - localVideoInfo.setFile_md5(videoInfo.getFile_md5()); - localVideoInfo.setDuration(videoInfo.getDuration()); - if (JgyUtils.getInstance().fileExists(videoInfo.getFile())) { - localVideoInfo.setLocalPath(JgyUtils.getInstance().getUrlLocalPath(videoInfo.getFile())); - } - LocalVideoInfos.add(localVideoInfo); - } - callback.setVideoList(LocalVideoInfos); - } catch (Exception e) { - Log.e(TAG, "getHomeVideo: " + e.getMessage()); - callback.setVideoList(null); - } - callback.onComplete(); - } - - public void getHomeVideo(BehaviorSubject lifecycle, onVideoPathCallback callback) { - getHomeVideoControl() - .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) - .subscribe(getHomeVideoObserver(callback)); - } - - public void getHomeVideoFragment(BehaviorSubject lifecycle, onVideoPathCallback callback) { - getHomeVideoControl() - .compose(RxLifecycle.bindUntilEvent(lifecycle, FragmentEvent.DESTROY)) - .subscribe(getHomeVideoObserver(callback)); - } - - public void getHomeVideo(onVideoPathCallback callback) { - getHomeVideoControl() - .subscribe(getHomeVideoObserver(callback)); - } - - public void getHomeVideo() { - getHomeVideoControl() - .subscribe(getHomeVideoObserver(null)); - } - - private Observer>> getHomeVideoObserver(onVideoPathCallback callback) { - return new Observer>>() { - @Override - public void onSubscribe(@NonNull Disposable d) { - Log.e("getHomeVideo", "onSubscribe: "); - } - - @Override - public void onNext(@NonNull BaseResponse> listBaseResponse) { - Log.e("getHomeVideo", "onNext: " + listBaseResponse); - int code = listBaseResponse.code; - if (code == 200) { - List videoInfos = listBaseResponse.data; - ArrayList LocalVideoInfos = new ArrayList<>(); - for (VideoInfo videoInfo : videoInfos) { - LocalVideoInfo localVideoInfo = new LocalVideoInfo(); - localVideoInfo.setFile(videoInfo.getFile()); - localVideoInfo.setFile_name(videoInfo.getFile_name()); - localVideoInfo.setFile_md5(videoInfo.getFile_md5()); - localVideoInfo.setDuration(videoInfo.getDuration()); - if (JgyUtils.getInstance().fileExists(videoInfo.getFile())) { - localVideoInfo.setLocalPath(JgyUtils.getInstance().getUrlLocalPath(videoInfo.getFile())); - } - LocalVideoInfos.add(localVideoInfo); - } - callback.setVideoList(LocalVideoInfos); - mCacheHelper.put(UrlAddress.HOME_VIDEO, GsonUtils.toJSONString(videoInfos)); - } else { - callback.setVideoList(null); - mCacheHelper.put(UrlAddress.HOME_VIDEO, ""); - } - } - - @Override - public void onError(@NonNull Throwable e) { - Log.e("getHomeVideo", "onError: " + e.getMessage()); - ToastUtil.show("网络连接失败"); - String jsonString = mCacheHelper.getAsString(UrlAddress.HOME_VIDEO); - getHomeVideoCache(jsonString, callback); - onComplete(); - } - - @Override - public void onComplete() { - Log.e("getHomeVideo", "onComplete: "); - if (callback != null) { - callback.onComplete(); - } - } - }; - } - - public Observable> getLocalVideo() { - return Observable.create(new ObservableOnSubscribe>() { - @Override - public void subscribe(@NonNull ObservableEmitter> emitter) throws Throwable { - long s1 = System.currentTimeMillis(); - List fileList = new ArrayList<>(); - String rootPath = Environment.getExternalStorageDirectory().getPath() + File.separator; - File file = new File(rootPath); - if (file.exists()) { - LinkedList list = new LinkedList(); - File[] files = file.listFiles(); - if (files == null) { - emitter.onNext(null); - } else { - for (File file2 : files) { - if (file2.isDirectory()) { - list.add(file2); - } else { - if (VideoUtils.isVideoFormat(file2.getAbsolutePath())) { - fileList.add(file2.getAbsolutePath()); - } - } - } - File temp_file; - while (!list.isEmpty()) { - temp_file = list.removeFirst(); - files = temp_file.listFiles(); - if (files == null) { - continue; - } - for (File file2 : files) { - if (file2.isDirectory()) { - list.add(file2); - } else { - if (VideoUtils.isVideoFormat(file2.getAbsolutePath())) { - fileList.add(file2.getAbsolutePath()); - } - } - } - } - emitter.onNext(fileList); - } - } else { - emitter.onNext(null); - Log.e("traverseFolder1", "文件不存在!"); - } - Log.e("ScanTask", "doInBackground: " + "Scan time = " + (System.currentTimeMillis() - s1) + "ms"); - emitter.onComplete(); - } - }) - .subscribeOn(Schedulers.newThread()) + public Observable> getUserInfoObservable() { + String bearerToken = LoginUtils.getInstance().getBearerToken(); + return getUserApi() + .getUserInfo(bearerToken) + .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } - public void getVideoPath(BehaviorSubject lifecycle, onVideoPathCallback callback) { - Observable.zip(getHomeVideoControl(), getLocalVideo(), new BiFunction>, List, ArrayList>() { - @Override - public ArrayList apply(BaseResponse> listBaseResponse, List strings) throws Throwable { - ArrayList LocalVideoInfos = new ArrayList<>(); - if (listBaseResponse.code == 200) { - List videoInfos = listBaseResponse.data; -// List videoList = videoInfos.stream().map(VideoInfo::getFile).collect(Collectors.toList()); - for (VideoInfo videoInfo : videoInfos) { - LocalVideoInfo localVideoInfo = new LocalVideoInfo(); - localVideoInfo.setFile(videoInfo.getFile()); - localVideoInfo.setFile_md5(videoInfo.getFile_md5()); - localVideoInfo.setDuration(videoInfo.getDuration()); - if (JgyUtils.getInstance().fileExists(videoInfo.getFile())) { - localVideoInfo.setLocalPath(JgyUtils.getInstance().getUrlLocalPath(videoInfo.getFile())); - } - LocalVideoInfos.add(localVideoInfo); - } - } - if (strings != null && strings.size() != 0) { - for (String s : strings) { - LocalVideoInfo localVideoInfo = new LocalVideoInfo(); - localVideoInfo.setLocalPath(s); - LocalVideoInfos.add(localVideoInfo); - } - } - return LocalVideoInfos; - } - }) + public Observable getRestPasswdObservable(String password, String confirm_password, String captcha, String verify_key) { + String bearerToken = LoginUtils.getInstance().getBearerToken(); + return getUserApi() + .restPasswd(bearerToken, password, confirm_password, captcha, verify_key) .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) - .subscribe(new Observer>() { - @Override - public void onSubscribe(@NonNull Disposable d) { - Log.e("getVideoPath", "onSubscribe: "); - } - - @Override - public void onNext(@NonNull ArrayList strings) { - Log.e("getVideoPath", "onNext: " + strings); - callback.setVideoList(strings); - } - - @Override - public void onError(@NonNull Throwable e) { - Log.e("getVideoPath", "onError: " + e.getMessage()); - onComplete(); - } - - @Override - public void onComplete() { - Log.e("getVideoPath", "onComplete: "); - callback.onComplete(); - } - }); + .observeOn(AndroidSchedulers.mainThread()); } - public interface onPhotoCallback { - void setPhotoList(ArrayList photoList); - - void onComplete(); + public Observable> getSetCodeObservable() { + String bearerToken = LoginUtils.getInstance().getBearerToken(); + return getUserApi() + .getSetCode(bearerToken) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); } - public void getHomePhoto(boolean refresh, BehaviorSubject lifecycle, onPhotoCallback callback) { - ConnectMode connectMode = ConnectMode.ONE_MINUTE; - if (refresh) { - connectMode = ConnectMode.DEFAULT; - } - if (ConnectManager.getInstance().isNeedConnect(UrlAddress.HOME_PHOTO, connectMode)) { - getHomePhoto(lifecycle, callback); - } else { - String jsonString = mCacheHelper.getAsString(UrlAddress.HOME_PHOTO); - //为 "" 是已经请求成功的 - if (jsonString == null) { - getHomePhoto(lifecycle, callback); - } else { - getHomePhotoCache(jsonString, callback); - } - } + public Observable getSetPasswdObservable(String password, String confirm_password, String captcha, String verify_key) { + String bearerToken = LoginUtils.getInstance().getBearerToken(); + return getUserApi() + .setPasswd(bearerToken, password, confirm_password, captcha, verify_key) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); } - - public void getHomePhotoCache(String jsonString, onPhotoCallback callback) { - Gson gson = new Gson(); - Type type = new TypeToken>() { - }.getType(); - try { - ArrayList photoInfoList = gson.fromJson(jsonString, type); - if (callback != null) { - callback.setPhotoList(photoInfoList); - } - } catch (Exception e) { - Log.e(TAG, "getHomePhotoCache: " + e.getMessage()); - if (callback != null) { - callback.setPhotoList(null); - } - } - if (callback != null) { - callback.onComplete(); - } + public Observable> getModifyMobileCodeObservable(String phoneNumber) { + String bearerToken = LoginUtils.getInstance().getBearerToken(); + return getUserApi() + .getModifyMobileCode(bearerToken, phoneNumber) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); } - public void getHomePhoto(BehaviorSubject lifecycle, onPhotoCallback callback) { - getHomePhotoControl() - .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) - .subscribe(getHomePhotoObserver(callback)); + public Observable getModifyMobileObservable(String mobile, String captcha, String verify_key) { + String bearerToken = LoginUtils.getInstance().getBearerToken(); + return getUserApi() + .modifyMobileNumber(bearerToken, mobile, captcha, verify_key) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); } - public void getHomePhotoFragment(BehaviorSubject lifecycle, onPhotoCallback callback) { - getHomePhotoControl() - .compose(RxLifecycle.bindUntilEvent(lifecycle, FragmentEvent.DESTROY)) - .subscribe(getHomePhotoObserver(callback)); + public Observable>> getCategoryListObservable() { + String bearerToken = LoginUtils.getInstance().getBearerToken(); + return getVideoApi() + .getCategoryList(bearerToken) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); } - public void getHomePhoto(onPhotoCallback callback) { - getHomePhotoControl() - .subscribe(getHomePhotoObserver(callback)); + public Observable> getVideoListObservable(String category_uuid, String password) { + String bearerToken = LoginUtils.getInstance().getBearerToken(); + return getVideoApi() + .getVideoList(bearerToken, category_uuid, password) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); } - public void getHomePhoto() { - getHomePhotoControl() - .subscribe(getHomePhotoObserver(null)); + public Observable getCheckUpdateObservable() { + return mRetrofit.create(AppApi.class) + .checkUpdate(BuildConfig.APPLICATION_ID) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); } - private Observer>> getHomePhotoObserver(onPhotoCallback callback) { - return new Observer>>() { - @Override - public void onSubscribe(@NonNull Disposable d) { - Log.e("getHomePhotoObserver", "onSubscribe: "); - } - - @Override - public void onNext(@NonNull BaseResponse> listBaseResponse) { - Log.e("getHomePhotoObserver", "onNext: " + listBaseResponse); - int code = listBaseResponse.code; - if (code == 200) { - ArrayList photoInfoList = listBaseResponse.data; - for (PhotoInfo photoInfo : photoInfoList) { - if (!JgyUtils.getInstance().fileExists(photoInfo.getFile())) { - JgyUtils.getInstance().ariaDownload(photoInfo.getFile(), GsonUtils.getJsonObject(GsonUtils.toJSONString(photoInfo))); - } - } - mCacheHelper.put(UrlAddress.HOME_PHOTO, GsonUtils.toJSONString(photoInfoList)); - if (callback != null) { - callback.setPhotoList(photoInfoList); - } - } else { - mCacheHelper.put(UrlAddress.HOME_PHOTO, ""); - if (callback != null) { - callback.setPhotoList(null); - } - } - } - - @Override - public void onError(@NonNull Throwable e) { - Log.e("getHomePhotoObserver", "onError: " + e.getMessage()); - ToastUtil.show("网络连接失败"); - String jsonString = mCacheHelper.getAsString(UrlAddress.HOME_PHOTO); - getHomePhotoCache(jsonString, callback); - onComplete(); - } - - @Override - public void onComplete() { - Log.e("getHomePhotoObserver", "onComplete: "); - if (callback != null) { - callback.onComplete(); - } - } - }; + public Observable> getCheckUpdateObservable(String pkg) { + return mUiuiosRetrofit.create(CheckUpdateApi.class) + .checkUpdate(pkg) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); } } diff --git a/app/src/main/java/com/hainaos/vc/network/UrlAddress.java b/app/src/main/java/com/hainaos/vc/network/UrlAddress.java index 45fb048..079c191 100644 --- a/app/src/main/java/com/hainaos/vc/network/UrlAddress.java +++ b/app/src/main/java/com/hainaos/vc/network/UrlAddress.java @@ -2,17 +2,49 @@ package com.hainaos.vc.network; public class UrlAddress { /*主页接口*/ - public static final String ROOT_URL = "https://led.zuoyepad.com/android/"; + public static final String ROOT_URL = "https://hnapi.uisaas.cn/android/"; - /*获取家庭视频*/ - public static final String HOME_VIDEO ="File/getHomeVideo"; - /*获取家庭照片*/ - public static final String HOME_PHOTO ="File/getHomePhoto"; - /*获取家庭空间信息*/ - public static final String GET_HOME_SPACE_INFO ="File/getHomeSpaceInfo"; + /*手机号密码登录*/ + public static final String LOGIN = "login"; + /*手机号注册登录*/ + public static final String MOBILE_LOGIN = "login/mobile-login"; + /*获取验证码*/ + public static final String SEND_CODE = "common/send-code"; - /*获取设备激活支付信息*/ - public static final String ACTIVATION_INFO = "sn/act-info"; + /*1.检查用户是否注册*/ + public static final String CHECK_TEL = "login/check-tel"; + /*3.重置密码*/ + public static final String RESET_PASSWD = "login/reset-pswd"; + /*视频分类列表*/ + public static final String CATEGORY_LIST = "videos/category-list"; + /*视频列表*/ + public static final String VIDEO_LIST = "videos/video-list"; + /*点击下载后统计上报*/ + public static final String VIDEOS_DOWNLOAD = "videos/download"; + + + /*获取修改密码验证码*/ + public static final String GET_RESET_CODE = "user/get-reset-code"; + /*修改密码提交*/ + public static final String REST_PASSWD = "user/rest-pswd"; + /*用户信息*/ + public static final String USER_INFO = "user/info"; + /*获取设置密码验证码*/ + public static final String GET_SET_CODE = "user/get-set-code"; + /*设置密码提交*/ + public static final String SET_PSWD = "user/set-pswd"; + /*获取修改手机号验证码*/ + public static final String MODIFY_MOBILE_CODE = "user/get-modify-mobile-code"; + /*修改手机号提交*/ + public static final String MODIFY_MOBILE = "user/modify-mobile"; + + /*检查应用更新*/ + public static final String app_CHECK_UPDATE = "app/check-update"; + + + public static final String UIUIOS_ROOT_URL = "https://map.uiuios.com/android/"; + /*获取应用更新*/ + public static final String CHECK_UPDATE = "app/check-update"; } diff --git a/app/src/main/java/com/hainaos/vc/network/api/ActivationApi.java b/app/src/main/java/com/hainaos/vc/network/api/AppApi.java similarity index 52% rename from app/src/main/java/com/hainaos/vc/network/api/ActivationApi.java rename to app/src/main/java/com/hainaos/vc/network/api/AppApi.java index c2b74a4..bf1d753 100644 --- a/app/src/main/java/com/hainaos/vc/network/api/ActivationApi.java +++ b/app/src/main/java/com/hainaos/vc/network/api/AppApi.java @@ -1,6 +1,5 @@ package com.hainaos.vc.network.api; -import com.hainaos.vc.bean.ActivationInfo; import com.hainaos.vc.bean.BaseResponse; import com.hainaos.vc.network.UrlAddress; @@ -8,9 +7,9 @@ import io.reactivex.rxjava3.core.Observable; import retrofit2.http.GET; import retrofit2.http.Query; -public interface ActivationApi { - @GET(UrlAddress.ACTIVATION_INFO) - Observable> getActivation( - @Query("sn") String sn +public interface AppApi { + @GET(UrlAddress.app_CHECK_UPDATE) + Observable checkUpdate( + @Query("app_package") String app_package ); } diff --git a/app/src/main/java/com/hainaos/vc/network/api/FileApi.java b/app/src/main/java/com/hainaos/vc/network/api/FileApi.java deleted file mode 100644 index b54121d..0000000 --- a/app/src/main/java/com/hainaos/vc/network/api/FileApi.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.hainaos.vc.network.api; - -import com.hainaos.vc.bean.BaseResponse; -import com.hainaos.vc.bean.PhotoInfo; -import com.hainaos.vc.bean.SpaceInfo; -import com.hainaos.vc.bean.VideoInfo; -import com.hainaos.vc.network.UrlAddress; - -import java.util.ArrayList; -import java.util.List; - -import io.reactivex.rxjava3.core.Observable; -import retrofit2.http.GET; -import retrofit2.http.Query; - -public interface FileApi { - @GET(UrlAddress.HOME_VIDEO) - Observable>> getHomeVideo( - @Query("sn") String sn - ); - - @GET(UrlAddress.HOME_PHOTO) - Observable>> getHomePhoto( - @Query("sn") String sn - ); - - @GET(UrlAddress.GET_HOME_SPACE_INFO) - Observable> getHomeSpaceInfo( - @Query("sn") String sn - ); -} diff --git a/app/src/main/java/com/hainaos/vc/network/api/LoginApi.java b/app/src/main/java/com/hainaos/vc/network/api/LoginApi.java new file mode 100644 index 0000000..26970fe --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/network/api/LoginApi.java @@ -0,0 +1,53 @@ +package com.hainaos.vc.network.api; + +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.bean.LoginInfo; +import com.hainaos.vc.network.UrlAddress; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.Field; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Query; + +public interface LoginApi { + @FormUrlEncoded + @POST(UrlAddress.LOGIN) + Observable login( + @Field("sn") String sn, + @Field("mobile") String mobile, + @Field("password") String password + ); + + @FormUrlEncoded + @POST(UrlAddress.MOBILE_LOGIN) + Observable> mobileLogin( + @Field("sn") String sn, + @Field("mobile") String mobile, + @Field("captcha") String captcha, + @Field("verify_key") String verify_key + ); + + @FormUrlEncoded + @POST(UrlAddress.SEND_CODE) + Observable> sendCode( + @Field("mobile") String mobile + ); + + + @GET(UrlAddress.CHECK_TEL) + Observable checkTelNumber( + @Query("tel") String tel + ); + + @FormUrlEncoded + @POST(UrlAddress.RESET_PASSWD) + Observable resetPasswd( + @Field("mobile") String mobile, + @Field("password") String password, + @Field("captcha") String captcha, + @Field("verify_key") String verify_key + ); +} diff --git a/app/src/main/java/com/hainaos/vc/network/api/UserApi.java b/app/src/main/java/com/hainaos/vc/network/api/UserApi.java new file mode 100644 index 0000000..ea20646 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/network/api/UserApi.java @@ -0,0 +1,68 @@ +package com.hainaos.vc.network.api; + +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CodeInfo; +import com.hainaos.vc.bean.UserInfo; +import com.hainaos.vc.network.UrlAddress; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.Field; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.POST; +import retrofit2.http.Query; + +public interface UserApi { + + @GET(UrlAddress.USER_INFO) + Observable> getUserInfo( + @Header("Authorization") String token + ); + + @GET(UrlAddress.GET_RESET_CODE) + Observable> getResetCode( + @Header("Authorization") String token + ); + + @FormUrlEncoded + @POST(UrlAddress.REST_PASSWD) + Observable restPasswd( + @Header("Authorization") String token, + @Field("password") String password, + @Field("confirm_password") String confirm_password, + @Field("captcha") String captcha, + @Field("verify_key") String verify_key + ); + + @GET(UrlAddress.GET_SET_CODE) + Observable> getSetCode( + @Header("Authorization") String token + ); + + @FormUrlEncoded + @POST(UrlAddress.SET_PSWD) + Observable setPasswd( + @Header("Authorization") String token, + @Field("password") String password, + @Field("confirm_password") String confirm_password, + @Field("captcha") String captcha, + @Field("verify_key") String verify_key + ); + + @GET(UrlAddress.MODIFY_MOBILE_CODE) + Observable> getModifyMobileCode( + @Header("Authorization") String token, + @Query("mobile") String mobile + ); + + @FormUrlEncoded + @POST(UrlAddress.MODIFY_MOBILE) + Observable modifyMobileNumber( + @Header("Authorization") String token, + @Field("mobile") String mobile, + @Field("captcha") String captcha, + @Field("verify_key") String verify_key + ); + +} diff --git a/app/src/main/java/com/hainaos/vc/network/api/VideoApi.java b/app/src/main/java/com/hainaos/vc/network/api/VideoApi.java new file mode 100644 index 0000000..cea34e7 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/network/api/VideoApi.java @@ -0,0 +1,36 @@ +package com.hainaos.vc.network.api; + +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.CategoryInfo; +import com.hainaos.vc.bean.VideoListData; +import com.hainaos.vc.network.UrlAddress; + +import java.util.List; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.POST; +import retrofit2.http.Query; + +public interface VideoApi { + @GET(UrlAddress.CATEGORY_LIST) + Observable>> getCategoryList( + @Header("Authorization") String token + ); + + @GET(UrlAddress.VIDEO_LIST) + Observable> getVideoList( + @Header("Authorization") String token, + @Query("category_uuid") String category_uuid, + @Query("password") String password + ); + + @FormUrlEncoded + @POST(UrlAddress.VIDEOS_DOWNLOAD) + Observable sendDownloadStatu( + @Header("Authorization") String token, + @Query("uuid") String uuid + ); +} diff --git a/app/src/main/java/com/hainaos/vc/network/api/uiuios/CheckUpdateApi.java b/app/src/main/java/com/hainaos/vc/network/api/uiuios/CheckUpdateApi.java new file mode 100644 index 0000000..11a1d73 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/network/api/uiuios/CheckUpdateApi.java @@ -0,0 +1,16 @@ +package com.hainaos.vc.network.api.uiuios; + +import com.hainaos.vc.bean.BaseResponse; +import com.hainaos.vc.bean.uiuios.AppUpdateInfo; +import com.hainaos.vc.network.UrlAddress; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.GET; +import retrofit2.http.Query; + +public interface CheckUpdateApi { + @GET(UrlAddress.CHECK_UPDATE) + Observable> checkUpdate( + @Query("app_package") String app_package + ); +} diff --git a/app/src/main/java/com/hainaos/vc/receiver/InstallResultReceiver.java b/app/src/main/java/com/hainaos/vc/receiver/InstallResultReceiver.java new file mode 100644 index 0000000..9e1153f --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/receiver/InstallResultReceiver.java @@ -0,0 +1,56 @@ +package com.hainaos.vc.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInstaller; +import android.os.Build; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +public class InstallResultReceiver extends BroadcastReceiver { + private static final String TAG = "InstallResultReceiver"; + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public void onReceive(Context context, Intent intent) { + // an Intent broadcast. + //throw new UnsupportedOperationException("Not yet implemented"); + + + if (intent != null) { + final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_FAILURE); + if (status == PackageInstaller.STATUS_SUCCESS) { + // success + String PACKAGE_NAME = intent.getStringExtra("android.content.pm.extra.PACKAGE_NAME"); + + Log.e(TAG, "APP Install Success!"); + } else { + String msg = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE); + } + } +// String s = intent.getAction(); +// Log.e("fht", s); +// Bundle extras = intent.getExtras(); +// Set ks = extras.keySet(); +// Iterator iterator = ks.iterator(); +// while (iterator.hasNext()) { +// Log.d("KEY", iterator.next()); +// } + String STATUS = intent.getStringExtra(PackageInstaller.EXTRA_STATUS); + String PACKAGE_NAME = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME); + String SESSION_ID = intent.getStringExtra(PackageInstaller.EXTRA_SESSION_ID); + String STATUS_MESSAGE = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE); + String LEGACY_STATUS = intent.getStringExtra("android.content.pm.extra.LEGACY_STATUS"); +// Log.e("fht", STATUS); +// Log.e("fht", PACKAGE_NAME); +// Log.e("fht", SESSION_ID); +// Log.e("fht", LEGACY_STATUS); +// Log.e("fht", STATUS_MESSAGE); + if (STATUS_MESSAGE != null && "INSTALL_SUCCEEDED".equals(STATUS_MESSAGE)) { +// Toaster.show(PACKAGE_NAME + "安装成功"); + } + } +} diff --git a/app/src/main/java/com/hainaos/vc/service/DownloadService.java b/app/src/main/java/com/hainaos/vc/service/DownloadService.java new file mode 100644 index 0000000..ae41994 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/service/DownloadService.java @@ -0,0 +1,248 @@ +package com.hainaos.vc.service; + +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Build; +import android.os.IBinder; +import android.text.TextUtils; +import android.util.Log; + +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; +import androidx.core.content.FileProvider; + +import com.arialyy.annotations.Download; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.task.DownloadTask; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.hainaos.vc.R; +import com.hainaos.vc.bean.uiuios.AriaDownloadInfo; +import com.hainaos.vc.utils.ApkUtils; +import com.hjq.toast.Toaster; + +import java.io.File; +import java.lang.reflect.Type; + +public class DownloadService extends Service { + private static final String TAG = "DownloadService"; + + public DownloadService() { + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + Aria.download(this).register(); + + +// mNotificationManagerCompat = NotificationManagerCompat.from(this); +// createNotificationChannel(); +// createDownloadNotificationChannel(); +// sendSimpleNotification(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.e(TAG, "onStartCommand: " + intent); + return START_STICKY; + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + private static final String CHANNEL_ID = "CHANNEL_ID"; + private static final String CHANNEL_NAME = "系统通知"; + private static final String CHANNEL_DESCRIPTION = "海纳通知"; + + private static final String CHANNEL_DOWNLOAD_ID = "DOWNLOAD_CHANNEL"; + private static final String CHANNEL_DOWNLOAD_NAME = "下载管理"; + private static final String CHANNEL_DOWNLOAD_DESCRIPTION = "下载管理通知"; + + private void createNotificationChannel() { + // Create the NotificationChannel, but only on API 26+ because + // the NotificationChannel class is new and not in the support library + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT); + channel.setDescription(CHANNEL_DESCRIPTION); + // Register the channel with the system; you can't change the importance + // or other notification behaviors after this + NotificationManager notificationManager = getSystemService(NotificationManager.class); + notificationManager.createNotificationChannel(channel); + } + } + + private NotificationManagerCompat mNotificationManagerCompat; + private int NotificationID = 7890; + + private void sendSimpleNotification() { + Intent intent = new Intent(this, DownloadService.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.mipmap.ic_launcher) + .setContentTitle("海纳正在运行") +// .setContentText("测试内容") + .setAutoCancel(false) + .setShowWhen(false) + .setContentIntent(pendingIntent) + .setOngoing(true) + .setOnlyAlertOnce(true) + .setPriority(NotificationCompat.PRIORITY_MAX); + // notificationId is a unique int for each notification that you must define +// mNotificationManagerCompat.notify(NotificationID, builder.build()); + startForeground(NotificationID, builder.build()); + } + + private void createDownloadNotificationChannel() { + // Create the NotificationChannel, but only on API 26+ because + // the NotificationChannel class is new and not in the support library + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel(CHANNEL_DOWNLOAD_ID, CHANNEL_DOWNLOAD_NAME, NotificationManager.IMPORTANCE_DEFAULT); + channel.setDescription(CHANNEL_DOWNLOAD_DESCRIPTION); + // Register the channel with the system; you can't change the importance + // or other notification behaviors after this + NotificationManager notificationManager = getSystemService(NotificationManager.class); + notificationManager.createNotificationChannel(channel); + } + } + + private void sendDownloadRunning(AriaDownloadInfo ariaDownloadInfo, int progress) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_DOWNLOAD_ID) + .setSmallIcon(R.mipmap.ic_launcher) + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) + .setContentTitle(ariaDownloadInfo.getAppName()) + .setContentText("下载中:" + progress + "%") + .setAutoCancel(true) + .setShowWhen(true) + .setOngoing(false) + .setOnlyAlertOnce(true) + .setProgress(100, progress, false) + .setPriority(NotificationCompat.PRIORITY_HIGH); + // notificationId is a unique int for each notification that you must define + mNotificationManagerCompat.notify(ariaDownloadInfo.getAppId(), builder.build()); +// startForeground(ariaDownloadInfo.getAppId(), builder.build()); + } + + private void sendDownloadComplete(AriaDownloadInfo ariaDownloadInfo, String path) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_DOWNLOAD_ID) + .setSmallIcon(R.mipmap.ic_launcher) + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) + .setContentTitle(ariaDownloadInfo.getAppName()) + .setContentText("下载完成") + .setAutoCancel(true) + .setShowWhen(true) + .setOngoing(false) + .setOnlyAlertOnce(true) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setContentIntent(createIntent(path)); + // notificationId is a unique int for each notification that you must define + mNotificationManagerCompat.notify(ariaDownloadInfo.getAppId(), builder.build()); + } + + /** + * 设置通知点击事件 + * + * @return 点击事件 + */ + private PendingIntent createIntent(String path) { + File file = new File(path); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + //注意第二个参数,要保持和manifest中android:authorities的值相同 + Uri uri = FileProvider.getUriForFile(DownloadService.this, + getPackageName() + ".FileProvider", file); + intent.setDataAndType(uri, "application/vnd.android.package-archive"); + } else { + intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); + } + PendingIntent pendingIntent = PendingIntent.getActivity(DownloadService.this, 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + return pendingIntent; + } + + private void sendDownloadFail(AriaDownloadInfo ariaDownloadInfo) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_DOWNLOAD_ID) + .setSmallIcon(R.mipmap.ic_launcher) + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) + .setContentTitle(ariaDownloadInfo.getAppName()) + .setContentText("下载失败") + .setAutoCancel(true) + .setShowWhen(true) + .setOngoing(false) + .setOnlyAlertOnce(true) + .setPriority(NotificationCompat.PRIORITY_HIGH); + // notificationId is a unique int for each notification that you must define + mNotificationManagerCompat.notify(ariaDownloadInfo.getAppId(), builder.build()); + } + + @Download.onTaskRunning + void running(DownloadTask task) { + String jsonString = task.getExtendField(); + Log.e(TAG, "running: " + "正在下载:" + task.getPercent() + "% " + jsonString); + AriaDownloadInfo ariaDownloadInfo = getAriaDownloadInfo(jsonString); + if (ariaDownloadInfo != null) { + Toaster.show("正在下载: " + ariaDownloadInfo.getAppName() + "\t" + task.getPercent() + "%"); +// sendDownloadRunning(ariaDownloadInfo, task.getPercent()); + } + } + + @Download.onTaskComplete + void taskComplete(DownloadTask task) { + String path = task.getFilePath(); + Log.e(TAG, "taskComplete: " + path); + if (path.endsWith(".apk")) { + ApkUtils.installApp(DownloadService.this, task.getFilePath()); + String jsonString = task.getExtendField(); + Log.e(TAG, "taskComplete: " + "下载完成:" + jsonString); + AriaDownloadInfo ariaDownloadInfo = getAriaDownloadInfo(jsonString); + if (ariaDownloadInfo != null) { + Toaster.show("下载完成: " + "\t" + ariaDownloadInfo.getAppName()); +// sendDownloadComplete(ariaDownloadInfo, task.getFilePath()); + } + } + } + + @Download.onTaskFail + void taskFail(DownloadTask task, Exception e) { + Log.e(TAG, "taskFail: "); + String jsonString = task.getExtendField(); + Log.e(TAG, "taskFail: " + "下载失败:" + jsonString); + AriaDownloadInfo ariaDownloadInfo = getAriaDownloadInfo(jsonString); + if (ariaDownloadInfo != null) { + Toaster.show("下载失败: " + "\t" + ariaDownloadInfo.getAppName()); +// sendDownloadFail(ariaDownloadInfo); + } + } + + private AriaDownloadInfo getAriaDownloadInfo(String jsonString) { + if (!TextUtils.isEmpty(jsonString)) { + Gson gson = new Gson(); + Type type = new TypeToken() { + }.getType(); + AriaDownloadInfo ariaDownloadInfo = null; + try { + ariaDownloadInfo = gson.fromJson(jsonString, type); + } catch (Exception e) { + Log.e(TAG, "getAriaDownloadInfo: " + e.getMessage()); + } + return ariaDownloadInfo; + } else { + return null; + } + } +} diff --git a/app/src/main/java/com/hainaos/vc/utils/ApkUtils.java b/app/src/main/java/com/hainaos/vc/utils/ApkUtils.java new file mode 100644 index 0000000..f5464be --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/utils/ApkUtils.java @@ -0,0 +1,304 @@ +package com.hainaos.vc.utils; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageInstaller; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Build; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +import com.hainaos.vc.BuildConfig; +import com.hainaos.vc.bean.uiuios.AppUpdateInfo; +import com.hainaos.vc.receiver.InstallResultReceiver; +import com.hjq.toast.Toaster; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.List; + +public class ApkUtils { + + private static final String TAG = "ApkUtils"; + + public static boolean openPackage(Context context, String packageName) { + Context pkgContext = getPackageContext(context, packageName); + Intent intent = getAppOpenIntentByPackageName(context, packageName); + if (pkgContext != null && intent != null) { + pkgContext.startActivity(intent); + return true; + } + return false; + } + + public static boolean openPackage(Context context, String packageName, String className) { + if (TextUtils.isEmpty(className)) { + return openPackage(context, packageName); + } + ComponentName cn = new ComponentName(packageName, className); + Intent intent = new Intent(); + intent.setComponent(cn); + //Fix for Android 13 + if (Build.VERSION.SDK_INT < 33) { + intent.addCategory(Intent.CATEGORY_LAUNCHER); + } + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (context != null) { + try { + context.startActivity(intent); + } catch (Exception e) { + Log.e(TAG, "openPackage: " + e.getMessage()); + return false; + } + return true; + } + return false; + } + + public static Context getPackageContext(Context context, String packageName) { + Context pkgContext = null; + if (context.getPackageName().equals(packageName)) { + pkgContext = context; + } else { + // 创建第三方应用的上下文环境 + try { + pkgContext = context.createPackageContext(packageName, + Context.CONTEXT_IGNORE_SECURITY + | Context.CONTEXT_INCLUDE_CODE); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + return pkgContext; + } + + public static Intent getAppOpenIntentByPackageName(Context context, String packageName) { + //Activity完整名 + String mainAct = null; + //根据包名寻找 + PackageManager pkgMag = context.getPackageManager(); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK); + + List list = pkgMag.queryIntentActivities(intent, PackageManager.GET_ACTIVITIES); + for (int i = 0; i < list.size(); i++) { + ResolveInfo info = list.get(i); + if (info.activityInfo.packageName.equals(packageName)) { + mainAct = info.activityInfo.name; + break; + } + } + if (TextUtils.isEmpty(mainAct)) { + return null; + } + intent.setComponent(new ComponentName(packageName, mainAct)); + return intent; + } + + /** + * 通过路径安装APK,兼容Android 9以上 + * + * @param context 上下文 + * @param filePath apk文件路径 + */ + public static void installApp(Context context, String filePath) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + installAppatPie(context, filePath); + } else { + installApps(filePath); + } + } + + public static boolean installApps(String apkPath) { + Log.e(TAG, "installApps: 正在安装应用 " + apkPath); + Toaster.show("正在安装应用"); + Process process = null; + BufferedReader successResult = null; + BufferedReader errorResult = null; + StringBuilder successMsg = new StringBuilder(); + StringBuilder errorMsg = new StringBuilder(); + try { + process = new ProcessBuilder("pm", "install", "-i", BuildConfig.APPLICATION_ID, "--user", "0", apkPath).start(); + successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); + errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); + String s; + while ((s = successResult.readLine()) != null) { + successMsg.append(s); + } + while ((s = errorResult.readLine()) != null) { + errorMsg.append(s); + } + } catch (Exception e) { + + } finally { + try { + if (successResult != null) { + successResult.close(); + } + if (errorResult != null) { + errorResult.close(); + } + } catch (Exception e) { + + } + if (process != null) { + process.destroy(); + } + } + Log.e("result", "" + errorMsg.toString()); + //如果含有“success”认为安装成功 + Log.e("installApp", successMsg.toString()); +// if (!successMsg.toString().equalsIgnoreCase("success")) { +// ApkUtils.install(context, new File(apkPath)); +// } + return "success".equalsIgnoreCase(successMsg.toString()); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public static void installAppatPie(Context context, String apkFilePath) { + File file = new File(apkFilePath); + PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller(); + PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(PackageInstaller + .SessionParams.MODE_FULL_INSTALL); + sessionParams.setSize(file.length()); + int sessionId = createSession(packageInstaller, sessionParams); + if (sessionId != -1) { + boolean copySuccess = copyApkFile(packageInstaller, sessionId, apkFilePath); + if (copySuccess) { + install(packageInstaller, sessionId, context); + } + } + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private static boolean copyApkFile(PackageInstaller pi, int sessionId, String apkFilePath) { + boolean success = false; + File apkFile = new File(apkFilePath); + PackageInstaller.Session session = null; + try { + session = pi.openSession(sessionId); + OutputStream out = session.openWrite("app.apk", 0, apkFile.length()); + FileInputStream input = new FileInputStream(apkFile); + int read = 0; + byte[] buffer = new byte[65536]; +// while (read != -1) { +// read = input.read(buffer); +// out.write(buffer, 0, read); +// } + while (true) { + read = input.read(buffer); + if (read == -1) { + session.fsync(out); + success = true; + out.close(); + input.close(); + break; + } + out.write(buffer, 0, read); + } + } catch (IOException e) { + e.printStackTrace(); + Log.e("fht", "copyApkFile" + e.getMessage()); + } + return success; + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private static void install(PackageInstaller packageInstaller, int sessionId, Context context) { + try { + PackageInstaller.Session session = packageInstaller.openSession(sessionId); + Intent intent = new Intent(context, InstallResultReceiver.class); + PendingIntent pendingIntent = PendingIntent.getBroadcast( + context, + 1, intent, + PendingIntent.FLAG_UPDATE_CURRENT + ); + session.commit(pendingIntent.getIntentSender()); + } catch (IOException e) { + e.printStackTrace(); + Log.e(TAG, "install: " + e.getMessage()); + } + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private static int createSession(PackageInstaller packageInstaller, PackageInstaller.SessionParams sessionParams) { + int sessionId = -1; + try { + sessionId = packageInstaller.createSession(sessionParams); + } catch (IOException e) { + e.printStackTrace(); + } + return sessionId; + } + + public static boolean isUpdate(Context context, AppUpdateInfo appUpdateInfo) { + String packageName = appUpdateInfo.getApp().getApp_package(); + long versionCode = appUpdateInfo.getApp_version_code(); + return isUpdate(context, packageName, versionCode); + } + + public static boolean isUpdate(Context context, String packageName, long versionCode) { + PackageInfo packageInfo = null; + try { + packageInfo = context.getPackageManager().getPackageInfo(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + if (packageInfo == null) { + return true; + } else { + long appVersionCode; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + appVersionCode = packageInfo.getLongVersionCode(); + } else { + appVersionCode = packageInfo.versionCode; + } + if (appVersionCode < versionCode) { + return true; + } else { + Log.e(TAG, "checkUpdate: " + packageName + "\t已经是最新版"); + return false; + } + } + } + + public static void checkAppUpdate(Context context, AppUpdateInfo appUpdateInfo) { + String packageName = appUpdateInfo.getApp().getApp_package(); + long versionCode = appUpdateInfo.getApp_version_code(); + String url = appUpdateInfo.getApp_url(); + PackageInfo packageInfo = null; + try { + packageInfo = context.getPackageManager().getPackageInfo(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + if (packageInfo == null) { + FileUtils.ariaDownload(context, url, appUpdateInfo); + } else { + long appVersionCode; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + appVersionCode = packageInfo.getLongVersionCode(); + } else { + appVersionCode = packageInfo.versionCode; + } + if (appVersionCode < versionCode) { + FileUtils.ariaDownload(context, url, appUpdateInfo); + } else { + Log.e(TAG, "checkUpdate: " + packageName + "\t已经是最新版"); + } + } + } + + +} diff --git a/app/src/main/java/com/hainaos/vc/utils/FileUtils.java b/app/src/main/java/com/hainaos/vc/utils/FileUtils.java index 943ef36..5818017 100644 --- a/app/src/main/java/com/hainaos/vc/utils/FileUtils.java +++ b/app/src/main/java/com/hainaos/vc/utils/FileUtils.java @@ -1,8 +1,44 @@ package com.hainaos.vc.utils; +import android.content.Context; +import android.content.Intent; +import android.os.Environment; +import android.text.TextUtils; +import android.util.Log; + +import androidx.core.content.ContextCompat; + +import com.arialyy.aria.core.Aria; +import com.hainaos.vc.bean.uiuios.AppUpdateInfo; +import com.hainaos.vc.bean.uiuios.AriaDownloadInfo; +import com.hainaos.vc.gson.GsonUtils; +import com.hainaos.vc.service.DownloadService; + +import java.io.File; import java.text.DecimalFormat; public class FileUtils { + private static final String TAG = "FileUtils"; + + public static String getFileName(String path) { + if (TextUtils.isEmpty(path)) { + return ""; + } + int position = path.lastIndexOf(File.separator); + return path.substring(position + 1); + } + + public static String getFileNamefromURL(String url) { + int position = url.lastIndexOf("/"); + return url.substring(position + 1); + } + + public static String getFileNameWithoutExtension(String path) { + String name = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")); + Log.e("getFileName", "Name: " + name); + return name; + } + /** * 转换文件大小 MB */ @@ -22,4 +58,111 @@ public class FileUtils { } return fileSizeString; } + + public static String getCacheDir(Context context) { + String cachePath; + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) + || !Environment.isExternalStorageRemovable()) { + if (context.getExternalCacheDir() != null) { + cachePath = context.getExternalCacheDir().getPath(); + } else if (context.getExternalFilesDir("cache") != null) { + cachePath = context.getExternalFilesDir("cache").getPath(); + } else { + cachePath = context.getCacheDir().getPath(); + } + } else { + cachePath = context.getCacheDir().getPath(); + } + return cachePath; + } + + public static String getHainaVideoPath(Context context) { + String path = Environment.getExternalStorageDirectory() + File.separator + "haina"; + return path + File.separator; + } + + public static String getDownLoadPath(Context context) { + String path = ContextCompat.getExternalFilesDirs(context, Environment.DIRECTORY_DOWNLOADS)[0].getAbsolutePath(); + return path + File.separator; + } + + public static void ariaDownload(Context context, String dirName, String url, String md5) { + String downLoadPath = getHainaVideoPath(context) + dirName + File.separator; + File dirFile = new File(downLoadPath); + if (!dirFile.exists()) { + dirFile.mkdirs(); + } + String fileName = getFileNamefromURL(url); + File file = new File(downLoadPath + fileName); + if (file.exists() && !file.isDirectory()) { + String fileMD5 = com.blankj.utilcode.util.FileUtils.getFileMD5ToString(file); + Log.e("ariaDownload", "fileOnlineMD5=" + md5); + Log.e("ariaDownload", "fileMD5=" + fileMD5); + if (!TextUtils.isEmpty(md5)) { + if (!md5.equals(fileMD5)) { + Aria.download(context) + .load(url) //读取下载地址 + .setFilePath(file.getAbsolutePath()) +// .ignoreFilePathOccupy() + .setExtendField(url) + .create(); //启动下载} + } else { + Log.e("ariaDownload", "fileName = " + fileName + " exists"); + } + } else { + Log.e("ariaDownload", url + " no md5 params , skip"); + } + } else { + Aria.download(context) + .load(url) //读取下载地址 + .setFilePath(file.getAbsolutePath()) +// .ignoreFilePathOccupy() + .setExtendField(url) + .create(); //启动下载} + } + } + + public static void ariaDownload(Context context, String url, AppUpdateInfo appUpdateInfo) { + Log.e(TAG, "ariaDownload: " + appUpdateInfo); + AriaDownloadInfo ariaDownloadInfo = AriaDownloadInfo.toAriaDownloadInfo(appUpdateInfo); + ariaDownload(context, url, ariaDownloadInfo); + } + + public static void ariaDownload(Context context, String url, AriaDownloadInfo ariaDownloadInfo) { + Log.e(TAG, "ariaDownload: " + ariaDownloadInfo); + String fileName = getFileNamefromURL(url); + String app_md5 = ariaDownloadInfo.getAppMd5(); + Log.e("ariaDownload", "app_md5 = " + app_md5); + File file = new File(getDownLoadPath(context) + fileName); + if (file.exists() && !file.isDirectory()) { + String fileMd5 = com.blankj.utilcode.util.FileUtils.getFileMD5ToString(file); + Log.e("ariaDownload", "fileMD5 = " + fileMd5); + if (fileMd5.equalsIgnoreCase(app_md5)) { + ApkUtils.installApp(context, file.getAbsolutePath()); + } else { + file.delete(); + Aria.download(context) + .load(url) //读取下载地址 + .setFilePath(getDownLoadPath(context) + fileName) + .ignoreFilePathOccupy() + .setExtendField(GsonUtils.toJSONString(ariaDownloadInfo)) + .create(); //启动下载} + } + } else { + Aria.download(context) + .load(url) //读取下载地址 + .setFilePath(getDownLoadPath(context) + fileName) + .ignoreFilePathOccupy() + .setExtendField(GsonUtils.toJSONString(ariaDownloadInfo)) + .create(); //启动下载} + } + Intent intent = new Intent(context, DownloadService.class); +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { +// context.startForegroundService(intent); +// } else { + context.startService(intent); +// } + } + + } diff --git a/app/src/main/java/com/hainaos/vc/utils/GlideLoadUtils.java b/app/src/main/java/com/hainaos/vc/utils/GlideLoadUtils.java new file mode 100644 index 0000000..7cf2267 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/utils/GlideLoadUtils.java @@ -0,0 +1,144 @@ +package com.hainaos.vc.utils; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.Log; +import android.widget.ImageView; + +import androidx.fragment.app.Fragment; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.request.RequestOptions; + +import java.io.File; + +/** + * Glide 加载 简单判空封装 防止异步加载数据时调用Glide 抛出异常 + * Created by Li_Xavier on 2017/6/20 0020. + */ +public class GlideLoadUtils { + private String TAG = "ImageLoader"; + + /** + * 借助内部类 实现线程安全的单例模式 + * 属于懒汉式单例,因为Java机制规定,内部类SingletonHolder只有在getInstance() + * 方法第一次调用的时候才会被加载(实现了lazy),而且其加载过程是线程安全的。 + * 内部类加载的时候实例化一次instance。 + */ + public GlideLoadUtils() { + } + + private static class GlideLoadUtilsHolder { + private final static GlideLoadUtils INSTANCE = new GlideLoadUtils(); + } + + public static GlideLoadUtils getInstance() { + return GlideLoadUtilsHolder.INSTANCE; + } + + /** + * Glide 加载 简单判空封装 防止异步加载数据时调用Glide 抛出异常 + * + * @param context + * @param url 加载图片的url地址 String + * @param imageView 加载图片的ImageView 控件 + * @param defaultImage 图片展示错误的本地图片 id + */ + public void glideLoad(Context context, String url, ImageView imageView, int defaultImage) { + if (context != null) { + Glide.with(context).load(url).centerCrop().error(defaultImage).placeholder(imageView.getDrawable()).dontAnimate().into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + public void glideLoadRound(Context context, String url, ImageView imageView, int defaultImage) { + if (context != null) { + Glide.with(context).load(url).centerCrop().error(defaultImage) + .placeholder(imageView.getDrawable()).dontAnimate() + .apply(RequestOptions.bitmapTransform(new RoundedCorners(ScreenUtils.dp2px(context.getResources(), 16f)))) + .into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + + public void glideLoad(Context context, int resId, ImageView imageView, int defaultImage) { + if (context != null) { + Glide.with(context).load(resId).centerCrop().placeholder(imageView.getDrawable()).error(defaultImage).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + public void glideLoad(Context context, String url, ImageView imageView) { + if (context != null) { + Glide.with(context).load(url).centerCrop().dontAnimate().placeholder(imageView.getDrawable()).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + public void glideLoad(Context context, Bitmap bitmap, ImageView imageView) { + if (context != null) { + Glide.with(context).load(bitmap).centerCrop().dontAnimate().placeholder(imageView.getDrawable()).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + public void glideLoad(Context context, Drawable drawable, ImageView imageView) { + if (context != null) { + Glide.with(context).load(drawable).centerCrop().dontAnimate().placeholder(imageView.getDrawable()).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + public void glideLoad(Context context, File file, ImageView imageView) { + if (context != null) { + Glide.with(context).load(file).centerCrop().into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + public void glideLoad(Context context, File file, ImageView imageView, int defaultRes) { + if (context != null) { + Glide.with(context).load(file).centerCrop().error(defaultRes).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,context is null"); + } + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + public void glideLoad(Activity activity, String url, ImageView imageView, int default_image) { + if (!activity.isDestroyed()) { + Glide.with(activity).load(url).centerCrop().error(default_image).placeholder(imageView.getDrawable()).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,activity is Destroyed"); + } + } + + public void glideLoad(Fragment fragment, String url, ImageView imageView, int default_image) { + if (fragment != null && fragment.getActivity() != null) { + Glide.with(fragment).load(url).centerCrop().error(default_image).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,fragment is null"); + } + } + + public void glideLoad(android.app.Fragment fragment, String url, ImageView imageView, int default_image) { + if (fragment != null && fragment.getActivity() != null) { + Glide.with(fragment).load(url).centerCrop().error(default_image).into(imageView); + } else { + Log.i(TAG, "Picture loading failed,android.app.Fragment is null"); + } + } +} diff --git a/app/src/main/java/com/hainaos/vc/utils/JgyUtils.java b/app/src/main/java/com/hainaos/vc/utils/JgyUtils.java index c03de21..090132f 100644 --- a/app/src/main/java/com/hainaos/vc/utils/JgyUtils.java +++ b/app/src/main/java/com/hainaos/vc/utils/JgyUtils.java @@ -61,7 +61,7 @@ public class JgyUtils { if (TextUtils.isEmpty(url)) return false; if (VideoUtils.isUrl(url)) { - String fileName = VideoUtils.getFileNamefromURL(url); + String fileName = FileUtils.getFileNamefromURL(url); if (TextUtils.isEmpty(fileName)) return false; File file = new File(getDownLoadPath() + fileName); @@ -73,13 +73,13 @@ public class JgyUtils { } public String getUrlLocalPath(String url) { - String fileName = VideoUtils.getFileNamefromURL(url); + String fileName = FileUtils.getFileNamefromURL(url); return getDownLoadPath() + fileName; } public void ariaDownload(String url, JsonObject jsonObject) { - String fileName = VideoUtils.getFileNamefromURL(url); + String fileName = FileUtils.getFileNamefromURL(url); String urlMd5 = ""; if (jsonObject.get("MD5") != null) { urlMd5 = jsonObject.get("MD5").getAsString(); diff --git a/app/src/main/java/com/hainaos/vc/utils/LoginUtils.java b/app/src/main/java/com/hainaos/vc/utils/LoginUtils.java new file mode 100644 index 0000000..36c4926 --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/utils/LoginUtils.java @@ -0,0 +1,110 @@ +package com.hainaos.vc.utils; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.Log; + +import com.hainaos.vc.bean.LoginInfo; +import com.hainaos.vc.bean.LoginUserInfo; +import com.hainaos.vc.bean.UserInfo; +import com.hainaos.vc.config.CommonConfig; +import com.tencent.mmkv.MMKV; + +public class LoginUtils { + private static final String TAG = "LoginUtils"; + + private static final String USER_ID_KEY = "user_id"; + private static final String USER_MOBILE_KEY = "user_mobile"; + private static final String USER_NICKNAME_KEY = "user_nickname"; + private static final String USER_VIP_LEVEL_KEY = "user_vip_level"; + private static final String USER_EXPIRE_AT_KEY = "user_expire_at"; + + private static final String USER_TOKEN_KEY = "user_token"; + + private static final String USER_LOGIN_STATU_KEY = "user_token"; + + @SuppressLint("StaticFieldLeak") + private static LoginUtils sInstance; + private Context mContext; + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + + private LoginUtils(Context context) { + if (context == null) { + throw new RuntimeException("Context is NULL"); + } + this.mContext = context; + + } + + public static void init(Context context) { + if (sInstance == null) { + Log.e(TAG, "init: "); + sInstance = new LoginUtils(context); + } + } + + public static LoginUtils getInstance() { + if (sInstance == null) { + throw new IllegalStateException("You must be init LoginUtils first"); + } + return sInstance; + } + + public void setLoginInfo(LoginInfo loginInfo) { + if (loginInfo == null) { + return; + } + mMMKV.encode(USER_TOKEN_KEY, loginInfo.getToken()); + + LoginUserInfo loginUserInfo = loginInfo.getUser_info(); + mMMKV.encode(USER_ID_KEY, loginUserInfo.getId()); + mMMKV.encode(USER_MOBILE_KEY, loginUserInfo.getMobile()); + mMMKV.encode(USER_NICKNAME_KEY, loginUserInfo.getNickname()); + mMMKV.encode(USER_VIP_LEVEL_KEY, loginUserInfo.getVip_level()); + mMMKV.encode(USER_EXPIRE_AT_KEY, loginUserInfo.getExpire_at()); + + mMMKV.encode(USER_LOGIN_STATU_KEY, true); + } + + public void clearLoginInfo() { + mMMKV.remove(USER_TOKEN_KEY); + mMMKV.remove(USER_ID_KEY); + mMMKV.remove(USER_MOBILE_KEY); + mMMKV.remove(USER_NICKNAME_KEY); + mMMKV.remove(USER_VIP_LEVEL_KEY); + mMMKV.remove(USER_EXPIRE_AT_KEY); + + mMMKV.encode(USER_LOGIN_STATU_KEY, false); + + } + + public void updateUserInfo(UserInfo userInfo) { + mMMKV.encode(USER_MOBILE_KEY, userInfo.getMobile()); + mMMKV.encode(USER_NICKNAME_KEY, userInfo.getNickname()); + } + + public boolean isLogged() { + boolean logged = mMMKV.decodeBool(USER_LOGIN_STATU_KEY, false); + return logged; + } + + public String getToken() { + String token = mMMKV.decodeString(USER_TOKEN_KEY, ""); + return token; + } + + public String getBearerToken() { + String token = mMMKV.decodeString(USER_TOKEN_KEY, ""); + return "Bearer " + token; + } + + public String getName() { + String name = mMMKV.decodeString(USER_NICKNAME_KEY, ""); + return name; + } + + public String getPhoneNumber() { + String phone = mMMKV.decodeString(USER_MOBILE_KEY, ""); + return phone; + } +} diff --git a/app/src/main/java/com/hainaos/vc/utils/TimeUtils.java b/app/src/main/java/com/hainaos/vc/utils/TimeUtils.java index f973d5c..5b89582 100644 --- a/app/src/main/java/com/hainaos/vc/utils/TimeUtils.java +++ b/app/src/main/java/com/hainaos/vc/utils/TimeUtils.java @@ -1,5 +1,8 @@ package com.hainaos.vc.utils; +import java.text.SimpleDateFormat; +import java.util.Date; + public class TimeUtils { public static String TimeFormat(long millisecond) { @@ -21,4 +24,9 @@ public class TimeUtils { } } + public static String transferSecondToDate(long second) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date date = new Date(second * 1000); + return sdf.format(date); + } } diff --git a/app/src/main/java/com/hainaos/vc/utils/Utils.java b/app/src/main/java/com/hainaos/vc/utils/Utils.java index 90906a8..b217664 100644 --- a/app/src/main/java/com/hainaos/vc/utils/Utils.java +++ b/app/src/main/java/com/hainaos/vc/utils/Utils.java @@ -1,15 +1,23 @@ package com.hainaos.vc.utils; import android.annotation.SuppressLint; +import android.content.Context; import android.os.Build; +import android.os.StatFs; +import android.text.format.Formatter; import android.util.Log; +import com.hainaos.vc.BuildConfig; + import java.lang.reflect.Method; public class Utils { @SuppressLint({"MissingPermission", "HardwareIds"}) public static String getSerial() { + if (BuildConfig.DEBUG) { + return "T98005H1024GB32GB"; + } String serial = "unknow"; try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {//9.0+ @@ -27,4 +35,19 @@ public class Utils { } return serial; } + + public static String getDataTotalSize(Context context) { + StatFs sf = new StatFs(context.getCacheDir().getAbsolutePath()); + long blockSize = sf.getBlockSize(); + long totalBlocks = sf.getBlockCount(); + return Formatter.formatFileSize(context, blockSize * totalBlocks); + } + + public static String getRemnantSize(Context context) { + StatFs sf = new StatFs(context.getCacheDir().getAbsolutePath()); + long availableSize = sf.getAvailableBytes(); + return Formatter.formatFileSize(context, availableSize); + } + + } diff --git a/app/src/main/java/com/hainaos/vc/utils/VideoUtils.java b/app/src/main/java/com/hainaos/vc/utils/VideoUtils.java index 79eaab6..5cec218 100644 --- a/app/src/main/java/com/hainaos/vc/utils/VideoUtils.java +++ b/app/src/main/java/com/hainaos/vc/utils/VideoUtils.java @@ -1,7 +1,5 @@ package com.hainaos.vc.utils; -import android.util.Log; - import java.io.File; import java.io.FileInputStream; import java.math.BigInteger; @@ -10,16 +8,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class VideoUtils { - public static String getFileNamefromURL(String url) { - int position = url.lastIndexOf("/"); - return url.substring(position + 1); - } - public static String getFileNameWithoutExtension(String path) { - String name = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")); - Log.e("getFileName", "Name: " + name); - return name; - } public static boolean isUrl(String str) { String pattern = "(http|https|ftp)://((((25[0-5])|(2[0-4]\\d)|(1\\d{2})|([1-9]?\\d)\\.){3}((25[0-5])|(2[0-4]\\d)|(1\\d{2})|([1-9]?\\d)))|(([\\w-]+\\.)+(net|com|org|gov|edu|mil|info|travel|pro|museum|biz|[a-z]{2})))(/[\\w\\-~#]+)*(/[\\w-]+\\.[\\w]{2,4})?([\\?=&%_]?[\\w-]+)*"; diff --git a/app/src/main/java/com/hainaos/vc/view/ImageViewAdapter.java b/app/src/main/java/com/hainaos/vc/view/ImageViewAdapter.java new file mode 100644 index 0000000..859ac5f --- /dev/null +++ b/app/src/main/java/com/hainaos/vc/view/ImageViewAdapter.java @@ -0,0 +1,69 @@ +package com.hainaos.vc.view; + +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.databinding.BindingAdapter; + +import com.bumptech.glide.Glide; +import com.hainaos.vc.R; +import com.hainaos.vc.utils.TimeUtils; + +public class ImageViewAdapter { + @BindingAdapter("android:src") + public static void setSrc(ImageView view, Bitmap bitmap) { + view.setImageBitmap(bitmap); + } + + @BindingAdapter("android:src") + public static void setSrc(ImageView view, int resId) { + view.setImageResource(resId); + } + + @BindingAdapter("imageUrl") + public static void setSrc(ImageView imageView, String url) { + Glide.with(imageView.getContext()) + .load(url) + .error(R.mipmap.ic_launcher) + .centerCrop() + .into(imageView); + } + + /** + * 自定义设置图片属性 - 在匹配时自定义命名空间会被忽略 + */ + @BindingAdapter({"imageUrl", "error"}) + public static void loadImage(ImageView imageView, String url, Drawable error) { + Glide.with(imageView.getContext()) + .load(url) + .error(error) + .into(imageView); + } + + @BindingAdapter({"imageAvatarUrl", "error"}) + public static void loadAvatarImage(ImageView imageView, String url, Drawable error) { + Glide.with(imageView.getContext()) + .load(url) + .error(error) + .placeholder(imageView.getDrawable()) + .into(imageView); + } + + @BindingAdapter({"setTime"}) + public static void setTime(TextView textView, long timestamp) { + textView.setText(TimeUtils.transferSecondToDate(timestamp)); + } + + @BindingAdapter({"setTemp"}) + public static void setTemp(TextView textView, String temp) { + if (TextUtils.isEmpty(temp)) { + textView.setText("N/A"); + } else { + textView.setText(temp + " ℃"); + } + } + +} \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/haina_logo.png b/app/src/main/res/drawable-hdpi/haina_logo.png new file mode 100644 index 0000000..d3a284d Binary files /dev/null and b/app/src/main/res/drawable-hdpi/haina_logo.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_category.png b/app/src/main/res/drawable-hdpi/icon_category.png new file mode 100644 index 0000000..00860ca Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_category.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_download.png b/app/src/main/res/drawable-hdpi/icon_download.png new file mode 100644 index 0000000..f97e22e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_download.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_user_center.png b/app/src/main/res/drawable-hdpi/icon_user_center.png new file mode 100644 index 0000000..3504f34 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_user_center.png differ diff --git a/app/src/main/res/drawable-hdpi/main_background.png b/app/src/main/res/drawable-hdpi/main_background.png new file mode 100644 index 0000000..5833864 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/main_background.png differ diff --git a/app/src/main/res/drawable/alarm_pressed_background.xml b/app/src/main/res/drawable/alarm_pressed_background.xml deleted file mode 100644 index 0883976..0000000 --- a/app/src/main/res/drawable/alarm_pressed_background.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_item_user_info.xml b/app/src/main/res/drawable/bg_item_user_info.xml new file mode 100644 index 0000000..48f6318 --- /dev/null +++ b/app/src/main/res/drawable/bg_item_user_info.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_login_button.xml b/app/src/main/res/drawable/bg_login_button.xml index 90d8e31..09feb70 100644 --- a/app/src/main/res/drawable/bg_login_button.xml +++ b/app/src/main/res/drawable/bg_login_button.xml @@ -2,7 +2,7 @@ - + diff --git a/app/src/main/res/drawable/edit_text_login_bg.xml b/app/src/main/res/drawable/edit_text_login_bg.xml new file mode 100644 index 0000000..81fd882 --- /dev/null +++ b/app/src/main/res/drawable/edit_text_login_bg.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_more.xml b/app/src/main/res/drawable/ic_more.xml new file mode 100644 index 0000000..248bb07 --- /dev/null +++ b/app/src/main/res/drawable/ic_more.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_category_list.xml b/app/src/main/res/layout/activity_category_list.xml new file mode 100644 index 0000000..5e6d47b --- /dev/null +++ b/app/src/main/res/layout/activity_category_list.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_category.xml b/app/src/main/res/layout/activity_category_local.xml similarity index 63% rename from app/src/main/res/layout/activity_category.xml rename to app/src/main/res/layout/activity_category_local.xml index db8c15e..7dc3b27 100644 --- a/app/src/main/res/layout/activity_category.xml +++ b/app/src/main/res/layout/activity_category_local.xml @@ -2,13 +2,13 @@ + tools:context=".activity.category.local.LocalCategoryActivity"> + type="com.hainaos.vc.activity.category.local.LocalCategoryActivity.BtnClick" /> - + android:layout_height="match_parent"> + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_category_video.xml b/app/src/main/res/layout/activity_category_video.xml new file mode 100644 index 0000000..441d2b6 --- /dev/null +++ b/app/src/main/res/layout/activity_category_video.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 9d863bb..e54f476 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -48,7 +48,7 @@ + + + + + + + android:textSize="16sp" /> diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 135ec9f..760a1de 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -14,639 +14,41 @@ - + + + + + + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="0dp" + android:overScrollMode="never" + android:layout_marginTop="32dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@+id/imageView" /> diff --git a/app/src/main/res/layout/activity_modify_mobile.xml b/app/src/main/res/layout/activity_modify_mobile.xml new file mode 100644 index 0000000..e984096 --- /dev/null +++ b/app/src/main/res/layout/activity_modify_mobile.xml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_passwd.xml b/app/src/main/res/layout/activity_passwd.xml new file mode 100644 index 0000000..0fa19cf --- /dev/null +++ b/app/src/main/res/layout/activity_passwd.xml @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_passwd_lock.xml b/app/src/main/res/layout/activity_passwd_lock.xml new file mode 100644 index 0000000..f5b7ad8 --- /dev/null +++ b/app/src/main/res/layout/activity_passwd_lock.xml @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_user.xml b/app/src/main/res/layout/activity_user.xml new file mode 100644 index 0000000..9995fde --- /dev/null +++ b/app/src/main/res/layout/activity_user.xml @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_video_preview.xml b/app/src/main/res/layout/activity_video_preview.xml new file mode 100644 index 0000000..21b8fa7 --- /dev/null +++ b/app/src/main/res/layout/activity_video_preview.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_app.xml b/app/src/main/res/layout/fragment_app.xml new file mode 100644 index 0000000..d90e684 --- /dev/null +++ b/app/src/main/res/layout/fragment_app.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_category.xml b/app/src/main/res/layout/fragment_category.xml new file mode 100644 index 0000000..c32bade --- /dev/null +++ b/app/src/main/res/layout/fragment_category.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_dialog_passwd.xml b/app/src/main/res/layout/fragment_dialog_passwd.xml new file mode 100644 index 0000000..c861902 --- /dev/null +++ b/app/src/main/res/layout/fragment_dialog_passwd.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_app.xml b/app/src/main/res/layout/item_app.xml new file mode 100644 index 0000000..71c35df --- /dev/null +++ b/app/src/main/res/layout/item_app.xml @@ -0,0 +1,46 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_category.xml b/app/src/main/res/layout/item_category.xml new file mode 100644 index 0000000..8d3115e --- /dev/null +++ b/app/src/main/res/layout/item_category.xml @@ -0,0 +1,46 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_category_video.xml b/app/src/main/res/layout/item_category_video.xml new file mode 100644 index 0000000..809e120 --- /dev/null +++ b/app/src/main/res/layout/item_category_video.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_tiktok.xml b/app/src/main/res/layout/item_tiktok.xml index 9a85293..b5a1252 100644 --- a/app/src/main/res/layout/item_tiktok.xml +++ b/app/src/main/res/layout/item_tiktok.xml @@ -16,7 +16,7 @@ android:adjustViewBounds="true" android:scaleType="centerInside" /> - diff --git a/app/src/main/res/layout/item_video_file.xml b/app/src/main/res/layout/item_video_file.xml index 481c1b7..c3f4cab 100644 --- a/app/src/main/res/layout/item_video_file.xml +++ b/app/src/main/res/layout/item_video_file.xml @@ -1,6 +1,7 @@ + + - + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index 2b9b6ee..83f2334 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index 2b9b6ee..83f2334 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 2b9b6ee..83f2334 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 2b9b6ee..83f2334 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 2b9b6ee..83f2334 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 3e2f669..68ecf61 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -7,4 +7,11 @@ 16sp 12dp 4dp + + 16sp + 15sp + 40dp + 12dp + 16dp + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ab59e37..5118e19 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - 海纳美业学习机 + 海纳 正在下载%s