Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/src/main/java/io/netbird/client/PeersStateListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.netbird.client;

public interface PeersStateListener {
void onPeersChanged(long totalPeers);
}
22 changes: 22 additions & 0 deletions app/src/main/java/io/netbird/client/PeersStateListenerAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.netbird.client;

import org.jetbrains.annotations.NotNull;

public class PeersStateListenerAdapter extends StateListenerAdapter {
private PeersStateListener listener;

public PeersStateListenerAdapter(@NotNull PeersStateListener listener) {
this.listener = listener;
}

public void clearListener() {
this.listener = null;
}

@Override
public void onPeersListChanged(long totalPeers) {
if (listener == null) return;

listener.onPeersChanged(totalPeers);
}
}
44 changes: 44 additions & 0 deletions app/src/main/java/io/netbird/client/StateListenerAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.netbird.client;

public abstract class StateListenerAdapter implements StateListener {

@Override
public void onEngineStarted() {

}

@Override
public void onEngineStopped() {

}

@Override
public void onAddressChanged(String fqdn, String ip) {

}

@Override
public void onConnected() {

}

@Override
public void onConnecting() {

}

@Override
public void onDisconnected() {

}

@Override
public void onDisconnecting() {

}

@Override
public void onPeersListChanged(long totalPeers) {

}
}
78 changes: 45 additions & 33 deletions app/src/main/java/io/netbird/client/ui/home/PeersFragment.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
package io.netbird.client.ui.home;

import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.text.TextWatcher;
import android.text.Editable;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.PopupMenu;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

Expand All @@ -26,16 +25,16 @@

import io.netbird.client.R;
import io.netbird.client.ServiceAccessor;
import io.netbird.client.StateListenerRegistry;
import io.netbird.client.databinding.FragmentPeersBinding;
import io.netbird.gomobile.android.PeerInfo;
import io.netbird.gomobile.android.PeerInfoArray;

public class PeersFragment extends Fragment {

private FragmentPeersBinding binding;
private ServiceAccessor serviceAccessor;
private RecyclerView peersListView;

private StateListenerRegistry stateListenerRegistry;
private PeersFragmentViewModel model;
private final List<Peer> peers = new ArrayList<>();
private static final String ARG_IS_RUNNING_ON_TV = "isRunningOnTV";

@Override
Expand All @@ -46,6 +45,12 @@ public void onAttach(@NonNull Context context) {
} else {
throw new RuntimeException(context + " must implement ServiceAccessor");
}

if (context instanceof StateListenerRegistry) {
stateListenerRegistry = (StateListenerRegistry) context;
} else {
throw new RuntimeException(context + " must implement StateListenerRegistry");
}
}

@Override
Expand All @@ -58,6 +63,10 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);

model = new ViewModelProvider(this, PeersFragmentViewModel.getFactory(serviceAccessor))
.get(PeersFragmentViewModel.class);
stateListenerRegistry.registerServiceStateListener(model.getStateListener());

boolean isRunningOnTV = false;
if (getArguments() != null) {
isRunningOnTV = getArguments().getBoolean(ARG_IS_RUNNING_ON_TV, false);
Expand All @@ -75,15 +84,22 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
ZeroPeerView.setupLearnWhyClick(binding.zeroPeerLayout, requireContext());
}

PeerInfoArray peersInfo = serviceAccessor.getPeersList();
ZeroPeerView.updateVisibility(binding.zeroPeerLayout, binding.peersList, peersInfo.size() > 0);
PeersAdapter adapter = new PeersAdapter(peers);

RecyclerView peersRecyclerView = binding.peersRecyclerView;
peersRecyclerView.setAdapter(adapter);
peersRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));

model.getUiState().observe(getViewLifecycleOwner(), uiState -> {
peers.clear();
peers.addAll(uiState.getPeers());

updatePeersCounter(peers);

List<Peer> peerList = peersInfoToPeersList(peersInfo);
updatePeerCount(peersInfo);
peersListView = binding.peersRecyclerView;
peersListView.setLayoutManager(new LinearLayoutManager(requireContext()));
PeersAdapter adapter = new PeersAdapter(peerList);
peersListView.setAdapter(adapter);
ZeroPeerView.updateVisibility(binding.zeroPeerLayout, binding.peersList, !peers.isEmpty());
adapter.notifyDataSetChanged();
adapter.filterBySearchQuery(binding.searchView.getText().toString());
});

