Reviewed-on: https://git.bubblev.org/bubblev/bubble-droid/pulls/13pull/14/head
@@ -1,20 +1,16 @@ | |||||
package com.wireguard.android.activity; | package com.wireguard.android.activity; | ||||
import android.content.Context; | |||||
import android.os.Bundle; | import android.os.Bundle; | ||||
import android.os.Handler; | import android.os.Handler; | ||||
import android.view.Gravity; | import android.view.Gravity; | ||||
import android.view.LayoutInflater; | import android.view.LayoutInflater; | ||||
import android.view.View; | import android.view.View; | ||||
import android.view.ViewGroup; | |||||
import android.widget.Toast; | import android.widget.Toast; | ||||
import com.wireguard.android.R; | import com.wireguard.android.R; | ||||
import com.wireguard.android.fragment.ErrorDialogFragment; | |||||
import com.wireguard.android.fragment.LoadingDialogFragment; | import com.wireguard.android.fragment.LoadingDialogFragment; | ||||
import java.net.ConnectException; | |||||
import java.net.UnknownHostException; | |||||
import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||
import androidx.appcompat.app.AppCompatActivity; | import androidx.appcompat.app.AppCompatActivity; | ||||
import androidx.lifecycle.Lifecycle; | import androidx.lifecycle.Lifecycle; | ||||
@@ -23,10 +19,12 @@ public class BaseActivityBubble extends AppCompatActivity { | |||||
public static final String LOADING_TAG = "loading_tag"; | public static final String LOADING_TAG = "loading_tag"; | ||||
public static final String NO_CONNECTION_TAG = "no_connection_tag"; | public static final String NO_CONNECTION_TAG = "no_connection_tag"; | ||||
public static final String ERROR_TAG = "error_tag"; | |||||
public static final String RATE_TAG = "rate tag"; | public static final String RATE_TAG = "rate tag"; | ||||
private final long LOADER_DELAY = 1000; | private final long LOADER_DELAY = 1000; | ||||
private LoadingDialogFragment loadingDialog; | private LoadingDialogFragment loadingDialog; | ||||
private ErrorDialogFragment errorDialog; | |||||
private boolean showDialog = true; | private boolean showDialog = true; | ||||
@Override | @Override | ||||
@@ -80,4 +78,12 @@ public class BaseActivityBubble extends AppCompatActivity { | |||||
toast.show(); | toast.show(); | ||||
} | } | ||||
public void showErrorDialog(String message){ | |||||
errorDialog = ErrorDialogFragment.newInstance(); | |||||
final Bundle bundle = new Bundle(); | |||||
bundle.putString("message",message); | |||||
errorDialog.setArguments(bundle); | |||||
getSupportFragmentManager().beginTransaction().add(errorDialog,ERROR_TAG).commitAllowingStateLoss(); | |||||
} | |||||
} | } |
@@ -200,8 +200,9 @@ public class LoginActivity extends BaseActivityBubble { | |||||
if(userStatusResource.message.equals(NO_INTERNET_CONNECTION)){ | if(userStatusResource.message.equals(NO_INTERNET_CONNECTION)){ | ||||
showNetworkNotAvailableMessage(); | showNetworkNotAvailableMessage(); | ||||
} | } | ||||
Toast.makeText(LoginActivity.this, getString(R.string.login_failed), Toast.LENGTH_SHORT).show(); | |||||
Log.d("TAG", "Error"); | |||||
else { | |||||
showErrorDialog(userStatusResource.message); | |||||
} | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,72 @@ | |||||
package com.wireguard.android.fragment; | |||||
import android.content.Intent; | |||||
import android.net.Uri; | |||||
import android.os.Bundle; | |||||
import android.view.LayoutInflater; | |||||
import android.view.View; | |||||
import android.view.View.OnClickListener; | |||||
import android.view.ViewGroup; | |||||
import com.wireguard.android.R; | |||||
import androidx.annotation.NonNull; | |||||
import androidx.annotation.Nullable; | |||||
import androidx.appcompat.widget.AppCompatButton; | |||||
import androidx.fragment.app.DialogFragment; | |||||
public class ErrorDialogFragment extends DialogFragment { | |||||
private AppCompatButton contactSupportButton; | |||||
public static ErrorDialogFragment newInstance() { | |||||
ErrorDialogFragment fragment = new ErrorDialogFragment(); | |||||
Bundle args = new Bundle(); | |||||
fragment.setArguments(args); | |||||
return fragment; | |||||
} | |||||
@Override | |||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, | |||||
Bundle savedInstanceState) { | |||||
return inflater.inflate(R.layout.error_layout, container, false); | |||||
} | |||||
@Override | |||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { | |||||
super.onViewCreated(view, savedInstanceState); | |||||
Bundle bundle = getArguments(); | |||||
String message = ""; | |||||
if(bundle!=null){ | |||||
message = bundle.getString("message"); | |||||
} | |||||
initUI(view,message); | |||||
} | |||||
private void initUI(View view, String message) { | |||||
initViews(view); | |||||
initListeners(message); | |||||
} | |||||
private void initViews(View view) { | |||||
contactSupportButton = view.findViewById(R.id.contactSupportButton); | |||||
} | |||||
private void initListeners(String message) { | |||||
contactSupportButton.setOnClickListener(new OnClickListener() { | |||||
@Override public void onClick(final View v) { | |||||
sendEmail(message); | |||||
} | |||||
}); | |||||
} | |||||
private void sendEmail(String message){ | |||||
final Intent send = new Intent(Intent.ACTION_SENDTO); | |||||
final String uriText = "mailto:" + Uri.encode("support@getbubblenow.com") + | |||||
"?subject=" + Uri.encode("Error Message") + | |||||
"&body=" + Uri.encode(message); | |||||
final Uri uri = Uri.parse(uriText); | |||||
send.setData(uri); | |||||
startActivity(Intent.createChooser(send, "Send Error")); | |||||
} | |||||
} |
@@ -33,6 +33,7 @@ import java.io.InputStream; | |||||
import java.net.ConnectException; | import java.net.ConnectException; | ||||
import java.net.UnknownHostException; | import java.net.UnknownHostException; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Arrays; | |||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Scanner; | import java.util.Scanner; | ||||
@@ -49,10 +50,15 @@ import io.reactivex.disposables.CompositeDisposable; | |||||
import io.reactivex.disposables.Disposable; | import io.reactivex.disposables.Disposable; | ||||
import io.reactivex.schedulers.Schedulers; | import io.reactivex.schedulers.Schedulers; | ||||
import okhttp3.Callback; | import okhttp3.Callback; | ||||
import okhttp3.Headers; | |||||
import okhttp3.HttpUrl; | |||||
import okhttp3.OkHttpClient; | import okhttp3.OkHttpClient; | ||||
import okhttp3.Request; | import okhttp3.Request; | ||||
import okhttp3.RequestBody; | |||||
import okhttp3.Response; | import okhttp3.Response; | ||||
import okio.Buffer; | |||||
import retrofit2.Call; | import retrofit2.Call; | ||||
import retrofit2.HttpException; | |||||
public class DataRepository { | public class DataRepository { | ||||
private static volatile DataRepository instance; | private static volatile DataRepository instance; | ||||
@@ -468,5 +474,29 @@ public class DataRepository { | |||||
if( throwable instanceof UnknownHostException || throwable instanceof ConnectException){ | if( throwable instanceof UnknownHostException || throwable instanceof ConnectException){ | ||||
liveData.postMutableLiveData(StatusResource.error(NO_INTERNET_CONNECTION)); | liveData.postMutableLiveData(StatusResource.error(NO_INTERNET_CONNECTION)); | ||||
} | } | ||||
if(throwable instanceof HttpException){ | |||||
if(((HttpException) throwable).code() == 500){ | |||||
final String requestURL = ((HttpException) throwable).response().raw().request().url().toString(); | |||||
final String requestMethod = ((HttpException) throwable).response().raw().request().method(); | |||||
final String requestBody = bodyToString(((HttpException) throwable).response().raw().request()); | |||||
final String stackTrace = Arrays.toString(throwable.getStackTrace()); | |||||
final String message = "URL:" + requestURL + '\n' + | |||||
"BODY:" + requestBody + '\n' + | |||||
"METHOD:" + requestMethod + '\n' + | |||||
"STACK_TRACE:" + stackTrace; | |||||
liveData.postMutableLiveData(StatusResource.error(message)); | |||||
} | |||||
} | |||||
} | |||||
private String bodyToString(final Request request){ | |||||
try { | |||||
final Request copy = request.newBuilder().build(); | |||||
final Buffer buffer = new Buffer(); | |||||
copy.body().writeTo(buffer); | |||||
return buffer.readUtf8(); | |||||
} catch (final IOException e) { | |||||
return "did not work"; | |||||
} | |||||
} | } | ||||
} | } |
@@ -0,0 +1,11 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"> | |||||
<item> | |||||
<shape android:shape="rectangle"> | |||||
<gradient android:endColor="#701C79" android:startColor="#BC36BD" android:centerColor="#8F2695"/> | |||||
<corners android:radius="100dp" /> | |||||
</shape> | |||||
</item> | |||||
</selector> |
@@ -0,0 +1,79 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
xmlns:tools="http://schemas.android.com/tools" | |||||
android:layout_width="match_parent" | |||||
android:background="@color/white" | |||||
android:layout_height="match_parent"> | |||||
<TextView | |||||
android:id="@+id/textView" | |||||
android:layout_width="wrap_content" | |||||
android:layout_height="wrap_content" | |||||
android:layout_marginStart="@dimen/margin_start_and_end" | |||||
android:layout_marginTop="49dp" | |||||
android:layout_marginEnd="@dimen/margin_start_and_end" | |||||
android:fontFamily="@font/josefin_sans" | |||||
android:text="@string/error_title" | |||||
android:textAlignment="center" | |||||
android:textColor="@color/black" | |||||
android:textSize="@dimen/bubble_connection_title_text_size" | |||||
android:textStyle="bold" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toTopOf="parent" /> | |||||
<ImageView | |||||
android:layout_width="430dp" | |||||
android:layout_height="430dp" | |||||
android:layout_marginStart="@dimen/margin_start_and_end" | |||||
android:layout_marginTop="200dp" | |||||
android:layout_marginEnd="@dimen/margin_start_and_end" | |||||
android:scaleType="fitXY" | |||||
android:src="@drawable/error_face" | |||||
app:layout_constraintBottom_toBottomOf="@+id/error_constraints" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toBottomOf="@+id/textView" /> | |||||
<LinearLayout | |||||
android:id="@+id/linearLayout" | |||||
android:layout_width="@dimen/edit_text_width" | |||||
android:layout_height="@dimen/edit_text_height" | |||||
android:layout_marginStart="@dimen/margin_start_and_end" | |||||
android:layout_marginEnd="@dimen/margin_start_and_end" | |||||
android:layout_marginBottom="33dp" | |||||
android:background="@android:color/transparent" | |||||
android:orientation="vertical" | |||||
app:layout_constraintBottom_toBottomOf="parent" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintStart_toStartOf="parent"> | |||||
<androidx.appcompat.widget.AppCompatButton | |||||
android:id="@+id/contactSupportButton" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="match_parent" | |||||
android:background="@drawable/contact_support" | |||||
android:enabled="true" | |||||
android:text="@string/contact_support" | |||||
android:textAlignment="center" | |||||
android:textAllCaps="false" | |||||
android:textColor="@color/white" | |||||
android:textSize="@dimen/text_title" /> | |||||
</LinearLayout> | |||||
<androidx.constraintlayout.widget.Constraints | |||||
android:id="@+id/error_constraints" | |||||
android:layout_width="wrap_content" | |||||
android:layout_height="wrap_content" | |||||
android:layout_marginStart="@dimen/margin_start_and_end" | |||||
android:layout_marginTop="@dimen/margin_start_and_end" | |||||
android:layout_marginEnd="@dimen/margin_start_and_end" | |||||
android:layout_marginBottom="@dimen/margin_start_and_end" | |||||
app:layout_constraintBottom_toBottomOf="parent" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toTopOf="parent" /> | |||||
</androidx.constraintlayout.widget.ConstraintLayout> |
@@ -257,4 +257,6 @@ | |||||
<string name="enter_your_bubble_name">Enter your Bubble Name</string> | <string name="enter_your_bubble_name">Enter your Bubble Name</string> | ||||
<string name="your_private_bubble">Your private Bubble provides \n protection on this device.</string> | <string name="your_private_bubble">Your private Bubble provides \n protection on this device.</string> | ||||
<string name="network_not_found">Sorry, friends. Network not currently available.</string> | <string name="network_not_found">Sorry, friends. Network not currently available.</string> | ||||
<string name="error_title">Sadface. We have \n encountered \n an error.</string> | |||||
<string name="contact_support">CONTACT SUPPORT</string> | |||||
</resources> | </resources> |