Merge branch 'master' into legacy

legacy
sh123 2022-07-24 14:29:25 +03:00
commit 931e8acf6b
17 zmienionych plików z 229 dodań i 66 usunięć

Wyświetl plik

@ -60,6 +60,31 @@ public class Position {
return Math.sqrt(distance);
}
public static double distanceTo(double lat1, double lon1, double alt1, double lat2, double lon2, double alt2) {
Position pos1 = new Position();
pos1.latitude = lat1;
pos1.longitude = lon1;
pos1.altitudeMeters = alt1;
Position pos2 = new Position();
pos2.latitude = lat2;
pos2.longitude = lon2;
pos2.altitudeMeters = alt2;
return pos1.distanceTo(pos2);
}
public static String bearing(double lat1, double lon1, double lat2, double lon2) {
double radians = Math.atan2(lat2 - lat1, lon2 - lon1);
double degrees = radians * (180.0 / Math.PI);
String[] dirNames = {"N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"};
int dirIndex = (int) Math.round(degrees / 45);
if (dirIndex < 0) {
dirIndex = dirIndex + 8;
};
return dirNames[dirIndex];
}
public PositionItem toPositionItem(boolean isTransmit) {
PositionItem positionItem = new PositionItem();
positionItem.setTimestampEpoch(System.currentTimeMillis());

Wyświetl plik

@ -1,6 +1,7 @@
package com.radio.codec2talkie.storage.log;
import androidx.room.Entity;
import androidx.room.Index;
import androidx.room.PrimaryKey;
@Entity

Wyświetl plik

@ -17,6 +17,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.radio.codec2talkie.R;
import com.radio.codec2talkie.storage.log.group.LogItemGroupAdapter;
import com.radio.codec2talkie.storage.position.PositionItemViewModel;
public class LogItemActivity extends AppCompatActivity {
@ -32,6 +33,14 @@ public class LogItemActivity extends AppCompatActivity {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) actionBar.setDisplayHomeAsUpEnabled(true);
// get group name to decide if filtering should be enabled
Bundle bundle = getIntent().getExtras();
_groupName = null;
if (bundle != null) {
_groupName = (String)bundle.get("groupName");
}
// view models
_logItemViewModel = new ViewModelProvider(this).get(LogItemViewModel.class);
_positionItemViewModel = new ViewModelProvider(this).get(PositionItemViewModel.class);
@ -39,7 +48,8 @@ public class LogItemActivity extends AppCompatActivity {
RecyclerView logItemRecyclerView = findViewById(R.id.log_item_recyclerview);
logItemRecyclerView.setHasFixedSize(true);
final LogItemAdapter adapter = new LogItemAdapter(new LogItemAdapter.LogItemDiff());
// log lines list adapter
final LogItemAdapter adapter = new LogItemAdapter(new LogItemAdapter.LogItemDiff(), _groupName == null);
logItemRecyclerView.setAdapter(adapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
logItemRecyclerView.setLayoutManager(linearLayoutManager);
@ -49,6 +59,7 @@ public class LogItemActivity extends AppCompatActivity {
RecyclerView logItemGroupRecyclerView = findViewById(R.id.log_item_group_recyclerview);
logItemGroupRecyclerView.setHasFixedSize(true);
// groups adapter
final LogItemGroupAdapter adapterGroup = new LogItemGroupAdapter(new LogItemGroupAdapter.LogItemGroupDiff());
adapterGroup.setClickListener(v -> {
TextView itemView = v.findViewById(R.id.log_view_group_item_title);
@ -64,11 +75,6 @@ public class LogItemActivity extends AppCompatActivity {
_logItemViewModel.getGroups().observe(this, adapterGroup::submitList);
// launch with filter if group name is provided
Bundle bundle = getIntent().getExtras();
_groupName = null;
if (bundle != null) {
_groupName = (String)bundle.get("groupName");
}
if (_groupName == null) {
logItemGroupRecyclerView.setVisibility(View.GONE);
findViewById(R.id.log_item_textview).setVisibility(View.GONE);

Wyświetl plik

@ -8,14 +8,17 @@ import androidx.recyclerview.widget.ListAdapter;
public class LogItemAdapter extends ListAdapter<LogItem, LogItemHolder> {
public LogItemAdapter(@NonNull DiffUtil.ItemCallback<LogItem> diffCallback) {
private final boolean _isClickable;
public LogItemAdapter(@NonNull DiffUtil.ItemCallback<LogItem> diffCallback, boolean isClickable) {
super(diffCallback);
_isClickable = isClickable;
}
@NonNull
@Override
public LogItemHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return LogItemHolder.create(parent);
return LogItemHolder.create(parent, _isClickable);
}
@Override

Wyświetl plik

@ -6,7 +6,7 @@ import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import com.radio.codec2talkie.storage.message.MessageItem;
import com.radio.codec2talkie.storage.log.group.LogItemGroup;
import java.util.List;
@ -16,8 +16,24 @@ public interface LogItemDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
void insertLogItem(LogItem logItem);
@Query("SELECT srcCallsign from LogItem GROUP BY srcCallsign")
LiveData<List<String>> getGroups();
@Query("SELECT pos.timestampEpoch AS timestampEpoch, " +
"pos.srcCallsign AS srcCallsign, " +
"pos.dstCallsign AS dstCallsign, " +
"pos.latitude AS latitude, " +
"pos.longitude AS longitude, " +
"pos.maidenHead AS maidenHead, " +
"pos.altitudeMeters AS altitudeMeters, " +
"pos.bearingDegrees AS bearingDegrees, " +
"pos.speedMetersPerSecond AS speedMetersPerSecond, " +
"pos.status AS status, " +
"pos.comment AS comment, " +
"pos.symbolCode AS symbolCode, " +
"pos.privacyLevel AS privacyLevel, " +
"MAX(pos.timestampEpoch)" +
"FROM LogItem log " +
"LEFT OUTER JOIN PositionItem pos ON (log.srcCallsign = pos.srcCallsign)" +
"GROUP BY log.srcCallsign")
LiveData<List<LogItemGroup>> getGroups();
@Query("SELECT * FROM LogItem ORDER by timestampEpoch DESC")
LiveData<List<LogItem>> getAllLogItems();

Wyświetl plik

@ -1,33 +0,0 @@
package com.radio.codec2talkie.storage.log;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.radio.codec2talkie.R;
public class LogItemGroupHolder extends RecyclerView.ViewHolder {
private final TextView _logItemViewTitle;
private final TextView _logItemViewMessage;
private LogItemGroupHolder(View itemView) {
super(itemView);
_logItemViewTitle = itemView.findViewById(R.id.log_view_group_item_title);
_logItemViewMessage = itemView.findViewById(R.id.log_view_group_item_message);
}
public void bind(String groupName) {
_logItemViewTitle.setText(groupName);
}
static LogItemGroupHolder create(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.activity_log_view_group_item, parent, false);
return new LogItemGroupHolder(view);
}
}

Wyświetl plik

@ -9,7 +9,6 @@ import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.radio.codec2talkie.R;
import com.radio.codec2talkie.storage.message.MessageItemActivity;
import com.radio.codec2talkie.tools.DateTools;
import com.radio.codec2talkie.tools.TextTools;
@ -18,11 +17,13 @@ public class LogItemHolder extends RecyclerView.ViewHolder implements View.OnCli
private final TextView _logItemViewTitle;
private final TextView _logItemViewMessage;
private String _srcCallsign;
private final boolean _isClickable;
private LogItemHolder(View itemView) {
private LogItemHolder(View itemView, boolean isClickable) {
super(itemView);
_logItemViewTitle = itemView.findViewById(R.id.log_view_item_title);
_logItemViewMessage = itemView.findViewById(R.id.log_view_item_message);
_isClickable = isClickable;
itemView.setOnClickListener(this);
}
@ -35,14 +36,15 @@ public class LogItemHolder extends RecyclerView.ViewHolder implements View.OnCli
_logItemViewMessage.setText(TextTools.addZeroWidthSpaces(text));
}
static LogItemHolder create(ViewGroup parent) {
static LogItemHolder create(ViewGroup parent, boolean isClickable) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.activity_log_view_item, parent, false);
return new LogItemHolder(view);
return new LogItemHolder(view, isClickable);
}
@Override
public void onClick(View v) {
if (!_isClickable) return;
Intent logItemIntent = new Intent(v.getContext(), LogItemActivity.class);
logItemIntent.putExtra("groupName", _srcCallsign);
v.getContext().startActivity(logItemIntent);

Wyświetl plik

@ -5,6 +5,7 @@ import android.app.Application;
import androidx.lifecycle.LiveData;
import com.radio.codec2talkie.storage.AppDatabase;
import com.radio.codec2talkie.storage.log.group.LogItemGroup;
import java.util.List;
@ -13,7 +14,7 @@ public class LogItemRepository {
private final LogItemDao _logItemDao;
private final LiveData<List<LogItem>> _logItemLiveData;
private LiveData<List<LogItem>> _logItemGroupLiveData;
private final LiveData<List<String>> _logItemGroups;
private final LiveData<List<LogItemGroup>> _logItemGroups;
public LogItemRepository(Application application) {
AppDatabase appDatabase = AppDatabase.getDatabase(application);
@ -26,7 +27,7 @@ public class LogItemRepository {
return _logItemLiveData;
}
public LiveData<List<String>> getGroups() { return _logItemGroups; }
public LiveData<List<LogItemGroup>> getGroups() { return _logItemGroups; }
public LiveData<List<LogItem>> getLogItems(String groupName) {
return _logItemDao.getLogItems(groupName);

Wyświetl plik

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import com.radio.codec2talkie.storage.message.MessageItem;
import com.radio.codec2talkie.storage.log.group.LogItemGroup;
import java.util.List;
@ -15,7 +15,7 @@ public class LogItemViewModel extends AndroidViewModel {
private final LogItemRepository _logItemRepository;
private final LiveData<List<LogItem>> _logItemLiveData;
private LiveData<List<LogItem>> _logItemGroupLiveData;
private final LiveData<List<String>> _logItemGroups;
private final LiveData<List<LogItemGroup>> _logItemGroups;
public LogItemViewModel(@NonNull Application application) {
super(application);
@ -32,7 +32,7 @@ public class LogItemViewModel extends AndroidViewModel {
return _logItemRepository.getLogItems(groupName);
}
public LiveData<List<String>> getGroups() { return _logItemGroups; }
public LiveData<List<LogItemGroup>> getGroups() { return _logItemGroups; }
public void deleteAllLogItems() { _logItemRepository.deleteAllLogItems(); }

Wyświetl plik

@ -0,0 +1,69 @@
package com.radio.codec2talkie.storage.log.group;
public class LogItemGroup {
private long timestampEpoch;
private String srcCallsign;
public String dstCallsign;
private String maidenHead;
public double latitude;
public double longitude;
public double altitudeMeters;
public double bearingDegrees;
public double speedMetersPerSecond;
public String status;
public String comment;
public String symbolCode;
public int privacyLevel;
public long getTimestampEpoch() { return timestampEpoch; }
public String getSrcCallsign() { return srcCallsign; }
public String getDstCallsign() { return dstCallsign; }
public double getLatitude() { return latitude; }
public double getLongitude() { return longitude; }
public String getMaidenHead() { return maidenHead; }
public double getAltitudeMeters() { return altitudeMeters; }
public double getBearingDegrees() { return bearingDegrees; }
public double getSpeedMetersPerSecond() { return speedMetersPerSecond; };
public String getStatus() { return status; }
public String getComment() { return comment; };
public String getSymbolCode() { return symbolCode; }
public int getPrivacyLevel() { return privacyLevel; }
public void setTimestampEpoch(long timestampEpoch) { this.timestampEpoch = timestampEpoch; }
public void setSrcCallsign(String srcCallsign) { this.srcCallsign = srcCallsign; }
public void setMaidenHead(String maidenHead) { this.maidenHead = maidenHead; }
public void setDstCallsign(String dstCallsign) { this.dstCallsign = dstCallsign; }
public void setLatitude(double latitude) { this.latitude = latitude; }
public void setLongitude(double longitude) { this.longitude = longitude; }
public void setAltitudeMeters(double altitudeMeters) { this.altitudeMeters = altitudeMeters; }
public void setBearingDegrees(double bearingDegrees) { this.bearingDegrees = bearingDegrees; }
public void setSpeedMetersPerSecond(double speedMetersPerSecond) { this.speedMetersPerSecond = speedMetersPerSecond; }
public void setStatus(String status) { this.status = status; }
public void setComment(String comment) { this.comment = comment; }
public void setSymbolCode(String symbolCode) { this.symbolCode = symbolCode; }
public void setPrivacyLevel(int privacyLevel) { this.privacyLevel = privacyLevel; }
}

Wyświetl plik

@ -1,4 +1,4 @@
package com.radio.codec2talkie.storage.log;
package com.radio.codec2talkie.storage.log.group;
import android.view.View;
import android.view.ViewGroup;
@ -7,11 +7,11 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
public class LogItemGroupAdapter extends ListAdapter<String, LogItemGroupHolder> {
public class LogItemGroupAdapter extends ListAdapter<LogItemGroup, LogItemGroupHolder> {
private View.OnClickListener _clickListener;
public LogItemGroupAdapter(@NonNull DiffUtil.ItemCallback<String> diffCallback) {
public LogItemGroupAdapter(@NonNull DiffUtil.ItemCallback<LogItemGroup> diffCallback) {
super(diffCallback);
}
@ -27,21 +27,21 @@ public class LogItemGroupAdapter extends ListAdapter<String, LogItemGroupHolder>
@Override
public void onBindViewHolder(LogItemGroupHolder holder, int position) {
String current = getItem(position);
LogItemGroup current = getItem(position);
holder.itemView.setOnClickListener(_clickListener);
holder.bind(current);
}
static class LogItemGroupDiff extends DiffUtil.ItemCallback<String> {
public static class LogItemGroupDiff extends DiffUtil.ItemCallback<LogItemGroup> {
@Override
public boolean areItemsTheSame(@NonNull String oldItem, @NonNull String newItem) {
return oldItem.equals(newItem);
public boolean areItemsTheSame(@NonNull LogItemGroup oldItem, @NonNull LogItemGroup newItem) {
return oldItem == newItem;
}
@Override
public boolean areContentsTheSame(@NonNull String oldItem, @NonNull String newItem) {
return oldItem.equals(newItem);
public boolean areContentsTheSame(@NonNull LogItemGroup oldItem, @NonNull LogItemGroup newItem) {
return oldItem.getSrcCallsign().equals(newItem.getSrcCallsign());
}
}
}

Wyświetl plik

@ -0,0 +1,60 @@
package com.radio.codec2talkie.storage.log.group;
import android.annotation.SuppressLint;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.radio.codec2talkie.R;
import com.radio.codec2talkie.protocol.position.Position;
import com.radio.codec2talkie.tools.UnitTools;
import java.util.Locale;
public class LogItemGroupHolder extends RecyclerView.ViewHolder {
private final TextView _logItemViewTitle;
private final TextView _logItemViewDistance;
private final TextView _logItemViewMessage;
private final LocationManager _locationManager;
private LogItemGroupHolder(View itemView) {
super(itemView);
_logItemViewTitle = itemView.findViewById(R.id.log_view_group_item_title);
_logItemViewDistance = itemView.findViewById(R.id.log_view_group_item_distance);
_logItemViewMessage = itemView.findViewById(R.id.log_view_group_item_message);
_locationManager = (LocationManager) itemView.getContext().getSystemService(Context.LOCATION_SERVICE);
}
public void bind(LogItemGroup group) {
@SuppressLint("MissingPermission") Location loc = _locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
double distanceKm = Position.distanceTo(loc.getLatitude(), loc.getLongitude(), loc.getAltitude(),
group.getLatitude(), group.getLongitude(), group.getAltitudeMeters()) / 1000.0;
String bearing = Position.bearing(loc.getLatitude(), loc.getLongitude(), group.getLatitude(), group.getLongitude());
_logItemViewTitle.setText(String.format(Locale.US, "%s",
group.getSrcCallsign()));
_logItemViewDistance.setText(String.format(Locale.US, "%s %.1f km", bearing, distanceKm));
_logItemViewMessage.setText(String.format(Locale.US, "%s %s %.4f %.4f %03d° %03dkm/h %04dm %s %s",
group.getSymbolCode(),
group.getMaidenHead(),
group.getLatitude(),
group.getLongitude(),
(int)group.getBearingDegrees(),
UnitTools.metersPerSecondToKilometersPerHour((int)group.getSpeedMetersPerSecond()),
(int)group.getAltitudeMeters(),
group.getStatus(),
group.getComment()));
}
static LogItemGroupHolder create(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.activity_log_view_group_item, parent, false);
return new LogItemGroupHolder(view);
}
}

Wyświetl plik

@ -69,7 +69,7 @@ public class PositionItem {
public void setIsTransmit(boolean isTransmit) { this.isTransmit = isTransmit; }
public void setSrcCallsign(String srcCallsign) { this.srcCallsign = srcCallsign; }
public void setSrcCallsign(String srcCallsign) { this.srcCallsign = srcCallsign; }
public void setDstCallsign(String dstCallsign) { this.dstCallsign = dstCallsign; }

Wyświetl plik

@ -77,4 +77,8 @@ public class UnitTools {
}
public static long millisToSeconds(long milliseconds) { return milliseconds / 1000L; }
public static int metersPerSecondToKilometersPerHour(int speedMetersPerSecond) {
return (int) (speedMetersPerSecond * 3.6);
}
}

Wyświetl plik

@ -45,7 +45,6 @@ public class Periodic implements Tracker {
Log.e(TAG, "No permissions for location access");
return;
}
_locationManager.requestSingleUpdate(
LocationManager.GPS_PROVIDER,
this::sendLocation,

Wyświetl plik

@ -9,18 +9,27 @@
<TextView
android:id="@+id/log_view_group_item_title"
style="@style/log_item_title"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/log_view_group_item_distance"
style="@style/log_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/log_view_group_item_message"
style="@style/log_item_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lines="1"
android:lines="3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/log_view_group_item_title" />

Wyświetl plik

@ -13,6 +13,7 @@
<item name="android:layout_marginBottom">4dp</item>
<item name="android:paddingLeft">4dp</item>
<item name="android:background">@android:color/white</item>
<item name="android:fontFamily">monospace</item>
<item name="android:textColor">@color/grey</item>
<item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Small</item>
</style>