device transmit

pull/446/head
okjack 2 years ago
parent 4b2b34f07b
commit 1e1a320dd7
  1. 2
      app/src/main/java/com/fongmi/android/tv/Constant.java
  2. 27
      app/src/main/java/com/fongmi/android/tv/server/process/Action.java
  3. 57
      app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TransmitActionDialog.java
  4. 163
      app/src/mobile/java/com/fongmi/android/tv/ui/dialog/TransmitDialog.java
  5. 10
      app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingFragment.java
  6. 10
      app/src/mobile/res/drawable/ic_action_upload.xml
  7. 27
      app/src/mobile/res/layout/dialog_transmit_action.xml
  8. 40
      app/src/mobile/res/layout/fragment_setting.xml
  9. 3
      app/src/mobile/res/values-zh-rCN/strings.xml
  10. 3
      app/src/mobile/res/values-zh-rTW/strings.xml
  11. 3
      app/src/mobile/res/values/strings.xml

@ -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;
}

@ -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<String, String> params, Map<String, String> files) {
String type = params.get("type");
switch (type) {
case "apk":
apk(params, files);
}
}
private void sendHistory(Device device, Map<String, String> params) {
try {
String url = Objects.requireNonNullElse(params.get("url"), VodConfig.getUrl());
@ -215,4 +227,19 @@ public class Action implements Process {
}
};
}
private void apk(Map<String, String> params, Map<String, String> 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();
}
}
}
}

@ -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();
}
}

@ -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<Device> 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);
}
}

@ -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));
}
}

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M440,640L440,314L336,418L280,360L480,160L680,360L624,418L520,314L520,640L440,640ZM240,800Q207,800 183.5,776.5Q160,753 160,720L160,600L240,600L240,720Q240,720 240,720Q240,720 240,720L720,720Q720,720 720,720Q720,720 720,720L720,600L800,600L800,720Q800,753 776.5,776.5Q753,800 720,800L240,800Z"/>
</vector>

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/apk"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="marquee"
android:singleLine="true"
android:textColor="@color/control"
android:textSize="14sp"
android:text="@string/transmit_apk" />
</LinearLayout>
</LinearLayout>

@ -13,17 +13,35 @@
app:elevation="0dp"
app:liftOnScrollColor="@color/transparent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:text="@string/nav_setting"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
app:layout_scrollFlags="scroll|enterAlways" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:text="@string/nav_setting"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
app:layout_scrollFlags="scroll|enterAlways" />
<ImageView
android:id="@+id/transmit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:padding="7dp"
android:scaleType="fitCenter"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_action_upload" />
</LinearLayout>
</com.google.android.material.appbar.AppBarLayout>

@ -40,6 +40,9 @@
<string name="timer_delay">延长 5 分钟</string>
<string name="timer_cancel">取消定时器</string>
<!-- Transmit -->
<string name="transmit_apk">推送APK</string>
<!-- Hint -->
<string name="shortcut"> 已于主萤幕新增捷径。</string>

@ -40,6 +40,9 @@
<string name="timer_delay">延長 5 分鐘</string>
<string name="timer_cancel">取消定時器</string>
<!-- Transmit -->
<string name="transmit_apk">推送APK</string>
<!-- Hint -->
<string name="shortcut"> 已於主螢幕新增捷徑。</string>

@ -40,6 +40,9 @@
<string name="timer_delay">Add 5 minutes</string>
<string name="timer_cancel">Cancel timer</string>
<!-- Transmit -->
<string name="transmit_apk">Push apk</string>
<!-- Hint -->
<string name="shortcut">Shortcut has been added.</string>

Loading…
Cancel
Save