diff --git a/JZVideo/src/main/res/drawable-xhdpi/icon_play.png b/JZVideo/src/main/res/drawable-xhdpi/icon_play.png new file mode 100644 index 0000000..a4d33c3 Binary files /dev/null and b/JZVideo/src/main/res/drawable-xhdpi/icon_play.png differ diff --git a/JZVideo/src/main/res/layout/jz_layout_std.xml b/JZVideo/src/main/res/layout/jz_layout_std.xml index 3bfbd9a..38f4925 100644 --- a/JZVideo/src/main/res/layout/jz_layout_std.xml +++ b/JZVideo/src/main/res/layout/jz_layout_std.xml @@ -196,7 +196,7 @@ android:id="@+id/start" android:layout_width="@dimen/jz_start_button_w_h_normal" android:layout_height="@dimen/jz_start_button_w_h_normal" - android:src="@drawable/jz_click_play_selector" /> + android:src="@drawable/icon_play" /> diff --git a/app/build.gradle b/app/build.gradle index 2d488d8..0cafef6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,15 +16,16 @@ android { applicationId "com.uiui.videoplayer" minSdkVersion 24 targetSdkVersion 28 - versionCode 106 - versionName "1.0.5" + versionCode 107 + versionName "1.0.6" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true ndk { // add support lib - abiFilters /*"armeabi",*/ "armeabi-v7a", "arm64-v8a", "x86"/*, "x86_64", "mips", "mips64"*/ + abiFilters /*"armeabi",*/ "armeabi-v7a", "arm64-v8a", "x86" +/*, "x86_64", "mips", "mips64"*/ } lintOptions { @@ -158,6 +159,8 @@ dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10' // implementation 'com.github.SheHuan:NiceImageView:1.0.5' - + //指示器 + implementation 'com.github.hackware1993:MagicIndicator:1.7.0' // for androidx + implementation 'com.github.Othershe:CombineBitmap:1.0.5' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 69b8637..e3d6d76 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,21 +12,30 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> + + + + - - - - - - - - paths = new ArrayList<>(); - private RecycleGridLayoutManager mManager; - - - @Override - public void initView() { - ButterKnife.bind(this); - mPresenter = new MainAPresenter(this); - mPresenter.setLifecycle(lifecycleSubject); - mPresenter.attachView(this); - - Aria.download(this).register(); - - checkSelfPermission(); - - initActionBar(); - tips = findViewById(R.id.tips); - tv_scan = findViewById(R.id.tv_scan); - refreshLayout = findViewById(R.id.swipeRefreshLayout); - refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - mPresenter.getHomeVideo(); - } - }); - refreshLayout.setRefreshing(true); - recyclerView = findViewById(R.id.recyclerView); - ((SimpleItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false); - int orientation = getResources().getConfiguration().orientation; - if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - mManager = new RecycleGridLayoutManager(MainActivity.this, 3); - } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { - mManager = new RecycleGridLayoutManager(MainActivity.this, 2); - } - recyclerView.setLayoutManager(mManager); - recyclerView.setNestedScrollingEnabled(false); - recyclerView.addItemDecoration(new SpacesItemDecoration(getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x), - getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x))); - ((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false); - adapter = new VideoAdapter(MainActivity.this); - adapter.setOnLongClickListener(new VideoAdapter.onItemLongClickListener() { - @Override - public void onItemLongClick(String path, int position) { - showDialog(path, position); - } - }); - recyclerView.setAdapter(adapter); - } - - @Override - public void initData() { - mPresenter.getHomeVideo(); - } @Override public int getLayoutId() { @@ -128,204 +87,41 @@ public class MainActivity extends BaseLightActivity implements MainAContact.Main } @Override - protected void onResume() { - super.onResume(); + public void initView() { +// getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); +// //注意要清除 FLAG_TRANSLUCENT_STATUS flag +// getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); +// getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark)); + ButterKnife.bind(this); + cl_pic.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(MainActivity.this, GalleryActivity.class)); + } + }); + vl_video.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(MainActivity.this, VideoActivity.class)); + } + }); + iv_back.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); } @Override - public void onConfigurationChanged(@NonNull Configuration newConfig) { - super.onConfigurationChanged(newConfig); - Configuration config = getResources().getConfiguration(); - if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) { - mManager = new RecycleGridLayoutManager(MainActivity.this, 2); - recyclerView.setLayoutManager(mManager); - } - if (config.orientation == Configuration.ORIENTATION_PORTRAIT) { - mManager = new RecycleGridLayoutManager(MainActivity.this, 3); - recyclerView.setLayoutManager(mManager); - } + public void initData() { + } - private void showDialog(String path, int position) { - CustomDialog dialog = new CustomDialog(MainActivity.this); - dialog.setTitle("删除文件") - .setMessage("确定要删除文件 " + VideoUtils.getFileNameWithoutExtension(path) + "吗") - .setPositive("确定") - .setNegtive("取消") - .setOnClickBottomListener(new CustomDialog.OnClickBottomListener() { - @Override - public void onPositiveClick() { - dialog.dismiss(); - File file = new File(path); - if (file.delete()) { - adapter.removeItem(position); - ToastUtil.show("删除成功"); - } else { - ToastUtil.show("删除失败,检查权限是否开启"); - } - } - - @Override - public void onNegtiveClick() { - dialog.dismiss(); - } - }); - dialog.show(); - } - - - private void initActionBar() { - setToolbarCustomTheme(); - //显示返回按钮 - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setHomeButtonEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(true); - SpannableString spannableString = new SpannableString(getString(R.string.app_name)); - ForegroundColorSpan colorSpan = new ForegroundColorSpan(getResources().getColor(R.color.defaultColor)); - spannableString.setSpan(colorSpan, 0, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - actionBar.setTitle(spannableString); - } - getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); - } - - //自定义颜色返回按钮 - protected void setToolbarCustomTheme() { - Drawable upArrow = ContextCompat.getDrawable(this, R.drawable.abc_ic_ab_back_material); - if (upArrow != null) { - upArrow.setColorFilter(ContextCompat.getColor(this, R.color.defaultColor), PorterDuff.Mode.SRC_ATOP); - if (getSupportActionBar() != null) { - getSupportActionBar().setHomeAsUpIndicator(upArrow); - } - } - } - - public void traverseFolder(String path) { - int fileNum = 0, folderNum = 0; - File file = new File(path); - if (file.exists()) { - LinkedList list = new LinkedList(); - File[] files = file.listFiles(); - for (File file2 : files) { - if (file2.isDirectory()) { - Log.e("traverseFolder1", "文件夹:" + file2.getAbsolutePath()); - list.add(file2); - folderNum++; - } else { - Log.e("traverseFolder1", "文件:" + file2.getAbsolutePath()); - fileNum++; - } - } - File temp_file; - while (!list.isEmpty()) { - temp_file = list.removeFirst(); - files = temp_file.listFiles(); - for (File file2 : files) { - if (file2.isDirectory()) { - Log.e("traverseFolder2", "文件夹:" + file2.getAbsolutePath()); - list.add(file2); - folderNum++; - } else { - Log.e("traverseFolder2", "文件:" + file2.getAbsolutePath()); - fileNum++; - } - } - } - } else { - Log.e("traverseFolder1", "文件不存在!"); - } - Log.e("traverseFolder1", "文件夹共有:" + folderNum + ",文件共有:" + fileNum); - } - - - public class ScanTask extends AsyncTask> { - - @Override - protected List doInBackground(Void... voids) { - long s1 = System.currentTimeMillis(); - paths.clear(); - 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) return null; - for (File file2 : files) { - publishProgress(file2.getAbsolutePath()); - 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) { - publishProgress(file2.getAbsolutePath()); - if (file2.isDirectory()) { - list.add(file2); - } else { - if (VideoUtils.isVideoFormat(file2.getAbsolutePath())) { - fileList.add(file2.getAbsolutePath()); - } - } - } - } - } else { - Log.e("traverseFolder1", "文件不存在!"); - } - Log.e("ScanTask", "doInBackground: " + "Scan time = " + (System.currentTimeMillis() - s1) + "ms"); - return fileList; - } - - @Override - protected void onProgressUpdate(String... values) { - super.onProgressUpdate(values); - paths.add(values[0]); - tv_scan.setVisibility(View.VISIBLE); - tv_scan.setText("正在扫描:" + values[0]); -// adapter.setData(paths); - } - - @Override - protected void onPostExecute(List strings) { - super.onPostExecute(strings); - Log.e("ScanTask", "onPostExecute: " + strings.size()); - if (strings.size() == 0) { - tips.setVisibility(View.VISIBLE); - recyclerView.setVisibility(View.GONE); - } else { - tips.setVisibility(View.GONE); - recyclerView.setVisibility(View.VISIBLE); -// adapter.setData(strings); - } - tv_scan.setVisibility(View.GONE); - refreshLayout.setRefreshing(false); - } - } - - private void checkSelfPermission() { - List mPermissionList = new ArrayList<>(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - for (String s : permissions) { - if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { - mPermissionList.add(s); - } else { -// mPresenter.getHomeVideo(); - } - } - if (mPermissionList.size() > 0) {//有权限没有通过,需要申请 - ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_CODE); - } - } + @Override + protected void onResume() { + super.onResume(); + checkSelfPermission(); } @Override @@ -333,7 +129,8 @@ public class MainActivity extends BaseLightActivity implements MainAContact.Main super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSION_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - mPresenter.getHomeVideo(); + Log.e("TAG", "onRequestPermissionsResult: "); + getThumbnail(); } else if (grantResults[0] == PackageManager.PERMISSION_DENIED) { if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)) { ToastUtil.show("需要存储空间权限才能正常使用软件"); @@ -345,151 +142,187 @@ public class MainActivity extends BaseLightActivity implements MainAContact.Main intent.setData(Uri.parse("package:" + this.getPackageName())); startActivity(intent); } - refreshLayout.setRefreshing(false); + } } } - private MenuItem refresh, single_loop, loop; - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.main, menu); - refresh = menu.findItem(R.id.refresh); - single_loop = menu.findItem(R.id.single_loop); - loop = menu.findItem(R.id.loop); - updateMenuIcon(); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - //返回按钮点击事件 - switch (item.getItemId()) { - case R.id.setting: - - break; - case android.R.id.home: - if (System.currentTimeMillis() - mPreClickTime > 1000) { - ToastUtil.show("再按一次,退出"); - mPreClickTime = System.currentTimeMillis(); + private void checkSelfPermission() { + List mPermissionList = new ArrayList<>(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + for (String s : permissions) { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { + mPermissionList.add(s); } else { - finish(); + Log.e("TAG", "checkSelfPermission: "); +// mPresenter.getHomeVideo(); + getThumbnail(); } - break; - case R.id.refresh: - refreshLayout.setRefreshing(true); - mPresenter.getHomeVideo(); - break; - case R.id.single_loop: - if (null != single_loop) { - int singleLoop = (int) SPUtils.get(MainActivity.this, "single_loop", 0); - if (singleLoop == 0) { - SPUtils.put(MainActivity.this, "single_loop", 1); - SPUtils.put(MainActivity.this, "loop", 0); - single_loop.setIcon(R.drawable.menu_selected); - } else { - SPUtils.put(MainActivity.this, "single_loop", 0); - single_loop.setIcon(R.drawable.menu_transparent); - } - } - break; - case R.id.loop: - if (null != loop) { - int singleLoop = (int) SPUtils.get(MainActivity.this, "loop", 0); - if (singleLoop == 0) { - SPUtils.put(MainActivity.this, "single_loop", 0); - SPUtils.put(MainActivity.this, "loop", 1); - loop.setIcon(R.drawable.menu_selected); - } else { - SPUtils.put(MainActivity.this, "loop", 0); - loop.setIcon(R.drawable.menu_transparent); - } - } - break; - default: - break; - } - updateMenuIcon(); - return super.onOptionsItemSelected(item); - } - - private long mPreClickTime; - - private void updateMenuIcon() { - if (null != refresh) { - - } - if (null != single_loop) { - int singleLoop = (int) SPUtils.get(MainActivity.this, "single_loop", 0); - if (singleLoop == 0) { - single_loop.setIcon(R.drawable.menu_transparent); - } else { - single_loop.setIcon(R.drawable.menu_selected); } - } - if (null != loop) { - int singleLoop = (int) SPUtils.get(MainActivity.this, "loop", 0); - if (singleLoop == 0) { - loop.setIcon(R.drawable.menu_transparent); - } else { - loop.setIcon(R.drawable.menu_selected); + if (mPermissionList.size() > 0) {//有权限没有通过,需要申请 + ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_CODE); } } } - @Override - public void setHomeVideo(ArrayList video) { - if (video == null || video.size() == 0) { - tips.setVisibility(View.VISIBLE); - recyclerView.setVisibility(View.GONE); + private void getThumbnail() { + long s1 = System.currentTimeMillis(); + List picFileList = new ArrayList<>(); + List videoFileList = new ArrayList<>(); + String rootPath = JGYUtils.getInstance().getDownLoadPath() + File.separator; + File file = new File(rootPath); + if (file.exists()) { + LinkedList list = new LinkedList(); + File[] files = file.listFiles(); + if (files == null) { + return; + } + for (File file2 : files) { + if (file2.isDirectory()) { + list.add(file2); + } else { + if (VideoUtils.isPicFormat(file2.getAbsolutePath())) { + picFileList.add(file2.getAbsolutePath()); + } else if (VideoUtils.isVideoFormat(file2.getAbsolutePath())) { + videoFileList.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.isPicFormat(file2.getAbsolutePath())) { + picFileList.add(file2.getAbsolutePath()); + } else if (VideoUtils.isVideoFormat(file2.getAbsolutePath())) { + videoFileList.add(file2.getAbsolutePath()); + } + } + } + } } else { - tips.setVisibility(View.GONE); - recyclerView.setVisibility(View.VISIBLE); - adapter.setData(video); + Log.e("traverseFolder1", "文件不存在!"); } - tv_scan.setVisibility(View.GONE); - refreshLayout.setRefreshing(false); - } + Log.e("ScanTask", "doInBackground: " + "Scan time = " + (System.currentTimeMillis() - s1) + "ms"); + Log.e("getThumbnail", "picFileList: " + picFileList); + Log.e("getThumbnail", "videoFileList: " + videoFileList); + Log.e("getThumbnail", "picFileList size = " + picFileList.size()); + Log.e("getThumbnail", "videoFileList size = " + videoFileList.size()); + if (picFileList.size() == 0) { + nv_pic.setImageDrawable(getDrawable(R.drawable.icon_pic)); + } else { + nv_pic.setImageDrawable(path2Drawable(picFileList.get(0))); + } + if (videoFileList.size() == 0) { + nv_video.setImageDrawable(getDrawable(R.drawable.icon_video)); + } else { + Observable.create(new ObservableOnSubscribe() { + @Override + public void subscribe(ObservableEmitter emitter) throws Exception { + FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever(); + mmr.setDataSource(videoFileList.get(0)); + Bitmap bitmap = mmr.getFrameAtTime();//获得视频第一帧的Bitmap对象. + mmr.release(); + emitter.onNext(bitmap); + } + }).subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + Log.e("VideoResult", "onSubscribe: "); + } - @Override - public void getHomeVideoFinish() { - refreshLayout.setRefreshing(false); + @Override + public void onNext(Bitmap result) { + Log.e("VideoResult", "onNext: " + result); + nv_video.setImageBitmap(result); +// Glide.with(nv_video).load(result).error(R.drawable.icon_video).into(nv_video); + } + + @Override + public void onError(Throwable e) { + Log.e("VideoResult", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("VideoResult", "onComplete: "); + } + }); + } + Log.e("getThumbnail", "videoFileList size = " + videoFileList.size()); +// CombineBitmap.init(this) +// .setLayoutManager(new DingLayoutManager()) // 必选, 设置图片的组合形式,支持WechatLayoutManager、DingLayoutManager +// .setSize(100) // 必选,组合后Bitmap的尺寸,单位dp +// .setGap(1) // 单个图片之间的距离,单位dp,默认0dp +//// .setGapColor() // 单个图片间距的颜色,默认白色 +//// .setPlaceholder() // 单个图片加载失败的默认显示图片 +// .setUrls(picFileList.toArray(new String[picFileList.size()])) // 要加载的图片url数组 +// .setBitmaps() // 要加载的图片bitmap数组 +// .setResourceIds() // 要加载的图片资源id数组 +// .setImageView(nv_pic) // 直接设置要显示图片的ImageView +// // 设置“子图片”的点击事件,需使用setImageView(),index和图片资源数组的索引对应 +//// .setOnSubItemClickListener(new OnSubItemClickListener() { +//// @Override +//// public void onSubItemClick(int index) { +//// +//// } +//// }) +//// // 加载进度的回调函数,如果不使用setImageView()方法,可在onComplete()完成最终图片的显示 +//// .setProgressListener(new ProgressListener() { +//// @Override +//// public void onStart() { +//// +//// } +//// +//// @Override +//// public void onComplete(Bitmap bitmap) { +//// +//// } +//// }) +// .build(); + +// CombineBitmap.init(this) +// .setLayoutManager(new DingLayoutManager()) // 必选, 设置图片的组合形式,支持WechatLayoutManager、DingLayoutManager +// .setSize(100) // 必选,组合后Bitmap的尺寸,单位dp +// .setGap(1) // 单个图片之间的距离,单位dp,默认0dp +//// .setGapColor() // 单个图片间距的颜色,默认白色 +//// .setPlaceholder() // 单个图片加载失败的默认显示图片 +// .setUrls(videoFileList.toArray(new String[videoFileList.size()])) // 要加载的图片url数组 +// .setBitmaps() // 要加载的图片bitmap数组 +// .setResourceIds() // 要加载的图片资源id数组 +// .setImageView(nv_video) // 直接设置要显示图片的ImageView +// .build(); } - //在这里处理任务执行中的状态,如进度进度条的刷新 - @Download.onTaskRunning - void running(DownloadTask task) { - Log.e("aria running", "正在下载:" + task.getState() + "-" + task.getPercent() + "--" + task.getExtendField()); + /** + * 将本地图片转换为 Drawable + * + * @param file 文件路径 + * @return + */ + public Drawable path2Drawable(String file) { + if (file == null || file.isEmpty()) { + return null; + } + Drawable drawable = null; try { - String jsonString = task.getExtendField(); - JsonObject jsonObject = GsonUtils.getJsonObject(jsonString); - } catch (Exception e) { - Log.e("running", "running: " + e.getMessage()); + FileInputStream fis = new FileInputStream(file); + Bitmap bitmap = BitmapFactory.decodeStream(fis); + drawable = new BitmapDrawable(getResources(), bitmap); + } catch (FileNotFoundException e) { + e.printStackTrace(); } - } - @Download.onTaskComplete - void taskComplete(DownloadTask task) { - //在这里处理任务完成的状态 - Log.e("taskComplete", task.getExtendField()); -// Aria.download(this).load(task.getDownloadEntity().getId()).cancel(); - mPresenter.getHomeVideo(); - } - - @Download.onTaskFail - void taskFail(DownloadTask task, Exception e) { - Aria.download(this).resumeAllTask(); - final String filepath = task.getFilePath(); - final String packageName = task.getExtendField(); - try { - Aria.download(this).load(task.getDownloadEntity().getId()).cancel(true); - Log.e(TAG, "taskFail: " + "Exception: " + e.getLocalizedMessage()); - } catch (Exception ex) { - - } - Log.e(TAG, "taskFail: " + packageName + "filepath: " + filepath); - mPresenter.getHomeVideo(); + return drawable; } } diff --git a/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryActivity.java b/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryActivity.java new file mode 100644 index 0000000..9968ca1 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryActivity.java @@ -0,0 +1,85 @@ +package com.uiui.videoplayer.activity.pic; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; + +import com.uiui.videoplayer.R; +import com.uiui.videoplayer.adapter.PicAdapter; +import com.uiui.videoplayer.base.BGAGridDivider; +import com.uiui.videoplayer.base.BaseLightActivity; +import com.uiui.videoplayer.base.GridSpaceItemDecoration; +import com.uiui.videoplayer.bean.PhotoInfo; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class GalleryActivity extends BaseLightActivity implements GalleryContact.GalleryView { + + @BindView(R.id.swipeRefreshLayout) + SwipeRefreshLayout swipeRefreshLayout; + @BindView(R.id.recyclerView) + RecyclerView recyclerView; + @BindView(R.id.iv_back) + ImageView iv_back; + + private GalleryPresenter mPresenter; + private PicAdapter mPicAdapter; + private static final int SPAN_COUNT = 3; + + @Override + public int getLayoutId() { + return R.layout.activity_gallery; + } + + @Override + public void initView() { + ButterKnife.bind(this); + mPresenter = new GalleryPresenter(this); + mPresenter.setLifecycle(lifecycleSubject); + mPresenter.attachView(this); + + GridLayoutManager layoutManager = new GridLayoutManager(this, SPAN_COUNT, LinearLayoutManager.VERTICAL, false); + mPicAdapter = new PicAdapter(layoutManager); + recyclerView.setLayoutManager(layoutManager); + recyclerView.addItemDecoration(BGAGridDivider.newInstanceWithSpaceRes(R.dimen.dp_2)); + recyclerView.setAdapter(mPicAdapter); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + swipeRefreshLayout.setRefreshing(true); + mPresenter.getHomePhoto(); + } + }); + iv_back.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + } + + @Override + public void initData() { + mPresenter.getHomePhoto(); + } + + @Override + public void setHomePhoto(ArrayList photoInfos) { + mPicAdapter.setPhotoInfos(photoInfos); + } + + @Override + public void getHomePhotoFinish() { + swipeRefreshLayout.setRefreshing(false); + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryContact.java b/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryContact.java new file mode 100644 index 0000000..40f6b83 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryContact.java @@ -0,0 +1,20 @@ +package com.uiui.videoplayer.activity.pic; + +import com.uiui.videoplayer.base.BasePresenter; +import com.uiui.videoplayer.base.BaseView; +import com.uiui.videoplayer.bean.PhotoInfo; + +import java.util.ArrayList; +import java.util.List; + +public class GalleryContact { + interface Presenter extends BasePresenter { + /*获取视频*/ + void getHomePhoto(); + } + + public interface GalleryView extends BaseView { + void setHomePhoto(ArrayList photoInfos); + void getHomePhotoFinish(); + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryPresenter.java b/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryPresenter.java new file mode 100644 index 0000000..12a4418 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/activity/pic/GalleryPresenter.java @@ -0,0 +1,62 @@ +package com.uiui.videoplayer.activity.pic; + +import android.content.Context; + +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.uiui.videoplayer.bean.BaseResponse; +import com.uiui.videoplayer.bean.PhotoInfo; +import com.uiui.videoplayer.network.NetInterfaceManager; + +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; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +public class GalleryPresenter implements GalleryContact.Presenter { + + private GalleryContact.GalleryView mView; + private Context mContext; + + public GalleryPresenter(Context context) { + this.mContext = context; + } + + private BehaviorSubject lifecycle; + + public void setLifecycle(BehaviorSubject lifecycle) { + this.lifecycle = lifecycle; + } + + public BehaviorSubject getLifecycle() { + return lifecycle; + } + + @Override + public void attachView(GalleryContact.GalleryView view) { + this.mView = view; + } + + @Override + public void detachView() { + this.mView = null; + } + + @Override + public void getHomePhoto() { + NetInterfaceManager.getInstance().getHomePhoto(true, getLifecycle(), new NetInterfaceManager.onPhotoCallback() { + @Override + public void setPhotoList(ArrayList photoList) { + mView.setHomePhoto(photoList); + } + + @Override + public void onComplete() { + mView.getHomePhotoFinish(); + } + }); + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/activity/preview/PreviewActivity.java b/app/src/main/java/com/uiui/videoplayer/activity/preview/PreviewActivity.java new file mode 100644 index 0000000..8c1df4c --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/activity/preview/PreviewActivity.java @@ -0,0 +1,103 @@ +package com.uiui.videoplayer.activity.preview; + +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.widget.ImageView; + +import androidx.viewpager.widget.ViewPager; + +import com.bumptech.glide.Glide; +import com.uiui.videoplayer.R; +import com.uiui.videoplayer.adapter.PreviewAdapter; +import com.uiui.videoplayer.base.BaseLightActivity; +import com.uiui.videoplayer.base.ScaleCircleNavigator; +import com.uiui.videoplayer.bean.PhotoInfo; +import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX; + +import net.lucode.hackware.magicindicator.MagicIndicator; +import net.lucode.hackware.magicindicator.ViewPagerHelper; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class PreviewActivity extends BaseLightActivity { + + @BindView(R.id.viewPager) + ViewPager viewPager; + @BindView(R.id.magicIndicator) + MagicIndicator mMagicIndicator; + + private PreviewAdapter mPreviewAdapter; + private ScaleCircleNavigator scaleCircleNavigator; + private ArrayList mPhotoInfos; + + @Override + public int getLayoutId() { + return R.layout.activity_preview; + } + + @Override + public void initView() { + UltimateBarX.statusBar(this) + .transparent() + .fitWindow(false) + .light(true) + .apply(); + UltimateBarX.navigationBar(this) + .transparent() + .light(true) + .apply(); + + ButterKnife.bind(this); + mPreviewAdapter = new PreviewAdapter(); + viewPager.setAdapter(mPreviewAdapter); + scaleCircleNavigator = new ScaleCircleNavigator(this); + } + + @Override + public void initData() { + Intent intent = getIntent(); + Bundle bundle = intent.getExtras(); + if (bundle == null) { + finish(); + return; + } + ArrayList photoInfos = bundle.getParcelableArrayList("mPhotoInfos"); + if (photoInfos == null) { + finish(); + return; + } + int position = bundle.getInt("position"); + setImageViews(photoInfos); + viewPager.setCurrentItem(position); + + } + + private void setImageViews(List photoInfos) { + mMagicIndicator.setNavigator(scaleCircleNavigator); + scaleCircleNavigator.setCircleCount(photoInfos.size()); + scaleCircleNavigator.setNormalCircleColor(Color.DKGRAY); + scaleCircleNavigator.setSelectedCircleColor(Color.LTGRAY); + scaleCircleNavigator.setCircleClickListener(new ScaleCircleNavigator.OnCircleClickListener() { + @Override + public void onClick(int index) { + + } + }); + ViewPagerHelper.bind(mMagicIndicator, viewPager); + List imageViews = new ArrayList<>(); + for (PhotoInfo photoInfo : photoInfos) { + ImageView image = new ImageView(this); + image.setAdjustViewBounds(true); + image.setScaleType(ImageView.ScaleType.FIT_CENTER); + Glide.with(this).load(photoInfo.getFile()).into(image); + imageViews.add(image); + } + mPreviewAdapter.setImageViews(imageViews); + mPreviewAdapter.notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/activity/video/VideoActivity.java b/app/src/main/java/com/uiui/videoplayer/activity/video/VideoActivity.java new file mode 100644 index 0000000..d859549 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/activity/video/VideoActivity.java @@ -0,0 +1,459 @@ +package com.uiui.videoplayer.activity.video; + +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Environment; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.arialyy.annotations.Download; +import com.arialyy.aria.core.Aria; +import com.arialyy.aria.core.task.DownloadTask; +import com.google.gson.JsonObject; +import com.uiui.videoplayer.R; +import com.uiui.videoplayer.adapter.VideoAdapter; +import com.uiui.videoplayer.base.BaseLightActivity; +import com.uiui.videoplayer.base.CustomDialog; +import com.uiui.videoplayer.base.RecycleGridLayoutManager; +import com.uiui.videoplayer.base.SpacesItemDecoration; +import com.uiui.videoplayer.bean.LocalVideoInfo; +import com.uiui.videoplayer.gson.GsonUtils; +import com.uiui.videoplayer.utils.SPUtils; +import com.uiui.videoplayer.utils.ToastUtil; +import com.uiui.videoplayer.utils.VideoUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class VideoActivity extends BaseLightActivity implements VideoContact.VideoView { + + private static final String TAG = VideoActivity.class.getSimpleName(); + + @BindView(R.id.recyclerView) + RecyclerView recyclerView; + @BindView(R.id.cl_nodata) + ConstraintLayout cl_nodata; + @BindView(R.id.tv_scan) + TextView tv_scan; + @BindView(R.id.swipeRefreshLayout) + SwipeRefreshLayout refreshLayout; + @BindView(R.id.iv_back) + ImageView iv_back; + + private VideoPresenter mPresenter; + private List paths = new ArrayList<>(); + private RecycleGridLayoutManager mManager; + private VideoAdapter adapter; + + @Override + public void initView() { + ButterKnife.bind(this); + mPresenter = new VideoPresenter(this); + mPresenter.setLifecycle(lifecycleSubject); + mPresenter.attachView(this); + + Aria.download(this).register(); + +// initActionBar(); + refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + mPresenter.getHomeVideo(); + } + }); + refreshLayout.setRefreshing(true); + ((SimpleItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false); + int orientation = getResources().getConfiguration().orientation; + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + mManager = new RecycleGridLayoutManager(VideoActivity.this, 3); + } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { + mManager = new RecycleGridLayoutManager(VideoActivity.this, 2); + } + recyclerView.setLayoutManager(mManager); + recyclerView.setNestedScrollingEnabled(false); + recyclerView.addItemDecoration(new SpacesItemDecoration(getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x), + getResources().getDimensionPixelSize(R.dimen.PX1x), getResources().getDimensionPixelSize(R.dimen.PX1x))); + ((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false); + adapter = new VideoAdapter(VideoActivity.this); + adapter.setOnLongClickListener(new VideoAdapter.onItemLongClickListener() { + @Override + public void onItemLongClick(String path, int position) { + showDialog(path, position); + } + }); + recyclerView.setAdapter(adapter); + iv_back.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + } + + @Override + public void initData() { + mPresenter.getHomeVideo(); + } + + @Override + public int getLayoutId() { + return R.layout.activity_video; + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + Configuration config = getResources().getConfiguration(); + if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) { + mManager = new RecycleGridLayoutManager(VideoActivity.this, 2); + recyclerView.setLayoutManager(mManager); + } + if (config.orientation == Configuration.ORIENTATION_PORTRAIT) { + mManager = new RecycleGridLayoutManager(VideoActivity.this, 3); + recyclerView.setLayoutManager(mManager); + } + } + + private void showDialog(String path, int position) { + CustomDialog dialog = new CustomDialog(VideoActivity.this); + dialog.setTitle("删除文件") + .setMessage("确定要删除文件 " + VideoUtils.getFileNameWithoutExtension(path) + "吗") + .setPositive("确定") + .setNegtive("取消") + .setOnClickBottomListener(new CustomDialog.OnClickBottomListener() { + @Override + public void onPositiveClick() { + dialog.dismiss(); + File file = new File(path); + if (file.delete()) { + adapter.removeItem(position); + ToastUtil.show("删除成功"); + } else { + ToastUtil.show("删除失败,检查权限是否开启"); + } + } + + @Override + public void onNegtiveClick() { + dialog.dismiss(); + } + }); + dialog.show(); + } + + + private void initActionBar() { + setToolbarCustomTheme(); + //显示返回按钮 + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setHomeButtonEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + SpannableString spannableString = new SpannableString(getString(R.string.app_name)); + ForegroundColorSpan colorSpan = new ForegroundColorSpan(getResources().getColor(R.color.defaultColor)); + spannableString.setSpan(colorSpan, 0, spannableString.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + actionBar.setTitle(spannableString); + } + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } + + //自定义颜色返回按钮 + protected void setToolbarCustomTheme() { + Drawable upArrow = ContextCompat.getDrawable(this, R.drawable.abc_ic_ab_back_material); + if (upArrow != null) { + upArrow.setColorFilter(ContextCompat.getColor(this, R.color.defaultColor), PorterDuff.Mode.SRC_ATOP); + if (getSupportActionBar() != null) { + getSupportActionBar().setHomeAsUpIndicator(upArrow); + } + } + } + + public void traverseFolder(String path) { + int fileNum = 0, folderNum = 0; + File file = new File(path); + if (file.exists()) { + LinkedList list = new LinkedList(); + File[] files = file.listFiles(); + for (File file2 : files) { + if (file2.isDirectory()) { + Log.e("traverseFolder1", "文件夹:" + file2.getAbsolutePath()); + list.add(file2); + folderNum++; + } else { + Log.e("traverseFolder1", "文件:" + file2.getAbsolutePath()); + fileNum++; + } + } + File temp_file; + while (!list.isEmpty()) { + temp_file = list.removeFirst(); + files = temp_file.listFiles(); + for (File file2 : files) { + if (file2.isDirectory()) { + Log.e("traverseFolder2", "文件夹:" + file2.getAbsolutePath()); + list.add(file2); + folderNum++; + } else { + Log.e("traverseFolder2", "文件:" + file2.getAbsolutePath()); + fileNum++; + } + } + } + } else { + Log.e("traverseFolder1", "文件不存在!"); + } + Log.e("traverseFolder1", "文件夹共有:" + folderNum + ",文件共有:" + fileNum); + } + + + public class ScanTask extends AsyncTask> { + + @Override + protected List doInBackground(Void... voids) { + long s1 = System.currentTimeMillis(); + paths.clear(); + 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) return null; + for (File file2 : files) { + publishProgress(file2.getAbsolutePath()); + 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) { + publishProgress(file2.getAbsolutePath()); + if (file2.isDirectory()) { + list.add(file2); + } else { + if (VideoUtils.isVideoFormat(file2.getAbsolutePath())) { + fileList.add(file2.getAbsolutePath()); + } + } + } + } + } else { + Log.e("traverseFolder1", "文件不存在!"); + } + Log.e("ScanTask", "doInBackground: " + "Scan time = " + (System.currentTimeMillis() - s1) + "ms"); + return fileList; + } + + @Override + protected void onProgressUpdate(String... values) { + super.onProgressUpdate(values); + paths.add(values[0]); + tv_scan.setVisibility(View.VISIBLE); + tv_scan.setText("正在扫描:" + values[0]); +// adapter.setData(paths); + } + + @Override + protected void onPostExecute(List strings) { + super.onPostExecute(strings); + Log.e("ScanTask", "onPostExecute: " + strings.size()); + if (strings.size() == 0) { + cl_nodata.setVisibility(View.VISIBLE); + recyclerView.setVisibility(View.GONE); + } else { + cl_nodata.setVisibility(View.GONE); + recyclerView.setVisibility(View.VISIBLE); +// adapter.setData(strings); + } + tv_scan.setVisibility(View.GONE); + refreshLayout.setRefreshing(false); + } + } + + private MenuItem refresh, single_loop, loop; + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.main, menu); + refresh = menu.findItem(R.id.refresh); + single_loop = menu.findItem(R.id.single_loop); + loop = menu.findItem(R.id.loop); + updateMenuIcon(); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + //返回按钮点击事件 + switch (item.getItemId()) { + case R.id.setting: + + break; + case android.R.id.home: + if (System.currentTimeMillis() - mPreClickTime > 1000) { + ToastUtil.show("再按一次,退出"); + mPreClickTime = System.currentTimeMillis(); + } else { + finish(); + } + break; + case R.id.refresh: + refreshLayout.setRefreshing(true); + mPresenter.getHomeVideo(); + break; + case R.id.single_loop: + if (null != single_loop) { + int singleLoop = (int) SPUtils.get(VideoActivity.this, "single_loop", 0); + if (singleLoop == 0) { + SPUtils.put(VideoActivity.this, "single_loop", 1); + SPUtils.put(VideoActivity.this, "loop", 0); + single_loop.setIcon(R.drawable.menu_selected); + } else { + SPUtils.put(VideoActivity.this, "single_loop", 0); + single_loop.setIcon(R.drawable.menu_transparent); + } + } + break; + case R.id.loop: + if (null != loop) { + int singleLoop = (int) SPUtils.get(VideoActivity.this, "loop", 0); + if (singleLoop == 0) { + SPUtils.put(VideoActivity.this, "single_loop", 0); + SPUtils.put(VideoActivity.this, "loop", 1); + loop.setIcon(R.drawable.menu_selected); + } else { + SPUtils.put(VideoActivity.this, "loop", 0); + loop.setIcon(R.drawable.menu_transparent); + } + } + break; + default: + break; + } + updateMenuIcon(); + return super.onOptionsItemSelected(item); + } + + private long mPreClickTime; + + private void updateMenuIcon() { + if (null != refresh) { + + } + if (null != single_loop) { + int singleLoop = (int) SPUtils.get(VideoActivity.this, "single_loop", 0); + if (singleLoop == 0) { + single_loop.setIcon(R.drawable.menu_transparent); + } else { + single_loop.setIcon(R.drawable.menu_selected); + } + } + if (null != loop) { + int singleLoop = (int) SPUtils.get(VideoActivity.this, "loop", 0); + if (singleLoop == 0) { + loop.setIcon(R.drawable.menu_transparent); + } else { + loop.setIcon(R.drawable.menu_selected); + } + } + } + + @Override + public void setHomeVideo(ArrayList video) { + if (video == null || video.size() == 0) { + cl_nodata.setVisibility(View.VISIBLE); + recyclerView.setVisibility(View.GONE); + } else { + cl_nodata.setVisibility(View.GONE); + recyclerView.setVisibility(View.VISIBLE); + adapter.setData(video); + } + tv_scan.setVisibility(View.GONE); + refreshLayout.setRefreshing(false); + } + + @Override + public void getHomeVideoFinish() { + refreshLayout.setRefreshing(false); + } + + + //在这里处理任务执行中的状态,如进度进度条的刷新 + @Download.onTaskRunning + void running(DownloadTask task) { + Log.e("aria running", "正在下载:" + task.getState() + "-" + task.getPercent() + "--" + task.getExtendField()); + try { + String jsonString = task.getExtendField(); + JsonObject jsonObject = GsonUtils.getJsonObject(jsonString); + } catch (Exception e) { + Log.e("running", "running: " + e.getMessage()); + } + } + + @Download.onTaskComplete + void taskComplete(DownloadTask task) { + //在这里处理任务完成的状态 + Log.e("taskComplete", task.getExtendField()); +// Aria.download(this).load(task.getDownloadEntity().getId()).cancel(); + mPresenter.getHomeVideo(); + } + + @Download.onTaskFail + void taskFail(DownloadTask task, Exception e) { + Aria.download(this).resumeAllTask(); + final String filepath = task.getFilePath(); + final String packageName = task.getExtendField(); + try { + Aria.download(this).load(task.getDownloadEntity().getId()).cancel(true); + Log.e(TAG, "taskFail: " + "Exception: " + e.getLocalizedMessage()); + } catch (Exception ex) { + + } + Log.e(TAG, "taskFail: " + packageName + "filepath: " + filepath); + mPresenter.getHomeVideo(); + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/activity/main/MainAContact.java b/app/src/main/java/com/uiui/videoplayer/activity/video/VideoContact.java similarity index 64% rename from app/src/main/java/com/uiui/videoplayer/activity/main/MainAContact.java rename to app/src/main/java/com/uiui/videoplayer/activity/video/VideoContact.java index d750c73..4c90ec2 100644 --- a/app/src/main/java/com/uiui/videoplayer/activity/main/MainAContact.java +++ b/app/src/main/java/com/uiui/videoplayer/activity/video/VideoContact.java @@ -1,4 +1,4 @@ -package com.uiui.videoplayer.activity.main; +package com.uiui.videoplayer.activity.video; import com.uiui.videoplayer.base.BasePresenter; import com.uiui.videoplayer.base.BaseView; @@ -6,13 +6,13 @@ import com.uiui.videoplayer.bean.LocalVideoInfo; import java.util.ArrayList; -public class MainAContact { - interface Presenter extends BasePresenter { +public class VideoContact { + interface Presenter extends BasePresenter { /*获取视频*/ void getHomeVideo(); } - public interface MainView extends BaseView { + public interface VideoView extends BaseView { void setHomeVideo(ArrayList video); void getHomeVideoFinish(); } diff --git a/app/src/main/java/com/uiui/videoplayer/activity/main/MainAPresenter.java b/app/src/main/java/com/uiui/videoplayer/activity/video/VideoPresenter.java similarity index 81% rename from app/src/main/java/com/uiui/videoplayer/activity/main/MainAPresenter.java rename to app/src/main/java/com/uiui/videoplayer/activity/video/VideoPresenter.java index 4509559..765af2b 100644 --- a/app/src/main/java/com/uiui/videoplayer/activity/main/MainAPresenter.java +++ b/app/src/main/java/com/uiui/videoplayer/activity/video/VideoPresenter.java @@ -1,4 +1,4 @@ -package com.uiui.videoplayer.activity.main; +package com.uiui.videoplayer.activity.video; import android.content.Context; @@ -14,14 +14,14 @@ import io.reactivex.rxjava3.subjects.BehaviorSubject; /** * @author jgy02 */ -public class MainAPresenter implements MainAContact.Presenter { - private static final String TAG = MainAPresenter.class.getSimpleName(); +public class VideoPresenter implements VideoContact.Presenter { + private static final String TAG = VideoPresenter.class.getSimpleName(); - private MainAContact.MainView mView; + private VideoContact.VideoView mView; private Context mContext; private CacheHelper mCacheHelper; - public MainAPresenter(Context context) { + public VideoPresenter(Context context) { this.mContext = context; this.mCacheHelper = new CacheHelper(context); } @@ -37,7 +37,7 @@ public class MainAPresenter implements MainAContact.Presenter { } @Override - public void attachView(MainAContact.MainView view) { + public void attachView(VideoContact.VideoView view) { this.mView = view; } diff --git a/app/src/main/java/com/uiui/videoplayer/adapter/PicAdapter.java b/app/src/main/java/com/uiui/videoplayer/adapter/PicAdapter.java new file mode 100644 index 0000000..95eb7c2 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/adapter/PicAdapter.java @@ -0,0 +1,104 @@ +package com.uiui.videoplayer.adapter; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +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.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.Glide; +import com.uiui.videoplayer.R; +import com.uiui.videoplayer.activity.preview.PreviewActivity; +import com.uiui.videoplayer.bean.PhotoInfo; +import com.uiui.videoplayer.gson.GsonUtils; +import com.uiui.videoplayer.utils.JGYUtils; +import com.uiui.videoplayer.utils.VideoUtils; + +import java.util.ArrayList; +import java.util.List; + +public class PicAdapter extends RecyclerView.Adapter { + + private Context mContext; + private GridLayoutManager mGridLayoutManager; + private ArrayList mPhotoInfos; + + public PicAdapter(GridLayoutManager gridLayoutManager) { + this.mGridLayoutManager = gridLayoutManager; + } + + @NonNull + @Override + public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + mContext = parent.getContext(); + Holder holder = new Holder(LayoutInflater.from(mContext).inflate(R.layout.item_pic, parent, false)); + ViewGroup.LayoutParams params = holder.itemView.getLayoutParams(); + ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) holder.iv_pic.getLayoutParams(); + //动态计算,设置item的宽高一致,总宽度-左右margin-左右padding /总列数-item左右margin-item左右padding + params.height = + (mGridLayoutManager.getWidth() - layoutParams.leftMargin + - layoutParams.rightMargin - holder.iv_pic.getPaddingStart() - holder.iv_pic.getPaddingEnd()) / mGridLayoutManager.getSpanCount() + - 2 * holder.itemView.getPaddingLeft() - 2 * ((ViewGroup.MarginLayoutParams) params).leftMargin; + return holder; + } + + @Override + public void onBindViewHolder(@NonNull Holder holder, int position) { + PhotoInfo photoInfo = mPhotoInfos.get(position); + String fileName = photoInfo.getFile_name(); + String fileUrl = photoInfo.getFile(); + if (TextUtils.isEmpty(fileName)) { + holder.tv_name.setText(VideoUtils.getFileNameWithoutExtension(fileUrl)); + } else { + holder.tv_name.setText(fileName); + } + if (!JGYUtils.getInstance().fileExists(photoInfo.getFile())) { + Glide.with(mContext).load(fileUrl).into(holder.iv_pic); + } else { + Glide.with(mContext).load(JGYUtils.getInstance().getUrlLocalPath(photoInfo.getFile())).into(holder.iv_pic); + } + holder.root.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(mContext, PreviewActivity.class); + Bundle bundle = new Bundle(); + bundle.putParcelableArrayList("mPhotoInfos", mPhotoInfos); + bundle.putInt("position", position); + intent.putExtras(bundle); + mContext.startActivity(intent); + } + }); + } + + @Override + public int getItemCount() { + return mPhotoInfos == null ? 0 : mPhotoInfos.size(); + } + + public void setPhotoInfos(ArrayList photoInfos) { + this.mPhotoInfos = photoInfos; + notifyDataSetChanged(); + } + + class Holder extends RecyclerView.ViewHolder { + ConstraintLayout root; + ImageView iv_pic; + TextView tv_name; + + public Holder(@NonNull View itemView) { + super(itemView); + root = itemView.findViewById(R.id.root); + iv_pic = itemView.findViewById(R.id.iv_pic); + tv_name = itemView.findViewById(R.id.tv_name); + } + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/adapter/PreviewAdapter.java b/app/src/main/java/com/uiui/videoplayer/adapter/PreviewAdapter.java new file mode 100644 index 0000000..56ecc73 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/adapter/PreviewAdapter.java @@ -0,0 +1,43 @@ +package com.uiui.videoplayer.adapter; + +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.viewpager.widget.PagerAdapter; + +import java.util.List; + +public class PreviewAdapter extends PagerAdapter { + private List mImageViews; + + public void setImageViews(List imageViews) { + this.mImageViews = imageViews; + } + + @Override + public int getCount() { + return mImageViews == null ? 0 : mImageViews.size(); + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { + return view == object; + + } + + @NonNull + @Override + public Object instantiateItem(@NonNull ViewGroup container, int position) { + // 给 container 添加一个view + container.addView(mImageViews.get(position)); + // 返回一个和该view相对的object + return mImageViews.get(position); + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + container.removeView(mImageViews.get(position)); + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/base/BGABaseAdapterUtil.java b/app/src/main/java/com/uiui/videoplayer/base/BGABaseAdapterUtil.java new file mode 100644 index 0000000..813d984 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/base/BGABaseAdapterUtil.java @@ -0,0 +1,88 @@ +package com.uiui.videoplayer.base; + +import android.app.Application; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import androidx.annotation.ColorRes; +import androidx.annotation.DimenRes; +import android.util.Log; +import android.util.TypedValue; + +import java.util.List; + +/** + * 作者:王浩 邮件:bingoogolapple@gmail.com + * 创建时间:17/1/6 上午4:04 + * 描述: + */ +public class BGABaseAdapterUtil { + private static final Application sApp; + + static { + Application app = null; + try { + app = (Application) Class.forName("android.app.AppGlobals").getMethod("getInitialApplication").invoke(null); + if (app == null) + throw new IllegalStateException("Static initialization of Applications must be on main thread."); + } catch (final Exception e) { + Log.e(BGABaseAdapterUtil.class.getSimpleName(), "Failed to get current application from AppGlobals." + e.getMessage()); + try { + app = (Application) Class.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null); + } catch (final Exception ex) { + Log.e(BGABaseAdapterUtil.class.getSimpleName(), "Failed to get current application from ActivityThread." + e.getMessage()); + } + } finally { + sApp = app; + } + } + + private BGABaseAdapterUtil() { + } + + public static Application getApp() { + return sApp; + } + + public static int dp2px(float dpValue) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, getApp().getResources().getDisplayMetrics()); + } + + public static int sp2px(float dpValue) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, dpValue, getApp().getResources().getDisplayMetrics()); + } + + public static int getDimensionPixelOffset(@DimenRes int resId) { + return getApp().getResources().getDimensionPixelOffset(resId); + } + + public static int getColor(@ColorRes int resId) { + return getApp().getResources().getColor(resId); + } + + public static Drawable rotateBitmap(Bitmap inputBitmap) { + Matrix matrix = new Matrix(); + matrix.setRotate(90, (float) inputBitmap.getWidth() / 2, (float) inputBitmap.getHeight() / 2); + + float outputX = inputBitmap.getHeight(); + float outputY = 0; + + final float[] values = new float[9]; + matrix.getValues(values); + float x1 = values[Matrix.MTRANS_X]; + float y1 = values[Matrix.MTRANS_Y]; + matrix.postTranslate(outputX - x1, outputY - y1); + Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap.getHeight(), inputBitmap.getWidth(), Bitmap.Config.ARGB_8888); + Paint paint = new Paint(); + Canvas canvas = new Canvas(outputBitmap); + canvas.drawBitmap(inputBitmap, matrix, paint); + return new BitmapDrawable(null, outputBitmap); + } + + public static boolean isListNotEmpty(List list) { + return list != null && !list.isEmpty(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/uiui/videoplayer/base/BGAGridDivider.java b/app/src/main/java/com/uiui/videoplayer/base/BGAGridDivider.java new file mode 100644 index 0000000..8a95748 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/base/BGAGridDivider.java @@ -0,0 +1,58 @@ +package com.uiui.videoplayer.base; + +import android.graphics.Rect; +import android.view.View; + +import androidx.annotation.DimenRes; +import androidx.recyclerview.widget.RecyclerView; + +/** + * 作者:王浩 邮件:bingoogolapple@gmail.com + * 创建时间:17/1/9 下午11:12 + * 描述: + */ +public class BGAGridDivider extends RecyclerView.ItemDecoration { + private int mSpace; + + private BGAGridDivider(int space) { + mSpace = space; + } + + /** + * 设置间距资源 id + * + * @param resId + * @return + */ + public static BGAGridDivider newInstanceWithSpaceRes(@DimenRes int resId) { + return new BGAGridDivider(BGABaseAdapterUtil.getDimensionPixelOffset(resId)); + } + + /** + * 设置间距 + * + * @param spaceDp 单位为 dp + * @return + */ + public static BGAGridDivider newInstanceWithSpaceDp(int spaceDp) { + return new BGAGridDivider(BGABaseAdapterUtil.dp2px(spaceDp)); + } + + /** + * 设置间距 + * + * @param spacePx 单位为 px + * @return + */ + public static BGAGridDivider newInstanceWithSpacePx(int spacePx) { + return new BGAGridDivider(spacePx); + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + outRect.left = mSpace; + outRect.right = mSpace; + outRect.top = mSpace; + outRect.bottom = mSpace; + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/base/BaseLightActivity.java b/app/src/main/java/com/uiui/videoplayer/base/BaseLightActivity.java index bc13a53..26758b2 100644 --- a/app/src/main/java/com/uiui/videoplayer/base/BaseLightActivity.java +++ b/app/src/main/java/com/uiui/videoplayer/base/BaseLightActivity.java @@ -1,5 +1,6 @@ package com.uiui.videoplayer.base; +import android.graphics.Color; import android.os.Bundle; import androidx.annotation.CallSuper; @@ -61,17 +62,19 @@ public abstract class BaseLightActivity extends AppCompatActivity implements Lif super.onCreate(savedInstanceState); lifecycleSubject.onNext(ActivityEvent.CREATE); // StatusBarUtil.init(this); + setContentView(this.getLayoutId()); UltimateBarX.statusBar(this) - .transparent() - .colorRes(R.color.colorPrimaryDark) - .light(true) +// .transparent() + .colorRes(R.color.colorAccent) + .fitWindow(true) + .light(false) .apply(); UltimateBarX.navigationBar(this) .transparent() - .colorRes(R.color.colorPrimaryDark) - .light(true) +// .color(Color.TRANSPARENT) + .fitWindow(false) + .light(false) .apply(); - setContentView(this.getLayoutId()); initView(); initData(); } diff --git a/app/src/main/java/com/uiui/videoplayer/base/GridSpaceItemDecoration.java b/app/src/main/java/com/uiui/videoplayer/base/GridSpaceItemDecoration.java new file mode 100644 index 0000000..57a7aea --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/base/GridSpaceItemDecoration.java @@ -0,0 +1,59 @@ +package com.uiui.videoplayer.base; + +import android.graphics.Rect; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +/** + * 描述 : RecyclerView GridLayoutManager 等间距。 + *

+ * 等间距需满足两个条件: + * 1.各个模块的大小相等,即 各列的left+right 值相等; + * 2.各列的间距相等,即 前列的right + 后列的left = 列间距; + *

+ * 在{@link #getItemOffsets(Rect, View, RecyclerView, RecyclerView.State)} 中针对 outRect 的left 和right 满足这两个条件即可 + *

+ * 作者 : shiguotao + * 版本 : V1 + * 创建时间 : 2020/3/19 4:54 PM + */ +public class GridSpaceItemDecoration extends RecyclerView.ItemDecoration { + + private final String TAG = "GridSpaceItemDecoration"; + + private int mSpanCount;//横条目数量 + private int mRowSpacing;//行间距 + private int mColumnSpacing;// 列间距 + + /** + * @param spanCount 列数 + * @param rowSpacing 行间距 + * @param columnSpacing 列间距 + */ + public GridSpaceItemDecoration(int spanCount, int rowSpacing, int columnSpacing) { + this.mSpanCount = spanCount; + this.mRowSpacing = rowSpacing; + this.mColumnSpacing = columnSpacing; + } + + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + int position = parent.getChildAdapterPosition(view); // 获取view 在adapter中的位置。 + int column = position % mSpanCount; // view 所在的列 + + outRect.left = column * mColumnSpacing / mSpanCount; // column * (列间距 * (1f / 列数)) + outRect.right = mColumnSpacing - (column + 1) * mColumnSpacing / mSpanCount; // 列间距 - (column + 1) * (列间距 * (1f /列数)) + + Log.e(TAG, "position:" + position + + " columnIndex: " + column + + " left,right ->" + outRect.left + "," + outRect.right); + + // 如果position > 行数,说明不是在第一行,则不指定行高,其他行的上间距为 top=mRowSpacing + if (position >= mSpanCount) { + outRect.top = mRowSpacing; // item top + } + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/base/ScaleCircleNavigator.java b/app/src/main/java/com/uiui/videoplayer/base/ScaleCircleNavigator.java new file mode 100644 index 0000000..53ef03b --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/base/ScaleCircleNavigator.java @@ -0,0 +1,323 @@ +package com.uiui.videoplayer.base; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.util.SparseArray; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + +import net.lucode.hackware.magicindicator.NavigatorHelper; +import net.lucode.hackware.magicindicator.abs.IPagerNavigator; +import net.lucode.hackware.magicindicator.buildins.ArgbEvaluatorHolder; +import net.lucode.hackware.magicindicator.buildins.UIUtil; + +import java.util.ArrayList; +import java.util.List; + +// _oo0oo_ +// o8888888o +// 88" . "88 +// (| -_- |) +// 0\ = /0 +// ___/`---'\___ +// .' \\| |// '. +// / \\||| : |||// \ +// / _||||| -:- |||||- \ +// | | \\\ - /// | | +// | \_| ''\---/'' |_/ | +// \ .-\__ '-' ___/-. / +// ___'. .' /--.--\ `. .'___ +// ."" '< `.___\_<|>_/___.' >' "". +// | | : `- \`.;`\ _ /`;.`/ - ` : | | +// \ \ `_. \_ __\ /__ _/ .-` / / +// =====`-.____`.___ \_____/___.-`___.-'===== +// `=---=' +// +// +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// 佛祖保佑 永无BUG + +/** + * 类似CircleIndicator的效果 + * Created by hackware on 2016/9/3. + */ + +public class ScaleCircleNavigator extends View implements IPagerNavigator, NavigatorHelper.OnNavigatorScrollListener { + private int mMinRadius; + private int mMaxRadius; + private int mNormalCircleColor = Color.LTGRAY; + private int mSelectedCircleColor = Color.GRAY; + private int mCircleSpacing; + private int mCircleCount; + + private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private List mCirclePoints = new ArrayList(); + private SparseArray mCircleRadiusArray = new SparseArray(); + + // 事件回调 + private boolean mTouchable; + private ScaleCircleNavigator.OnCircleClickListener mCircleClickListener; + private float mDownX; + private float mDownY; + private int mTouchSlop; + + private boolean mFollowTouch = true; // 是否跟随手指滑动 + private NavigatorHelper mNavigatorHelper = new NavigatorHelper(); + private Interpolator mStartInterpolator = new LinearInterpolator(); + + public ScaleCircleNavigator(Context context) { + super(context); + init(context); + } + + private void init(Context context) { + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + mMinRadius = UIUtil.dip2px(context, 3); + mMaxRadius = UIUtil.dip2px(context, 4); + mCircleSpacing = UIUtil.dip2px(context, 8); + mNavigatorHelper.setNavigatorScrollListener(this); + mNavigatorHelper.setSkimOver(true); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); + } + + private int measureWidth(int widthMeasureSpec) { + int mode = MeasureSpec.getMode(widthMeasureSpec); + int width = MeasureSpec.getSize(widthMeasureSpec); + int result = 0; + switch (mode) { + case MeasureSpec.EXACTLY: + result = width; + break; + case MeasureSpec.AT_MOST: + case MeasureSpec.UNSPECIFIED: + if (mCircleCount <= 0) { + result = getPaddingLeft() + getPaddingRight(); + } else { + result = (mCircleCount - 1) * mMinRadius * 2 + mMaxRadius * 2 + (mCircleCount - 1) * mCircleSpacing + getPaddingLeft() + getPaddingRight(); + } + break; + default: + break; + } + return result; + } + + private int measureHeight(int heightMeasureSpec) { + int mode = MeasureSpec.getMode(heightMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + int result = 0; + switch (mode) { + case MeasureSpec.EXACTLY: + result = height; + break; + case MeasureSpec.AT_MOST: + case MeasureSpec.UNSPECIFIED: + result = mMaxRadius * 2 + getPaddingTop() + getPaddingBottom(); + break; + default: + break; + } + return result; + } + + @Override + protected void onDraw(Canvas canvas) { + for (int i = 0, j = mCirclePoints.size(); i < j; i++) { + PointF point = mCirclePoints.get(i); + float radius = mCircleRadiusArray.get(i, (float) mMinRadius); + mPaint.setColor(ArgbEvaluatorHolder.eval((radius - mMinRadius) / (mMaxRadius - mMinRadius), mNormalCircleColor, mSelectedCircleColor)); + canvas.drawCircle(point.x, getHeight() / 2.0f, radius, mPaint); + } + } + + private void prepareCirclePoints() { + mCirclePoints.clear(); + if (mCircleCount > 0) { + int y = Math.round(getHeight() / 2.0f); + int centerSpacing = mMinRadius * 2 + mCircleSpacing; + int startX = mMaxRadius + getPaddingLeft(); + for (int i = 0; i < mCircleCount; i++) { + PointF pointF = new PointF(startX, y); + mCirclePoints.add(pointF); + startX += centerSpacing; + } + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (mTouchable) { + mDownX = x; + mDownY = y; + return true; + } + break; + case MotionEvent.ACTION_UP: + if (mCircleClickListener != null) { + if (Math.abs(x - mDownX) <= mTouchSlop && Math.abs(y - mDownY) <= mTouchSlop) { + float max = Float.MAX_VALUE; + int index = 0; + for (int i = 0; i < mCirclePoints.size(); i++) { + PointF pointF = mCirclePoints.get(i); + float offset = Math.abs(pointF.x - x); + if (offset < max) { + max = offset; + index = i; + } + } + mCircleClickListener.onClick(index); + } + } + break; + default: + break; + } + return super.onTouchEvent(event); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + mNavigatorHelper.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + + @Override + public void onPageSelected(int position) { + mNavigatorHelper.onPageSelected(position); + } + + @Override + public void onPageScrollStateChanged(int state) { + mNavigatorHelper.onPageScrollStateChanged(state); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + prepareCirclePoints(); + } + + @Override + public void notifyDataSetChanged() { + prepareCirclePoints(); + requestLayout(); + } + + @Override + public void onAttachToMagicIndicator() { + } + + @Override + public void onDetachFromMagicIndicator() { + } + + public void setMinRadius(int minRadius) { + mMinRadius = minRadius; + prepareCirclePoints(); + invalidate(); + } + + public void setMaxRadius(int maxRadius) { + mMaxRadius = maxRadius; + prepareCirclePoints(); + invalidate(); + } + + public void setNormalCircleColor(int normalCircleColor) { + mNormalCircleColor = normalCircleColor; + invalidate(); + } + + public void setSelectedCircleColor(int selectedCircleColor) { + mSelectedCircleColor = selectedCircleColor; + invalidate(); + } + + public void setCircleSpacing(int circleSpacing) { + mCircleSpacing = circleSpacing; + prepareCirclePoints(); + invalidate(); + } + + public void setStartInterpolator(Interpolator startInterpolator) { + mStartInterpolator = startInterpolator; + if (mStartInterpolator == null) { + mStartInterpolator = new LinearInterpolator(); + } + } + + public void setCircleCount(int count) { + mCircleCount = count; // 此处不调用invalidate,让外部调用notifyDataSetChanged + mNavigatorHelper.setTotalCount(mCircleCount); + } + + public void setTouchable(boolean touchable) { + mTouchable = touchable; + } + + public void setFollowTouch(boolean followTouch) { + mFollowTouch = followTouch; + } + + public void setSkimOver(boolean skimOver) { + mNavigatorHelper.setSkimOver(skimOver); + } + + public void setCircleClickListener(OnCircleClickListener circleClickListener) { + if (!mTouchable) { + mTouchable = true; + } + mCircleClickListener = circleClickListener; + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + if (mFollowTouch) { + float radius = mMinRadius + (mMaxRadius - mMinRadius) * mStartInterpolator.getInterpolation(enterPercent); + mCircleRadiusArray.put(index, radius); + invalidate(); + } + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + if (mFollowTouch) { + float radius = mMaxRadius + (mMinRadius - mMaxRadius) * mStartInterpolator.getInterpolation(leavePercent); + mCircleRadiusArray.put(index, radius); + invalidate(); + } + } + + @Override + public void onSelected(int index, int totalCount) { + if (!mFollowTouch) { + mCircleRadiusArray.put(index, (float) mMaxRadius); + invalidate(); + } + } + + @Override + public void onDeselected(int index, int totalCount) { + if (!mFollowTouch) { + mCircleRadiusArray.put(index, (float) mMinRadius); + invalidate(); + } + } + + public interface OnCircleClickListener { + void onClick(int index); + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/bean/PhotoInfo.java b/app/src/main/java/com/uiui/videoplayer/bean/PhotoInfo.java new file mode 100644 index 0000000..77bc914 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/bean/PhotoInfo.java @@ -0,0 +1,79 @@ +package com.uiui.videoplayer.bean; + +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; + +public class PhotoInfo implements Serializable, Parcelable { + private static final long serialVersionUID = 4205742067664126524L; + + String file_name; + String file; + long file_size; + + protected PhotoInfo(Parcel in) { + file_name = in.readString(); + file = in.readString(); + file_size = in.readLong(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public PhotoInfo createFromParcel(Parcel in) { + return new PhotoInfo(in); + } + + @Override + public PhotoInfo[] newArray(int size) { + return new PhotoInfo[size]; + } + }; + + public String getFile_name() { + return file_name; + } + + public void setFile_name(String file_name) { + this.file_name = file_name; + } + + public String getFile() { + return file; + } + + public void setFile(String file) { + this.file = file; + } + + public long getFile_size() { + return file_size; + } + + public void setFile_size(long file_size) { + this.file_size = file_size; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(file_name); + dest.writeString(file); + dest.writeLong(file_size); + } +} diff --git a/app/src/main/java/com/uiui/videoplayer/manager/RemoteManager.java b/app/src/main/java/com/uiui/videoplayer/manager/RemoteManager.java index 8ed474e..bd907d6 100644 --- a/app/src/main/java/com/uiui/videoplayer/manager/RemoteManager.java +++ b/app/src/main/java/com/uiui/videoplayer/manager/RemoteManager.java @@ -13,6 +13,7 @@ import android.util.Log; import com.tencent.mmkv.MMKV; import com.uiui.sn.IGetInfoInterface; import com.uiui.videoplayer.BuildConfig; +import com.uiui.videoplayer.config.CommonConfig; import java.util.HashSet; import java.util.Set; @@ -27,7 +28,7 @@ public class RemoteManager { @SuppressLint("StaticFieldLeak") private static RemoteManager sInstance; private Context mContext; - private MMKV mMMKV = MMKV.defaultMMKV(); + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); private IGetInfoInterface mIGetInfoInterface; private ServiceConnection mServiceConnection; @@ -117,7 +118,7 @@ public class RemoteManager { public String getSerial() { if (BuildConfig.DEBUG) { - return "T1030B128GB22435020359"; +// return "T1030B128GB22435020359"; } String sn = mMMKV.decodeString(serialKey, ""); Log.e(TAG, "sn: " + sn); diff --git a/app/src/main/java/com/uiui/videoplayer/network/NetInterfaceManager.java b/app/src/main/java/com/uiui/videoplayer/network/NetInterfaceManager.java index e23bbad..8061cb6 100644 --- a/app/src/main/java/com/uiui/videoplayer/network/NetInterfaceManager.java +++ b/app/src/main/java/com/uiui/videoplayer/network/NetInterfaceManager.java @@ -13,6 +13,7 @@ import com.tencent.mmkv.MMKV; import com.trello.rxlifecycle4.RxLifecycle; import com.trello.rxlifecycle4.android.ActivityEvent; import com.uiui.videoplayer.bean.BaseResponse; +import com.uiui.videoplayer.bean.PhotoInfo; import com.uiui.videoplayer.bean.VideoInfo; import com.uiui.videoplayer.bean.LocalVideoInfo; import com.uiui.videoplayer.config.CommonConfig; @@ -21,6 +22,7 @@ import com.uiui.videoplayer.gson.GsonUtils; import com.uiui.videoplayer.manager.ConnectManager; import com.uiui.videoplayer.manager.ConnectMode; import com.uiui.videoplayer.manager.RemoteManager; +import com.uiui.videoplayer.network.api.HomePhotoApi; import com.uiui.videoplayer.network.api.HomeVideoApi; import com.uiui.videoplayer.network.interceptor.RepeatRequestInterceptor; import com.uiui.videoplayer.utils.JGYUtils; @@ -156,6 +158,13 @@ public class NetInterfaceManager { .observeOn(AndroidSchedulers.mainThread()); } + public Observable>> getHomePhotoControl() { + return mRetrofit.create(HomePhotoApi.class) + .getHomePhoto(RemoteManager.getInstance().getSerial()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + public interface onVideoPathCallback { void setVideoList(ArrayList videoList); @@ -385,4 +394,115 @@ public class NetInterfaceManager { } }); } + + public interface onPhotoCallback { + void setPhotoList(ArrayList photoList); + + void onComplete(); + } + + 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 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 void getHomePhoto(BehaviorSubject lifecycle, onPhotoCallback callback) { + getHomePhotoControl() + .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) + .subscribe(getHomePhotoObserver(callback)); + } + + public void getHomePhoto(onPhotoCallback callback) { + getHomePhotoControl() + .subscribe(getHomePhotoObserver(callback)); + } + + public void getHomePhoto() { + getHomePhotoControl() + .subscribe(getHomePhotoObserver(null)); + } + + 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(); + } + } + }; + } + } diff --git a/app/src/main/java/com/uiui/videoplayer/network/UrlAddress.java b/app/src/main/java/com/uiui/videoplayer/network/UrlAddress.java index b61cc26..90bb098 100644 --- a/app/src/main/java/com/uiui/videoplayer/network/UrlAddress.java +++ b/app/src/main/java/com/uiui/videoplayer/network/UrlAddress.java @@ -4,7 +4,8 @@ public class UrlAddress { /*主页接口*/ public static final String ROOT_URL = "https://led.zuoyepad.com/android/"; - /*获取视频*/ + /*获取家庭视频*/ public static final String HOME_VIDEO ="File/getHomeVideo"; - + /*获取家庭照片*/ + public static final String HOME_PHOTO ="File/getHomePhoto"; } diff --git a/app/src/main/java/com/uiui/videoplayer/network/api/HomePhotoApi.java b/app/src/main/java/com/uiui/videoplayer/network/api/HomePhotoApi.java new file mode 100644 index 0000000..30a4497 --- /dev/null +++ b/app/src/main/java/com/uiui/videoplayer/network/api/HomePhotoApi.java @@ -0,0 +1,19 @@ +package com.uiui.videoplayer.network.api; + +import com.uiui.videoplayer.bean.BaseResponse; +import com.uiui.videoplayer.bean.PhotoInfo; +import com.uiui.videoplayer.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 HomePhotoApi { + @GET(UrlAddress.HOME_PHOTO) + Observable>> getHomePhoto( + @Query("sn") String sn + ); +} diff --git a/app/src/main/java/com/uiui/videoplayer/utils/VideoUtils.java b/app/src/main/java/com/uiui/videoplayer/utils/VideoUtils.java index 7d912c3..32f561c 100644 --- a/app/src/main/java/com/uiui/videoplayer/utils/VideoUtils.java +++ b/app/src/main/java/com/uiui/videoplayer/utils/VideoUtils.java @@ -1,14 +1,7 @@ package com.uiui.videoplayer.utils; -import android.content.Context; -import android.os.Environment; import android.util.Log; -import androidx.core.content.ContextCompat; - -import com.arialyy.aria.core.Aria; -import com.google.gson.JsonObject; - import java.io.File; import java.io.FileInputStream; import java.math.BigInteger; @@ -36,12 +29,25 @@ public class VideoUtils { return matches; } - private static final String[] extension = new String[]{ + private static final String[] video_extension = new String[]{ ".3gp", ".avi", ".flv", ".mkv", ".mov", ".mp4", ".webm" }; + private static final String[] picture_extension = new String[]{ + ".jgp", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".jpe" + }; + public static boolean isVideoFormat(String filePath) { - for (String s : extension) { + for (String s : video_extension) { + if (filePath.endsWith(s)) { + return true; + } + } + return false; + } + + public static boolean isPicFormat(String filePath) { + for (String s : picture_extension) { if (filePath.endsWith(s)) { return true; } diff --git a/app/src/main/res/drawable-hdpi/back.png b/app/src/main/res/drawable-hdpi/back.png new file mode 100644 index 0000000..519aedb Binary files /dev/null and b/app/src/main/res/drawable-hdpi/back.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_pic.png b/app/src/main/res/drawable-hdpi/icon_pic.png new file mode 100644 index 0000000..a5f56ee Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_pic.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_video.png b/app/src/main/res/drawable-hdpi/icon_video.png new file mode 100644 index 0000000..1da2e48 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_video.png differ diff --git a/app/src/main/res/drawable-hdpi/no_video_data.png b/app/src/main/res/drawable-hdpi/no_video_data.png new file mode 100644 index 0000000..a2f45fd Binary files /dev/null and b/app/src/main/res/drawable-hdpi/no_video_data.png differ diff --git a/app/src/main/res/drawable-hdpi/play.png b/app/src/main/res/drawable-hdpi/play.png new file mode 100644 index 0000000..a4d33c3 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/play.png differ diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d1..0000000 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml deleted file mode 100644 index ef24ea1..0000000 --- a/app/src/main/res/layout-land/activity_main.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_video.xml b/app/src/main/res/layout-land/activity_video.xml new file mode 100644 index 0000000..33ad4ca --- /dev/null +++ b/app/src/main/res/layout-land/activity_video.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-port/activity_main.xml b/app/src/main/res/layout-port/activity_main.xml deleted file mode 100644 index ef24ea1..0000000 --- a/app/src/main/res/layout-port/activity_main.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout-port/activity_video.xml b/app/src/main/res/layout-port/activity_video.xml new file mode 100644 index 0000000..33ad4ca --- /dev/null +++ b/app/src/main/res/layout-port/activity_video.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_gallery.xml b/app/src/main/res/layout/activity_gallery.xml new file mode 100644 index 0000000..888cea1 --- /dev/null +++ b/app/src/main/res/layout/activity_gallery.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..a9f7bfd --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_preview.xml b/app/src/main/res/layout/activity_preview.xml new file mode 100644 index 0000000..4fdd42f --- /dev/null +++ b/app/src/main/res/layout/activity_preview.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_pic.xml b/app/src/main/res/layout/item_pic.xml new file mode 100644 index 0000000..1379d2b --- /dev/null +++ b/app/src/main/res/layout/item_pic.xml @@ -0,0 +1,34 @@ + + + + + + + + \ 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 999ee77..21397b9 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 999ee77..21397b9 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 999ee77..21397b9 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 999ee77..21397b9 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 999ee77..21397b9 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/colors.xml b/app/src/main/res/values/colors.xml index 68563a9..adc2439 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -2,7 +2,9 @@ #6200EE #3700B3 - #03DAC5 + #4880ff + #f3f3f3 + #FFFFFF #000000 #333333 @@ -11,4 +13,144 @@ #d0d0d0 #9F9F9F + + #00000000 + #FFE2C59B + #FFFFFFF0 + #FFFFFFE0 + #FFFFFF00 + #FFFFFAFA + #FFFFFAF0 + #FFFFFACD + #FFFFF8DC + #FFFFF5EE + #FFFFF0F5 + #FFFFEFD5 + #FFFFEBCD + #FFFFE4E1 + #FFFFE4C4 + #FFFFE4B5 + #FFFFDEAD + #FFFFDAB9 + #FFFFD700 + #FFFFC0CB + #FFFFB6C1 + #FFFFA500 + #FFFFA07A + #FFFF8C00 + #FFFF7F50 + #FFFF69B4 + #FFFF6347 + #FFFF4500 + #FFFF1493 + #FFFF00FF + #FFFF0000 + #FFFDF5E6 + #FFFAFAD2 + #FFFAF0E6 + #FFFAEBD7 + #FFFA8072 + #FFF8F8FF + #FFF5FFFA + #FFF5F5F5 + #FFF5F5DC + #FFF5DEB3 + #FFF4A460 + #FFF0FFFF + #FFF0F8FF + #FFF0E68C + #FFF08080 + #FFEEE8AA + #FFEE82EE + #FFE9967A + #FFE6E6FA + #FFE0FFFF + #FFDEB887 + #FFDDA0DD + #FFDCDCDC + #FFDC143C + #FFDB7093 + #FFDAA520 + #FFDA70D6 + #FFD8BFD8 + #FFD3D3D3 + #FFD2B48C + #FFD2691E + #FFCD853F + #FFCD5C5C + #FFC71585 + #FFC0C0C0 + #FFBDB76B + #FFBC8F8F + #FFBA55D3 + #FFB8860B + #FFB22222 + #FFB0E0E6 + #FFB0C4DE + #FFAFEEEE + #FFADFF2F + #FFADD8E6 + #FFA9A9A9 + #FFA52A2A + #FFA0522D + #FF9932CC + #FF98FB98 + #FF9400D3 + #FF9370DB + #FF90EE90 + #FF8FBC8F + #FF8B4513 + #FF8B008B + #FF8B0000 + #FF8A2BE2 + #FF87CEFA + #FF87CEEB + #FF808080 + #FF808000 + #FF800080 + #FF800000 + #FF7FFFD4 + #FF7FFF00 + #FF7CFC00 + #FF7B68EE + #FF778899 + #FF708090 + #FF6B8E23 + #FF6A5ACD + #FF696969 + #FF66CDAA + #FF6495ED + #FF5F9EA0 + #FF556B2F + #FF4B0082 + #FF48D1CC + #FF483D8B + #FF4682B4 + #FF4169E1 + #FF40E0D0 + #FF3CB371 + #FF32CD32 + #FF2F4F4F + #FF2E8B57 + #FF228B22 + #FF20B2AA + #FF1E90FF + #FF191970 + #FF00FFFF + #FF00FF7F + #FF00FF00 + #FF00FA9A + #FF00CED1 + #FF00BFFF + #FF008B8B + #FF008080 + #FF008000 + #FF006400 + #FF0000FF + #FF0000CD + #FF00008B + #FF000080 + #FF2B2B2B + + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 1d8cfb3..c8050c6 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,13 +1,22 @@ - - + + + + + + + +