package com.bg7yoz.ft8cn.ui; /** * 呼叫界面。 * @author BGY70Z * @date 2023-03-20 */ import android.annotation.SuppressLint; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.widget.AdapterView; import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.Observer; import androidx.navigation.NavController; import androidx.navigation.Navigation; import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.bg7yoz.ft8cn.Ft8Message; import com.bg7yoz.ft8cn.GeneralVariables; import com.bg7yoz.ft8cn.MainViewModel; import com.bg7yoz.ft8cn.R; import com.bg7yoz.ft8cn.databinding.FragmentMyCallingBinding; import com.bg7yoz.ft8cn.ft8transmit.FunctionOfTransmit; import com.bg7yoz.ft8cn.ft8transmit.TransmitCallsign; import com.bg7yoz.ft8cn.timer.UtcTimer; import java.util.ArrayList; public class MyCallingFragment extends Fragment { private static final String TAG = "MyCallingFragment"; private FragmentMyCallingBinding binding; private MainViewModel mainViewModel; private RecyclerView transmitRecycleView; private CallingListAdapter transmitCallListAdapter; private FunctionOrderSpinnerAdapter functionOrderSpinnerAdapter; static { System.loadLibrary("ft8cn"); } /** * 马上对发起者呼叫 * * @param message 消息 */ //@RequiresApi(api = Build.VERSION_CODES.N) private void doCallNow(Ft8Message message) { mainViewModel.addFollowCallsign(message.getCallsignFrom()); if (!mainViewModel.ft8TransmitSignal.isActivated()) { mainViewModel.ft8TransmitSignal.setActivated(true); GeneralVariables.transmitMessages.add(message);//把消息添加到关注列表中 } //呼叫发启者 mainViewModel.ft8TransmitSignal.setTransmit(message.getFromCallTransmitCallsign() , 1, message.extraInfo); mainViewModel.ft8TransmitSignal.transmitNow(); GeneralVariables.resetLaunchSupervision();//复位自动监管 } /** * 菜单选项 * * @param item 菜单 * @return 是否选择 */ //@RequiresApi(api = Build.VERSION_CODES.N) @Override public boolean onContextItemSelected(@NonNull MenuItem item) { //Ft8Message ft8Message = (Ft8Message) item.getActionView().getTag(); int position = (int) item.getActionView().getTag(); Ft8Message ft8Message = transmitCallListAdapter.getMessageByPosition(position); if (ft8Message == null) return super.onContextItemSelected(item); ; GeneralVariables.resetLaunchSupervision();//复位自动监管 switch (item.getItemId()) { case 1://时序与发送者相反!!! Log.d(TAG, "呼叫:" + ft8Message.getCallsignTo()); if (!mainViewModel.ft8TransmitSignal.isActivated()) { mainViewModel.ft8TransmitSignal.setActivated(true); } mainViewModel.ft8TransmitSignal.setTransmit(ft8Message.getToCallTransmitCallsign() , 1, ft8Message.extraInfo); mainViewModel.ft8TransmitSignal.transmitNow(); break; case 3: Log.d(TAG, "呼叫:" + ft8Message.getCallsignFrom()); doCallNow(ft8Message); //if (!mainViewModel.ft8TransmitSignal.isActivated()) { // mainViewModel.ft8TransmitSignal.setActivated(true); // } // mainViewModel.ft8TransmitSignal.setTransmit(ft8Message.getFromCallTransmitCallsign() // , 1, ft8Message.extraInfo); //mainViewModel.ft8TransmitSignal.transmitNow(); break; case 4://回复 Log.d(TAG, "回复:" + ft8Message.getCallsignFrom()); mainViewModel.addFollowCallsign(ft8Message.getCallsignFrom()); if (!mainViewModel.ft8TransmitSignal.isActivated()) { mainViewModel.ft8TransmitSignal.setActivated(true); GeneralVariables.transmitMessages.add(ft8Message);//把消息添加到关注列表中 } //呼叫发启者 mainViewModel.ft8TransmitSignal.setTransmit(ft8Message.getFromCallTransmitCallsign() , -1, ft8Message.extraInfo); mainViewModel.ft8TransmitSignal.transmitNow(); break; case 5://to 的QRZ showQrzFragment(ft8Message.getCallsignTo()); break; case 6://from 的QRZ showQrzFragment(ft8Message.getCallsignFrom()); break; case 7://查to的日志 navigateToLogFragment(ft8Message.getCallsignTo()); break; case 8://查from的日志 navigateToLogFragment(ft8Message.getCallsignFrom()); break; } return super.onContextItemSelected(item); } /** * 跳转到日志查询界面 * @param callsign 呼号 */ private void navigateToLogFragment(String callsign){ mainViewModel.queryKey=callsign;//把呼号作为关键字提交 NavController navController = Navigation.findNavController(requireActivity() , R.id.fragmentContainerView); navController.navigate(R.id.action_menu_nav_mycalling_to_menu_nav_history);//跳转到日志 } /** * 查询QRZ信息 * * @param callsign 呼号 */ private void showQrzFragment(String callsign) { NavHostFragment navHostFragment = (NavHostFragment) requireActivity().getSupportFragmentManager().findFragmentById(R.id.fragmentContainerView); assert navHostFragment != null;//断言不为空 Bundle bundle = new Bundle(); bundle.putString(QRZ_Fragment.CALLSIGN_PARAM, callsign); navHostFragment.getNavController().navigate(R.id.QRZ_Fragment, bundle); } @SuppressLint("NotifyDataSetChanged") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mainViewModel = MainViewModel.getInstance(this); binding = FragmentMyCallingBinding.inflate(inflater, container, false); //当横屏时显示频谱图 if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { binding.messageSpectrumView.run(mainViewModel, this); } //发射消息的列表 functionOrderSpinnerAdapter = new FunctionOrderSpinnerAdapter(requireContext(), mainViewModel); binding.functionOrderSpinner.setAdapter(functionOrderSpinnerAdapter); functionOrderSpinnerAdapter.notifyDataSetChanged(); //关注的消息列表 transmitRecycleView = binding.transmitRecycleView; transmitCallListAdapter = new CallingListAdapter(this.getContext(), mainViewModel , GeneralVariables.transmitMessages, CallingListAdapter.ShowMode.MY_CALLING); transmitRecycleView.setLayoutManager(new LinearLayoutManager(requireContext())); transmitRecycleView.setAdapter(transmitCallListAdapter); transmitCallListAdapter.notifyDataSetChanged(); //设置消息列表滑动,用于快速呼叫 initRecyclerViewAction(); //菜单 requireActivity().registerForContextMenu(transmitRecycleView); //显示UTC时间 mainViewModel.timerSec.observe(getViewLifecycleOwner(), new Observer() { @Override public void onChanged(Long aLong) { binding.timerTextView.setText(UtcTimer.getTimeStr(aLong)); } }); //显示发射频率 GeneralVariables.mutableBaseFrequency.observe(getViewLifecycleOwner(), new Observer() { @SuppressLint("DefaultLocale") @Override public void onChanged(Float aFloat) { binding.baseFrequencyTextView.setText(String.format( GeneralVariables.getStringFromResource(R.string.sound_frequency_is), aFloat)); } }); //观察发射状态按钮的变化 Observer transmittingObserver = new Observer() { @Override public void onChanged(Boolean aBoolean) { if (mainViewModel.ft8TransmitSignal.isTransmitting()) { binding.setTransmitImageButton.setImageResource(R.drawable.ic_baseline_send_red_48); binding.setTransmitImageButton.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.view_blink)); } else { //录音对象也要处于启动状态才可以有发射的状态 if (mainViewModel.ft8TransmitSignal.isActivated() && mainViewModel.hamRecorder.isRunning()) { binding.setTransmitImageButton.setImageResource(R.drawable.ic_baseline_send_white_48); } else { binding.setTransmitImageButton.setImageResource(R.drawable.ic_baseline_cancel_schedule_send_off); } binding.setTransmitImageButton.setAnimation(null); } //暂停播放按键 if (mainViewModel.ft8TransmitSignal.isTransmitting()) { binding.pauseTransmittingImageButton.setImageResource(R.drawable.ic_baseline_pause_circle_outline_24); binding.pauseTransmittingImageButton.setVisibility(View.VISIBLE); } else { binding.pauseTransmittingImageButton.setVisibility(View.GONE); binding.pauseTransmittingImageButton.setImageResource(R.drawable.ic_baseline_pause_disable_circle_outline_24); } } }; //显示发射状态 mainViewModel.ft8TransmitSignal.mutableIsTransmitting.observe(getViewLifecycleOwner(), transmittingObserver); mainViewModel.ft8TransmitSignal.mutableIsActivated.observe(getViewLifecycleOwner(), transmittingObserver); //暂停按钮 binding.pauseTransmittingImageButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mainViewModel.ft8TransmitSignal.setTransmitting(false); GeneralVariables.resetLaunchSupervision();//复位自动监管 } }); //监视命令程序 mainViewModel.ft8TransmitSignal.mutableFunctions.observe(getViewLifecycleOwner() , new Observer>() { @Override public void onChanged(ArrayList functionOfTransmits) { functionOrderSpinnerAdapter.notifyDataSetChanged(); } }); //观察指令序号的变化 mainViewModel.ft8TransmitSignal.mutableFunctionOrder.observe(getViewLifecycleOwner(), new Observer() { @Override public void onChanged(Integer integer) { if (mainViewModel.ft8TransmitSignal.functionList.size() < 6) { binding.functionOrderSpinner.setSelection(0); } else { binding.functionOrderSpinner.setSelection(integer - 1); } } }); //设置当指令序号被选择的事件 binding.functionOrderSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView adapterView, View view, int i, long l) { if (mainViewModel.ft8TransmitSignal.functionList.size() > 1) { mainViewModel.ft8TransmitSignal.setCurrentFunctionOrder(i + 1); } } @Override public void onNothingSelected(AdapterView adapterView) { } }); //显示当前目标呼号 mainViewModel.ft8TransmitSignal.mutableToCallsign.observe(getViewLifecycleOwner(), new Observer() { @Override public void onChanged(TransmitCallsign transmitCallsign) { if (GeneralVariables.toModifier!=null) { binding.toCallsignTextView.setText(String.format( GeneralVariables.getStringFromResource(R.string.target_callsign) , transmitCallsign.callsign+" "+GeneralVariables.toModifier)); }else { binding.toCallsignTextView.setText(String.format( GeneralVariables.getStringFromResource(R.string.target_callsign) , transmitCallsign.callsign)); } } }); //显示当前发射的时序 mainViewModel.ft8TransmitSignal.mutableSequential.observe(getViewLifecycleOwner(), new Observer() { @SuppressLint("DefaultLocale") @Override public void onChanged(Integer integer) { binding.transmittingSequentialTextView.setText( String.format(GeneralVariables.getStringFromResource(R.string.transmission_sequence) , integer)); } }); //设置发射按钮 binding.setTransmitImageButton.setOnClickListener(new View.OnClickListener() { //@RequiresApi(api = Build.VERSION_CODES.N) @Override public void onClick(View view) { //如果 if (!mainViewModel.ft8TransmitSignal.isActivated()) { mainViewModel.ft8TransmitSignal.restTransmitting(); } mainViewModel.ft8TransmitSignal.setActivated(!mainViewModel.ft8TransmitSignal.isActivated()); GeneralVariables.resetLaunchSupervision();//复位自动监管 } }); //观察传输消息列表的变化 //mainViewModel.mutableTransmitMessages.observe(getViewLifecycleOwner(), new Observer>() { mainViewModel.mutableTransmitMessagesCount.observe(getViewLifecycleOwner(), new Observer() { @SuppressLint("DefaultLocale") @Override public void onChanged(Integer count) { binding.decoderCounterTextView.setText(String.format( GeneralVariables.getStringFromResource(R.string.message_count) , GeneralVariables.transmitMessages.size())); //if (count == 0) { transmitCallListAdapter.notifyDataSetChanged(); //} else { // transmitCallListAdapter.notifyItemInserted( // GeneralVariables.transmitMessages.size() - count); //} //当列表下部稍微多出一些,自动上移 if (transmitRecycleView.computeVerticalScrollRange() - transmitRecycleView.computeVerticalScrollExtent() - transmitRecycleView.computeVerticalScrollOffset() < 300) { transmitRecycleView.scrollToPosition(transmitCallListAdapter.getItemCount() - 1); } } }); //清除传输消息列表 binding.clearMycallListImageButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mainViewModel.clearTransmittingMessage(); } }); //复位到CQ按键 binding.resetToCQImageView.setOnClickListener(new View.OnClickListener() { //@RequiresApi(api = Build.VERSION_CODES.N) @Override public void onClick(View view) { mainViewModel.ft8TransmitSignal.resetToCQ(); GeneralVariables.resetLaunchSupervision();//复位自动监管 } }); //自由文本输入框的限定操作 binding.transFreeTextEdit.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void afterTextChanged(Editable editable) { mainViewModel.ft8TransmitSignal.setFreeText(editable.toString().toUpperCase()); } }); binding.resetToCQImageView.setLongClickable(true); binding.resetToCQImageView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { mainViewModel.setTransmitIsFreeText(!mainViewModel.getTransitIsFreeText()); showFreeTextEdit(); return true; } }); binding.mycallToolsBar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { GeneralVariables.simpleCallItemMode=!GeneralVariables.simpleCallItemMode; transmitRecycleView.setAdapter(transmitCallListAdapter); transmitCallListAdapter.notifyDataSetChanged(); transmitRecycleView.scrollToPosition(transmitCallListAdapter.getItemCount() - 1); if (GeneralVariables.simpleCallItemMode){ ToastMessage.show(GeneralVariables.getStringFromResource(R.string.message_list_simple_mode)); }else { ToastMessage.show(GeneralVariables.getStringFromResource(R.string.message_list_standard_mode)); } } }); showFreeTextEdit(); return binding.getRoot(); } private void showFreeTextEdit() { if (mainViewModel.getTransitIsFreeText()) { binding.transFreeTextEdit.setVisibility(View.VISIBLE); binding.functionOrderSpinner.setVisibility(View.GONE); } else { binding.transFreeTextEdit.setVisibility(View.GONE); binding.functionOrderSpinner.setVisibility(View.VISIBLE); } } /** * 设置列表滑动动作 */ private void initRecyclerViewAction() { new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.ANIMATION_TYPE_DRAG , ItemTouchHelper.START | ItemTouchHelper.END) { @Override public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder , @NonNull RecyclerView.ViewHolder target) { return false; } //@RequiresApi(api = Build.VERSION_CODES.N) @SuppressLint("NotifyDataSetChanged") @Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { if (direction == ItemTouchHelper.START) { Ft8Message message = transmitCallListAdapter.getMessageByViewHolder(viewHolder); if (message != null) { //呼叫的目标不能是自己 if (!message.getCallsignFrom().equals("<...>") //&& !message.getCallsignFrom().equals(GeneralVariables.myCallsign) && !GeneralVariables.checkIsMyCallsign(message.getCallsignFrom()) && !(message.i3 == 0 && message.n3 == 0)) { doCallNow(message); } } transmitCallListAdapter.notifyItemChanged(viewHolder.getAdapterPosition()); } if (direction == ItemTouchHelper.END) {//删除 transmitCallListAdapter.deleteMessage(viewHolder.getAdapterPosition()); transmitCallListAdapter.notifyItemRemoved(viewHolder.getAdapterPosition()); } } @Override public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); //制作呼叫背景的图标显示 Drawable callIcon = ContextCompat.getDrawable(requireActivity(), R.drawable.ic_baseline_send_red_48); Drawable delIcon = ContextCompat.getDrawable(requireActivity(), R.drawable.log_item_delete_icon); Drawable background = new ColorDrawable(Color.LTGRAY); Ft8Message message = transmitCallListAdapter.getMessageByViewHolder(viewHolder); if (message == null) { return; } if (message.getCallsignFrom().equals("<...>")) {//如果属于不能呼叫的消息,就不显示图标 return; } Drawable icon; if (dX > 0) { icon = delIcon; } else { icon = callIcon; } View itemView = viewHolder.itemView; int iconMargin = (itemView.getHeight() - icon.getIntrinsicHeight()) / 2; int iconLeft, iconRight, iconTop, iconBottom; int backTop, backBottom, backLeft, backRight; backTop = itemView.getTop(); backBottom = itemView.getBottom(); iconTop = itemView.getTop() + (itemView.getHeight() - icon.getIntrinsicHeight()) / 2; iconBottom = iconTop + icon.getIntrinsicHeight(); if (dX > 0) { backLeft = itemView.getLeft(); backRight = itemView.getLeft() + (int) dX; background.setBounds(backLeft, backTop, backRight, backBottom); iconLeft = itemView.getLeft() + iconMargin; iconRight = iconLeft + icon.getIntrinsicWidth(); icon.setBounds(iconLeft, iconTop, iconRight, iconBottom); } else if (dX < 0) { backRight = itemView.getRight(); backLeft = itemView.getRight() + (int) dX; background.setBounds(backLeft, backTop, backRight, backBottom); iconRight = itemView.getRight() - iconMargin; iconLeft = iconRight - icon.getIntrinsicWidth(); icon.setBounds(iconLeft, iconTop, iconRight, iconBottom); } else { background.setBounds(0, 0, 0, 0); icon.setBounds(0, 0, 0, 0); } background.draw(c); icon.draw(c); } }).attachToRecyclerView(binding.transmitRecycleView); } }