From 1e1a320dd70df5716b807233d8ffa81d3024bae2 Mon Sep 17 00:00:00 2001 From: okjack Date: Mon, 20 May 2024 20:53:20 +0800 Subject: [PATCH] device transmit --- .../java/com/fongmi/android/tv/Constant.java | 2 + .../android/tv/server/process/Action.java | 27 +++ .../tv/ui/dialog/TransmitActionDialog.java | 57 ++++++ .../android/tv/ui/dialog/TransmitDialog.java | 163 ++++++++++++++++++ .../tv/ui/fragment/SettingFragment.java | 10 +- .../mobile/res/drawable/ic_action_upload.xml | 10 ++ .../res/layout/dialog_transmit_action.xml | 27 +++ .../mobile/res/layout/fragment_setting.xml | 40 +++-- app/src/mobile/res/values-zh-rCN/strings.xml | 3 + app/src/mobile/res/values-zh-rTW/strings.xml | 3 + app/src/mobile/res/values/strings.xml | 3 + 11 files changed, 333 insertions(+), 12 deletions(-) create mode 100644 app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TransmitActionDialog.java create mode 100644 app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TransmitDialog.java create mode 100644 app/src/mobile/res/drawable/ic_action_upload.xml create mode 100644 app/src/mobile/res/layout/dialog_transmit_action.xml diff --git a/app/src/main/java/com/fongmi/android/tv/Constant.java b/app/src/main/java/com/fongmi/android/tv/Constant.java index 76e913d8b..f4422f0fd 100644 --- a/app/src/main/java/com/fongmi/android/tv/Constant.java +++ b/app/src/main/java/com/fongmi/android/tv/Constant.java @@ -23,6 +23,8 @@ public class Constant { public static final int TIMEOUT_PARSE_LIVE = 10 * 1000; //同步超時時間 public static final int TIMEOUT_SYNC = 2 * 1000; + //传送超時時間 + public static final int TIMEOUT_TRANSMIT = 30 * 1000; //搜尋線程數量 public static final int THREAD_POOL = 5; } diff --git a/app/src/main/java/com/fongmi/android/tv/server/process/Action.java b/app/src/main/java/com/fongmi/android/tv/server/process/Action.java index 138b56e79..ecaf7af92 100644 --- a/app/src/main/java/com/fongmi/android/tv/server/process/Action.java +++ b/app/src/main/java/com/fongmi/android/tv/server/process/Action.java @@ -19,6 +19,7 @@ import com.fongmi.android.tv.utils.Notify; import com.github.catvod.net.OkHttp; import com.github.catvod.utils.Path; +import java.io.File; import java.util.List; import java.util.Map; import java.util.Objects; @@ -58,6 +59,9 @@ public class Action implements Process { case "sync": onSync(params); return Nano.success(); + case "transmit": + onTransmit(params, files); + return Nano.success(); default: return Nano.error(null); } @@ -134,6 +138,14 @@ public class Action implements Process { } } + private void onTransmit(Map params, Map files) { + String type = params.get("type"); + switch (type) { + case "apk": + apk(params, files); + } + } + private void sendHistory(Device device, Map params) { try { String url = Objects.requireNonNullElse(params.get("url"), VodConfig.getUrl()); @@ -215,4 +227,19 @@ public class Action implements Process { } }; } + + private void apk(Map params, Map files) { + for (String k : files.keySet()) { + String fn = params.get(k); + File temp = new File(files.get(k)); + if (!temp.exists()) continue; + if (fn.toLowerCase().endsWith(".apk")) { + File apk = Path.cache(System.currentTimeMillis() + "-" + fn); + Path.copy(temp, apk); + FileUtil.openFile(apk); + } else { + temp.delete(); + } + } + } } diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TransmitActionDialog.java b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TransmitActionDialog.java new file mode 100644 index 000000000..4f15c0281 --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TransmitActionDialog.java @@ -0,0 +1,57 @@ +package com.fongmi.android.tv.ui.dialog; + +import android.app.Activity; +import android.view.LayoutInflater; + +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.Fragment; + + +import com.fongmi.android.tv.databinding.DialogTransmitActionBinding; +import com.fongmi.android.tv.utils.FileChooser; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +public class TransmitActionDialog { + + private final Fragment fragment; + private DialogTransmitActionBinding binding; + private AlertDialog dialog; + + + public static TransmitActionDialog create(Fragment fragment) { + return new TransmitActionDialog(fragment); + } + + public TransmitActionDialog(Fragment fragment) { + this.fragment = fragment; + init(fragment.getActivity()); + } + + private void init(Activity activity) { + this.binding = DialogTransmitActionBinding.inflate(LayoutInflater.from(activity)); + this.dialog = new MaterialAlertDialogBuilder(activity).setView(binding.getRoot()).create(); + initEvent(); + } + + private void initEvent() { + this.binding.apk.setOnClickListener(v-> setAction("apk")); + } + + public void show() { + setDialog(); + } + + private void setDialog() { + dialog.getWindow().setDimAmount(0); + dialog.show(); + } + + private void setAction(String action) { + if ("apk".equals(action)) FileChooser.from(fragment).show(); + dialog.dismiss(); + } + + + + +} diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TransmitDialog.java b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TransmitDialog.java new file mode 100644 index 000000000..d63a9c4d1 --- /dev/null +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TransmitDialog.java @@ -0,0 +1,163 @@ +package com.fongmi.android.tv.ui.dialog; + +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.viewbinding.ViewBinding; + +import com.fongmi.android.tv.App; +import com.fongmi.android.tv.Constant; +import com.fongmi.android.tv.R; +import com.fongmi.android.tv.bean.Device; +import com.fongmi.android.tv.cast.ScanEvent; +import com.fongmi.android.tv.cast.ScanTask; +import com.fongmi.android.tv.databinding.DialogDeviceBinding; +import com.fongmi.android.tv.impl.Callback; +import com.fongmi.android.tv.ui.activity.ScanActivity; +import com.fongmi.android.tv.ui.adapter.DeviceAdapter; +import com.fongmi.android.tv.utils.Notify; +import com.github.catvod.net.OkHttp; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import okhttp3.Call; +import okhttp3.MediaType; +import okhttp3.MultipartBody; +import okhttp3.OkHttpClient; +import okhttp3.RequestBody; +import okhttp3.Response; + +public class TransmitDialog extends BaseDialog implements DeviceAdapter.OnClickListener, ScanTask.Listener { + + private final MultipartBody.Builder body; + private final OkHttpClient client; + private DialogDeviceBinding binding; + private DeviceAdapter adapter; + private String type; + + public static TransmitDialog create() { + return new TransmitDialog(); + } + + public TransmitDialog() { + client = OkHttp.client(Constant.TIMEOUT_TRANSMIT); + body = new MultipartBody.Builder(); + } + + public TransmitDialog apk(String path) { + type = "apk"; + File file = new File(path); + MediaType mediaType = MediaType.parse("multipart/form-data"); + RequestBody requestBody = RequestBody.create(mediaType, file); + body.setType(MultipartBody.FORM); + body.addFormDataPart("name", file.getName()); + body.addFormDataPart("files-0", file.getName(), requestBody); + return this; + } + + public void show(FragmentActivity activity) { + for (Fragment f : activity.getSupportFragmentManager().getFragments()) if (f instanceof BottomSheetDialogFragment) return; + show(activity.getSupportFragmentManager(), null); + } + + @Override + protected ViewBinding getBinding(@NonNull LayoutInflater inflater, @Nullable ViewGroup container) { + return binding = DialogDeviceBinding.inflate(inflater, container, false); + } + + @Override + protected void initView() { + EventBus.getDefault().register(this); + setRecyclerView(); + getDevice(); + } + + @Override + protected void initEvent() { + binding.scan.setOnClickListener(v -> onScan()); + binding.refresh.setOnClickListener(v -> onRefresh()); + } + + private void setRecyclerView() { + binding.recycler.setHasFixedSize(true); + binding.recycler.setAdapter(adapter = new DeviceAdapter(this)); + } + + private void getDevice() { + adapter.addAll(Device.getAll()); + if (adapter.getItemCount() == 0) App.post(this::onRefresh, 1000); + } + + private void onRefresh() { + ScanTask.create(this).start(adapter.getIps()); + adapter.clear(); + } + + private void onScan() { + ScanActivity.start(getActivity()); + } + + private void onSuccess() { + dismiss(); + Notify.dismiss(); + } + + private void onError() { + Notify.show(R.string.device_offline); + Notify.dismiss(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onScanEvent(ScanEvent event) { + ScanTask.create(this).start(event.getAddress()); + } + + @Override + public void onFind(List devices) { + if (devices.size() > 0) adapter.addAll(devices); + } + + @Override + public void onItemClick(Device item) { + Notify.progress(getContext()); + OkHttp.newCall(client, item.getIp().concat("/action?do=transmit&type=").concat(type), body.build()).enqueue(getCallback()); + } + + @Override + public boolean onLongClick(Device item) { + Notify.progress(getContext()); + OkHttp.newCall(client, item.getIp().concat("/action?do=transmit&type=").concat(type), body.build()).enqueue(getCallback()); + return true; + } + + private Callback getCallback() { + return new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + App.post(() -> onSuccess()); + } + + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + App.post(() -> onError()); + } + }; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + EventBus.getDefault().unregister(this); + } +} diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingFragment.java b/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingFragment.java index 77d6697f4..e2ac6fa5c 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingFragment.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingFragment.java @@ -38,6 +38,8 @@ import com.fongmi.android.tv.ui.dialog.HistoryDialog; import com.fongmi.android.tv.ui.dialog.LiveDialog; import com.fongmi.android.tv.ui.dialog.ProxyDialog; import com.fongmi.android.tv.ui.dialog.SiteDialog; +import com.fongmi.android.tv.ui.dialog.TransmitActionDialog; +import com.fongmi.android.tv.ui.dialog.TransmitDialog; import com.fongmi.android.tv.utils.FileChooser; import com.fongmi.android.tv.utils.FileUtil; import com.fongmi.android.tv.utils.Notify; @@ -112,6 +114,7 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit mBinding.proxy.setOnClickListener(this::onProxy); mBinding.cache.setOnClickListener(this::onCache); mBinding.cache.setOnLongClickListener(this::onCacheLongClick); + mBinding.transmit.setOnClickListener(this::onTransmit); mBinding.backup.setOnClickListener(this::onBackup); mBinding.restore.setOnClickListener(this::onRestore); mBinding.player.setOnClickListener(this::onPlayer); @@ -350,6 +353,10 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit FileChooser.from(this).show(); } + private void onTransmit(View view) { + TransmitActionDialog.create(this).show(); + } + private void initConfig() { WallConfig.get().init(); LiveConfig.get().init().load(); @@ -399,7 +406,8 @@ public class SettingFragment extends BaseFragment implements ConfigCallback, Sit super.onActivityResult(requestCode, resultCode, data); if (resultCode != Activity.RESULT_OK || requestCode != FileChooser.REQUEST_PICK_FILE) return; String path = FileChooser.getPathFromUri(getContext(), data.getData()); - if (path.endsWith(AppDatabase.BACKUP_SUFFIX)) restore(new File(path)); + if (path.toLowerCase().endsWith(".apk")) TransmitDialog.create().apk(path).show(getActivity()); + else if (path.endsWith(AppDatabase.BACKUP_SUFFIX)) restore(new File(path)); else setConfig(Config.find("file:/" + path.replace(Path.rootPath(), ""), type)); } } diff --git a/app/src/mobile/res/drawable/ic_action_upload.xml b/app/src/mobile/res/drawable/ic_action_upload.xml new file mode 100644 index 000000000..c2c350e70 --- /dev/null +++ b/app/src/mobile/res/drawable/ic_action_upload.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/src/mobile/res/layout/dialog_transmit_action.xml b/app/src/mobile/res/layout/dialog_transmit_action.xml new file mode 100644 index 000000000..98bc4c6c3 --- /dev/null +++ b/app/src/mobile/res/layout/dialog_transmit_action.xml @@ -0,0 +1,27 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/mobile/res/layout/fragment_setting.xml b/app/src/mobile/res/layout/fragment_setting.xml index 7b8048d93..d4f13e5de 100644 --- a/app/src/mobile/res/layout/fragment_setting.xml +++ b/app/src/mobile/res/layout/fragment_setting.xml @@ -13,17 +13,35 @@ app:elevation="0dp" app:liftOnScrollColor="@color/transparent"> - + + + + + + diff --git a/app/src/mobile/res/values-zh-rCN/strings.xml b/app/src/mobile/res/values-zh-rCN/strings.xml index 936f31c9b..2adadec8b 100644 --- a/app/src/mobile/res/values-zh-rCN/strings.xml +++ b/app/src/mobile/res/values-zh-rCN/strings.xml @@ -40,6 +40,9 @@ 延长 5 分钟 取消定时器 + + 推送APK + 已于主萤幕新增捷径。 diff --git a/app/src/mobile/res/values-zh-rTW/strings.xml b/app/src/mobile/res/values-zh-rTW/strings.xml index c39ef2632..63a297261 100644 --- a/app/src/mobile/res/values-zh-rTW/strings.xml +++ b/app/src/mobile/res/values-zh-rTW/strings.xml @@ -40,6 +40,9 @@ 延長 5 分鐘 取消定時器 + + 推送APK + 已於主螢幕新增捷徑。 diff --git a/app/src/mobile/res/values/strings.xml b/app/src/mobile/res/values/strings.xml index 8cf93148f..cf483b474 100644 --- a/app/src/mobile/res/values/strings.xml +++ b/app/src/mobile/res/values/strings.xml @@ -40,6 +40,9 @@ Add 5 minutes Cancel timer + + Push apk + Shortcut has been added.