binding.searchView.clearFocus();
binding.searchView.addTextChangedListener(new TextWatcher() {
Expand Down Expand Up @@ -127,37 +143,33 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat

@Override
public void onDetach() {
super.onDetach();
stateListenerRegistry = null;
serviceAccessor = null;

super.onDetach();
Comment thread
doromaraujo marked this conversation as resolved.
}

@Override
public void onDestroyView() {
super.onDestroyView();
if (model != null) {
stateListenerRegistry.unregisterServiceStateListener(model.getStateListener());
}
binding = null;
super.onDestroyView();
}
Comment thread
doromaraujo marked this conversation as resolved.

private List<Peer> peersInfoToPeersList(PeerInfoArray peersInfo) {
List<Peer> peerList = new ArrayList<>();
for (int i = 0; i < peersInfo.size(); i++) {
PeerInfo peerInfo = peersInfo.get(i);
Status status = Status.fromString(peerInfo.getConnStatus());
peerList.add(new Peer(status, peerInfo.getIP(), peerInfo.getFQDN()));
}
return peerList;
}
private void updatePeersCounter(List<Peer> peers) {
TextView textPeersCount = binding.textOpenPanel;

private void updatePeerCount(PeerInfoArray peersInfo) {
int connected = 0;
for (int i = 0; i < peersInfo.size(); i++) {
PeerInfo peer = peersInfo.get(i);
if (peer.getConnStatus().equalsIgnoreCase(Status.CONNECTED.toString())) {

for (var peer : peers) {
if (peer.getStatus() == Status.CONNECTED) {
connected++;
}
}

TextView textPeersCount = binding.textOpenPanel;
String text = getString(R.string.peers_connected, connected, peersInfo.size());
String text = getString(R.string.peers_connected, connected, peers.size());
textPeersCount.post(() ->
textPeersCount.setText(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY))
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.netbird.client.ui.home;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class PeersFragmentUiState {
private final List<Peer> peers;

public PeersFragmentUiState(List<Peer> peers) {
this.peers = new ArrayList<>(peers);
}

public List<Peer> getPeers() {
return Collections.unmodifiableList(peers);
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.netbird.client.ui.home;

import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;

import java.util.ArrayList;
import java.util.List;

import io.netbird.client.PeersStateListener;
import io.netbird.client.PeersStateListenerAdapter;
import io.netbird.client.ServiceAccessor;
import io.netbird.client.StateListener;
import io.netbird.gomobile.android.PeerInfo;
import io.netbird.gomobile.android.PeerInfoArray;

public class PeersFragmentViewModel extends ViewModel implements PeersStateListener {
private final PeersStateListenerAdapter peersAdapter;
private final ServiceAccessor serviceAccessor;

private final MutableLiveData<PeersFragmentUiState> uiState =
new MutableLiveData<>(new PeersFragmentUiState(new ArrayList<>()));

public PeersFragmentViewModel(ServiceAccessor serviceAccessor) {
peersAdapter = new PeersStateListenerAdapter(this);
this.serviceAccessor = serviceAccessor;
}

public static ViewModelProvider.Factory getFactory(ServiceAccessor serviceAccessor) {
return new ViewModelProvider.Factory() {
@NonNull
@Override
@SuppressWarnings("unchecked")
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (modelClass.isAssignableFrom(PeersFragmentViewModel.class)) {
return (T) new PeersFragmentViewModel(serviceAccessor);
}
throw new IllegalArgumentException("Unknown ViewModel class");
}
};
}

private List<Peer> getPeers(PeerInfoArray peersInfo) {
List<Peer> peers = new ArrayList<>();
PeerInfo peerInfo;
String connStatus;
Status status;

for (int i = 0; i < peersInfo.size(); i++) {
peerInfo = peersInfo.get(i);

if (peerInfo == null) {
continue;
}

connStatus = peerInfo.getConnStatus();
if (connStatus == null) {
continue;
}

status = Status.fromString(connStatus);
peers.add(new Peer(status, peerInfo.getIP(), peerInfo.getFQDN()));
}
return peers;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

public LiveData<PeersFragmentUiState> getUiState() {
return uiState;
}

public StateListener getStateListener() {
return this.peersAdapter;
}

@Override
protected void onCleared() {
peersAdapter.clearListener();
super.onCleared();
}

@Override
public void onPeersChanged(long totalPeers) {
var peers = getPeers(serviceAccessor.getPeersList());
this.uiState.postValue(new PeersFragmentUiState(peers));
}
}
6 changes: 4 additions & 2 deletions app/src/main/java/io/netbird/client/ui/home/Status.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.netbird.client.ui.home;


import java.util.Locale;

public enum Status {
IDLE,
CONNECTING,
Expand All @@ -25,15 +27,15 @@ public static Status fromString(String status) {
throw new IllegalArgumentException("Status string cannot be null");
}

switch (status.toLowerCase()) {
switch (status.toLowerCase(Locale.ROOT)) {
case "idle":
return IDLE;
case "connecting":
return CONNECTING;
case "connected":
return CONNECTED;
default:
throw new IllegalArgumentException("Unknown status: " + status);
throw new IllegalArgumentException("Unknown status: " + status.toLowerCase(Locale.ROOT));
}
}
}
Expand Down
Loading