mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
In app feedback (#4845)
* rebase * Progress * Completed UI and POST Request * removed invalid string resource * Removed unused code & Added string resources * Resolved Code style issues * Javadoc for getters & setters * Codestyle fixes * Minor Fixes * wip * Tests * Comments * Fixed Tests * Minor changes * minor change * Comments * Minor Fixes * fixed tests * Removed Butterknife * Fixed tests * Removed Unecessary strings * Minor chnages * Minor fix * Minor changes * Minor changes * Implemented Suggestions * Removed Redundant Toast
This commit is contained in:
parent
00760ba1c6
commit
fa0370438b
12 changed files with 777 additions and 5 deletions
|
|
@ -0,0 +1,95 @@
|
|||
package fr.free.nrw.commons.feedback;
|
||||
|
||||
import android.content.Context;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.feedback.model.Feedback;
|
||||
import fr.free.nrw.commons.utils.LangCodeUtils;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Creates a wikimedia recognizable format
|
||||
* from feedback information
|
||||
*/
|
||||
public class FeedbackContentCreator {
|
||||
private StringBuilder stringBuilder;
|
||||
private Feedback feedback;
|
||||
private Context context;
|
||||
|
||||
public FeedbackContentCreator(Context context, Feedback feedback) {
|
||||
this.feedback = feedback;
|
||||
this.context = context;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the string buffer object to append content from feedback object
|
||||
*/
|
||||
public void init() {
|
||||
// Localization is not needed here, because this ends up on a page where developers read the feedback, so English is the most convenient.
|
||||
|
||||
stringBuilder = new StringBuilder();
|
||||
stringBuilder.append("== ");
|
||||
stringBuilder.append("Feedback from ~~~ for version ");
|
||||
stringBuilder.append(feedback.getVersion());
|
||||
stringBuilder.append(" ==");
|
||||
stringBuilder.append("\n");
|
||||
stringBuilder.append(feedback.getTitle());
|
||||
stringBuilder.append("\n");
|
||||
stringBuilder.append("\n");
|
||||
if (feedback.getApiLevel() != null) {
|
||||
stringBuilder.append("* ");
|
||||
stringBuilder.append(LangCodeUtils.getLocalizedResources(context,
|
||||
Locale.ENGLISH).getString(R.string.api_level));
|
||||
stringBuilder.append(": ");
|
||||
stringBuilder.append(feedback.getApiLevel());
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
if (feedback.getAndroidVersion() != null) {
|
||||
stringBuilder.append("* ");
|
||||
stringBuilder.append(LangCodeUtils.getLocalizedResources(context,
|
||||
Locale.ENGLISH).getString(R.string.android_version));
|
||||
stringBuilder.append(": ");
|
||||
stringBuilder.append(feedback.getAndroidVersion());
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
if (feedback.getDeviceManufacturer() != null) {
|
||||
stringBuilder.append("* ");
|
||||
stringBuilder.append(LangCodeUtils.getLocalizedResources(context,
|
||||
Locale.ENGLISH).getString(R.string.device_manufacturer));
|
||||
stringBuilder.append(": ");
|
||||
stringBuilder.append(feedback.getDeviceManufacturer());
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
if (feedback.getDeviceModel() != null) {
|
||||
stringBuilder.append("* ");
|
||||
stringBuilder.append(LangCodeUtils.getLocalizedResources(context,
|
||||
Locale.ENGLISH).getString(R.string.device_model));
|
||||
stringBuilder.append(": ");
|
||||
stringBuilder.append(feedback.getDeviceModel());
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
if (feedback.getDevice() != null) {
|
||||
stringBuilder.append("* ");
|
||||
stringBuilder.append(LangCodeUtils.getLocalizedResources(context,
|
||||
Locale.ENGLISH).getString(R.string.device_name));
|
||||
stringBuilder.append(": ");
|
||||
stringBuilder.append(feedback.getDevice());
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
if (feedback.getNetworkType() != null) {
|
||||
stringBuilder.append("* ");
|
||||
stringBuilder.append(LangCodeUtils.getLocalizedResources(context,
|
||||
Locale.ENGLISH).getString(R.string.network_type));
|
||||
stringBuilder.append(": ");
|
||||
stringBuilder.append(feedback.getNetworkType());
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
stringBuilder.append("~~~~");
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package fr.free.nrw.commons.feedback;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Toast;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.databinding.DialogFeedbackBinding;
|
||||
import fr.free.nrw.commons.feedback.model.Feedback;
|
||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||
import fr.free.nrw.commons.utils.DeviceInfoUtil;
|
||||
|
||||
/**
|
||||
* Feedback dialog that asks user for message and
|
||||
* other device specifications
|
||||
*/
|
||||
public class FeedbackDialog extends Dialog {
|
||||
DialogFeedbackBinding dialogFeedbackBinding;
|
||||
|
||||
private OnFeedbackSubmitCallback onFeedbackSubmitCallback;
|
||||
|
||||
public FeedbackDialog(Context context, OnFeedbackSubmitCallback onFeedbackSubmitCallback) {
|
||||
super(context);
|
||||
this.onFeedbackSubmitCallback = onFeedbackSubmitCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
dialogFeedbackBinding = DialogFeedbackBinding.inflate(getLayoutInflater());
|
||||
final View view = dialogFeedbackBinding.getRoot();
|
||||
setContentView(view);
|
||||
dialogFeedbackBinding.btnSubmitFeedback.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
submitFeedback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* When the button is clicked, it will create a feedback object
|
||||
* and give a callback to calling activity/fragment
|
||||
*/
|
||||
void submitFeedback() {
|
||||
if(dialogFeedbackBinding.feedbackItemEditText.getText().toString().equals("")) {
|
||||
dialogFeedbackBinding.feedbackItemEditText.setError(getContext().getString(R.string.enter_description));
|
||||
return;
|
||||
}
|
||||
String appVersion = ConfigUtils.getVersionNameWithSha(getContext());
|
||||
String androidVersion = dialogFeedbackBinding.androidVersionCheckbox.isChecked() ? DeviceInfoUtil.getAndroidVersion() : null;
|
||||
String apiLevel = dialogFeedbackBinding.apiLevelCheckbox.isChecked() ? DeviceInfoUtil.getAPILevel() : null;
|
||||
String deviceManufacturer = dialogFeedbackBinding.deviceManufacturerCheckbox.isChecked() ? DeviceInfoUtil.getDeviceManufacturer() : null;
|
||||
String deviceModel = dialogFeedbackBinding.deviceModelCheckbox.isChecked() ? DeviceInfoUtil.getDeviceModel() : null;
|
||||
String deviceName = dialogFeedbackBinding.deviceNameCheckbox.isChecked() ? DeviceInfoUtil.getDevice() : null;
|
||||
String networkType = dialogFeedbackBinding.networkTypeCheckbox.isChecked() ? DeviceInfoUtil.getConnectionType(getContext()).toString() : null;
|
||||
Feedback feedback = new Feedback(appVersion, apiLevel
|
||||
, dialogFeedbackBinding.feedbackItemEditText.getText().toString()
|
||||
, androidVersion, deviceModel, deviceManufacturer, deviceName, networkType);
|
||||
onFeedbackSubmitCallback.onFeedbackSubmit(feedback);
|
||||
dismiss();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package fr.free.nrw.commons.feedback;
|
||||
|
||||
import fr.free.nrw.commons.feedback.model.Feedback;
|
||||
|
||||
/**
|
||||
* This interface is used to provide callback
|
||||
* from Feedback dialog whenever submit button is clicked
|
||||
*/
|
||||
public interface OnFeedbackSubmitCallback {
|
||||
|
||||
/**
|
||||
* callback function, called when user clicks on submit
|
||||
*/
|
||||
void onFeedbackSubmit(Feedback feedback);
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
package fr.free.nrw.commons.feedback.model;
|
||||
|
||||
/**
|
||||
* Pojo class for storing information that are required while uploading a feedback
|
||||
*/
|
||||
public class Feedback {
|
||||
/**
|
||||
* Version of app
|
||||
*/
|
||||
private String version;
|
||||
/**
|
||||
* API level of user's phone
|
||||
*/
|
||||
private String apiLevel;
|
||||
/**
|
||||
* Title/Description entered by user
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* Android version of user's device
|
||||
*/
|
||||
private String androidVersion;
|
||||
/**
|
||||
* Device Model of user's device
|
||||
*/
|
||||
private String deviceModel;
|
||||
/**
|
||||
* Device manufacturer name
|
||||
*/
|
||||
private String deviceManufacturer;
|
||||
/**
|
||||
* Device name stored on user's device
|
||||
*/
|
||||
private String device;
|
||||
/**
|
||||
* network type user is having (Ex: Wifi)
|
||||
*/
|
||||
private String networkType;
|
||||
|
||||
public Feedback(final String version, final String apiLevel, final String title, final String androidVersion,
|
||||
final String deviceModel, final String deviceManufacturer, final String device, final String networkType
|
||||
) {
|
||||
this.version = version;
|
||||
this.apiLevel = apiLevel;
|
||||
this.title = title;
|
||||
this.androidVersion = androidVersion;
|
||||
this.deviceModel = deviceModel;
|
||||
this.deviceManufacturer = deviceManufacturer;
|
||||
this.device = device;
|
||||
this.networkType = networkType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version from which this piece of feedback is being sent.
|
||||
* Ex: 3.0.1
|
||||
*/
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the version of app to given version
|
||||
*/
|
||||
public void setVersion(final String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets api level of device
|
||||
* Ex: 28
|
||||
*/
|
||||
public String getApiLevel() {
|
||||
return apiLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets api level value to given value
|
||||
*/
|
||||
public void setApiLevel(final String apiLevel) {
|
||||
this.apiLevel = apiLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets feedback text entered by user
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets feedback text
|
||||
*/
|
||||
public void setTitle(final String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets android version of device
|
||||
* Ex: 9
|
||||
*/
|
||||
public String getAndroidVersion() {
|
||||
return androidVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets value of android version
|
||||
*/
|
||||
public void setAndroidVersion(final String androidVersion) {
|
||||
this.androidVersion = androidVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* get device model of current device
|
||||
* Ex: Redmi 6 Pro
|
||||
*/
|
||||
public String getDeviceModel() {
|
||||
return deviceModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets value of device model to a given value
|
||||
*/
|
||||
public void setDeviceModel(final String deviceModel) {
|
||||
this.deviceModel = deviceModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* get device manufacturer of user's device
|
||||
* Ex: Redmi
|
||||
*/
|
||||
public String getDeviceManufacturer() {
|
||||
return deviceManufacturer;
|
||||
}
|
||||
|
||||
/**
|
||||
* set device manufacturer value to a given value
|
||||
*/
|
||||
public void setDeviceManufacturer(final String deviceManufacturer) {
|
||||
this.deviceManufacturer = deviceManufacturer;
|
||||
}
|
||||
|
||||
/**
|
||||
* get device name of user's device
|
||||
*/
|
||||
public String getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets device name value to a given value
|
||||
*/
|
||||
public void setDevice(final String device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
/**
|
||||
* get network type of user's network
|
||||
* Ex: wifi
|
||||
*/
|
||||
public String getNetworkType() {
|
||||
return networkType;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets network type to a given value
|
||||
*/
|
||||
public void setNetworkType(final String networkType) {
|
||||
this.networkType = networkType;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -24,13 +24,23 @@ import fr.free.nrw.commons.BuildConfig;
|
|||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.WelcomeActivity;
|
||||
import fr.free.nrw.commons.actions.PageEditClient;
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||
import fr.free.nrw.commons.feedback.FeedbackContentCreator;
|
||||
import fr.free.nrw.commons.feedback.model.Feedback;
|
||||
import fr.free.nrw.commons.feedback.FeedbackDialog;
|
||||
import fr.free.nrw.commons.feedback.OnFeedbackSubmitCallback;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.logging.CommonsLogSender;
|
||||
import fr.free.nrw.commons.profile.ProfileActivity;
|
||||
import fr.free.nrw.commons.review.ReviewActivity;
|
||||
import fr.free.nrw.commons.settings.SettingsActivity;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.SingleSource;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import timber.log.Timber;
|
||||
|
|
@ -47,6 +57,10 @@ public class MoreBottomSheetFragment extends BottomSheetDialogFragment {
|
|||
@Inject @Named("default_preferences")
|
||||
JsonKvStore store;
|
||||
|
||||
@Inject
|
||||
@Named("commons-page-edit")
|
||||
PageEditClient pageEditClient;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull final LayoutInflater inflater,
|
||||
|
|
@ -104,7 +118,44 @@ public class MoreBottomSheetFragment extends BottomSheetDialogFragment {
|
|||
|
||||
@OnClick(R.id.more_feedback)
|
||||
public void onFeedbackClicked() {
|
||||
showAlertDialog();
|
||||
showFeedbackDialog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and shows a dialog asking feedback from users
|
||||
*/
|
||||
private void showFeedbackDialog() {
|
||||
new FeedbackDialog(getContext(), new OnFeedbackSubmitCallback() {
|
||||
@Override
|
||||
public void onFeedbackSubmit(Feedback feedback) {
|
||||
uploadFeedback(feedback);
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* uploads feedback data on the server
|
||||
*/
|
||||
void uploadFeedback(Feedback feedback) {
|
||||
FeedbackContentCreator feedbackContentCreator = new FeedbackContentCreator(getContext(), feedback);
|
||||
|
||||
Single<Boolean> single =
|
||||
pageEditClient.prependEdit("Commons:Mobile_app/Feedback", feedbackContentCreator.toString(), "Summary")
|
||||
.flatMapSingle(result -> Single.just(result))
|
||||
.firstOrError();
|
||||
|
||||
Single.defer((Callable<SingleSource<Boolean>>) () -> single)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(aBoolean -> {
|
||||
if (aBoolean) {
|
||||
Toast.makeText(getContext(), getString(R.string.thanks_feedback), Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
} else {
|
||||
Toast.makeText(getContext(), getString(R.string.error_feedback),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
136
app/src/main/res/layout/dialog_feedback.xml
Normal file
136
app/src/main/res/layout/dialog_feedback.xml
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:layout_margin="@dimen/dimen_6"
|
||||
android:padding="@dimen/tiny_gap"
|
||||
android:textSize="24sp"
|
||||
android:textColor="@color/black"
|
||||
android:text="@string/navigation_item_feedback"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/feedback_item_edit_text_input_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dimen_6"
|
||||
android:layout_marginEnd="@dimen/dimen_6"
|
||||
>
|
||||
|
||||
<fr.free.nrw.commons.ui.PasteSensitiveTextInputEditText
|
||||
android:id="@+id/feedback_item_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:hint="@string/your_feedback"
|
||||
android:imeOptions="actionNext|flagNoExtractUi"
|
||||
android:lines="4"
|
||||
android:inputType="text|textMultiLine"
|
||||
app:allowFormatting="false" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_margin="@dimen/dimen_6"
|
||||
android:padding="4dp"
|
||||
android:textSize="21sp"
|
||||
android:textColor="@color/black"
|
||||
android:text="@string/select_feedback_data_choice"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/api_level_checkbox"
|
||||
android:text="@string/api_level"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checkMark="?android:attr/textCheckMark"
|
||||
android:checked="true"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="@dimen/tiny_gap"
|
||||
android:layout_margin="@dimen/dimen_6"
|
||||
/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/android_version_checkbox"
|
||||
android:text="@string/android_version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checkMark="?android:attr/textCheckMark"
|
||||
android:checked="true"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="@dimen/tiny_gap"
|
||||
android:layout_margin="@dimen/dimen_6"
|
||||
/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/device_manufacturer_checkbox"
|
||||
android:text="@string/device_manufacturer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checkMark="?android:attr/textCheckMark"
|
||||
android:checked="true"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="@dimen/tiny_gap"
|
||||
android:layout_margin="@dimen/dimen_6"
|
||||
/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/device_model_checkbox"
|
||||
android:text="@string/device_model"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checkMark="?android:attr/textCheckMark"
|
||||
android:checked="true"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="@dimen/tiny_gap"
|
||||
android:layout_margin="@dimen/dimen_6"
|
||||
/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/device_name_checkbox"
|
||||
android:text="@string/device_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checkMark="?android:attr/textCheckMark"
|
||||
android:checked="true"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="@dimen/tiny_gap"
|
||||
android:layout_margin="@dimen/dimen_6"
|
||||
/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/network_type_checkbox"
|
||||
android:text="@string/network_type"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checkMark="?android:attr/textCheckMark"
|
||||
android:checked="true"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="@dimen/tiny_gap"
|
||||
android:layout_margin="@dimen/dimen_6"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_submit_feedback"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginBottom="@dimen/dimen_10"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/submit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
|
@ -650,5 +650,4 @@
|
|||
<string name="feedback_sharing_data_alert">Од оваа порака отстранете ги сите информации што не сакате да бидат јавни. Воедно, имајте на ум дека вашата е-поштенска адреса од која испраќате, името и профилна слика ќе бидат јавно видливи.</string>
|
||||
<string name="achievements_unavailable_beta">Достигнувањата се достапни само во производниот вкус.</string>
|
||||
<string name="leaderboard_unavailable_beta">Предводниците се достапни само во производниот вкус.</string>
|
||||
<string name="copyright_popup">Подигајте само слики што сте ги направиле самите. Подигачите на слики заштитени со авторски права ќе бидат блокирани. Ова важи и за бета-верзијата. Ви благодариме што го испробувате прилогот!</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -693,4 +693,15 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="achievements_unavailable_beta">Achievements are only available in the prod flavor, please check the developer documentation.</string>
|
||||
<string name="leaderboard_unavailable_beta">The leaderboard is only available in the prod flavor, please check the developer documentation.</string>
|
||||
<string name="copyright_popup">Please only upload pictures you have taken by yourself. Uploaders of copyrighted images will be blocked. This applies to the beta flavor too. Thank you for testing the app!</string>
|
||||
<string name="select_feedback_data_choice">Please deselect any information that you are not comfortable sharing publicly.</string>
|
||||
<string name="api_level">API level</string>
|
||||
<string name="android_version">Android version</string>
|
||||
<string name="device_manufacturer">Device manufacturer</string>
|
||||
<string name="device_model">Device model</string>
|
||||
<string name="device_name">Device name</string>
|
||||
<string name="network_type">Network type</string>
|
||||
<string name="thanks_feedback">Thanks for giving feedback</string>
|
||||
<string name="error_feedback">Error while sending feedback</string>
|
||||
<string name="enter_description">What is your feedback?</string>
|
||||
<string name="your_feedback">Your feedback</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
package fr.free.nrw.commons.feedback
|
||||
|
||||
import android.content.Context
|
||||
import fr.free.nrw.commons.FakeContextWrapper
|
||||
import fr.free.nrw.commons.TestAppAdapter
|
||||
import fr.free.nrw.commons.TestCommonsApplication
|
||||
import fr.free.nrw.commons.feedback.model.Feedback
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.doReturn
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
import org.wikipedia.AppAdapter
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||
class FeedbackContentCreatorUnitTests {
|
||||
private lateinit var creator: FeedbackContentCreator
|
||||
private lateinit var feedback: Feedback
|
||||
|
||||
@Mock
|
||||
private lateinit var context: Context
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
AppAdapter.set(TestAppAdapter())
|
||||
context = RuntimeEnvironment.application.applicationContext
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testToString() {
|
||||
feedback = Feedback("123", "apiLevel", "title", "androidVersion", "deviceModel", "mfg", "deviceName", "wifi")
|
||||
creator = FeedbackContentCreator(context, feedback)
|
||||
Assert.assertNotNull(creator.toString())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package fr.free.nrw.commons.feedback
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Looper.getMainLooper
|
||||
import android.text.Editable
|
||||
import com.nhaarman.mockitokotlin2.doReturn
|
||||
import fr.free.nrw.commons.TestAppAdapter
|
||||
import fr.free.nrw.commons.TestCommonsApplication
|
||||
import fr.free.nrw.commons.contributions.MainActivity
|
||||
import fr.free.nrw.commons.databinding.DialogFeedbackBinding
|
||||
import fr.free.nrw.commons.ui.PasteSensitiveTextInputEditText
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.powermock.reflect.Whitebox
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.annotation.Config
|
||||
import org.robolectric.annotation.LooperMode
|
||||
import org.wikipedia.AppAdapter
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||
@LooperMode(LooperMode.Mode.PAUSED)
|
||||
class FeedbackDialogTests {
|
||||
private lateinit var dialogFeedbackBinding: DialogFeedbackBinding
|
||||
|
||||
@Mock
|
||||
private val onFeedbackSubmitCallback: OnFeedbackSubmitCallback? = null
|
||||
private lateinit var dialog: FeedbackDialog
|
||||
|
||||
private lateinit var context: Context
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
context = RuntimeEnvironment.application.applicationContext
|
||||
AppAdapter.set(TestAppAdapter())
|
||||
|
||||
val activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
|
||||
|
||||
dialog = FeedbackDialog(activity.applicationContext, onFeedbackSubmitCallback)
|
||||
dialogFeedbackBinding = DialogFeedbackBinding.inflate(dialog.layoutInflater)
|
||||
dialog.show()
|
||||
|
||||
Whitebox.setInternalState(dialog, "onFeedbackSubmitCallback", onFeedbackSubmitCallback)
|
||||
Whitebox.setInternalState(dialog, "dialogFeedbackBinding", dialogFeedbackBinding)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnCreate() {
|
||||
dialog.onCreate(null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSubmitFeedbackError() {
|
||||
val editable = mock(Editable::class.java)
|
||||
val ed = mock(PasteSensitiveTextInputEditText::class.java)
|
||||
Whitebox.setInternalState(dialogFeedbackBinding, "feedbackItemEditText", ed)
|
||||
`when`(ed?.text).thenReturn(editable)
|
||||
doReturn(editable).`when`(dialogFeedbackBinding.feedbackItemEditText)?.text
|
||||
doReturn("").`when`(editable).toString()
|
||||
dialog.submitFeedback()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSubmitFeedback() {
|
||||
shadowOf(getMainLooper()).idle()
|
||||
val editable: Editable = mock(Editable::class.java)
|
||||
val ed = mock(PasteSensitiveTextInputEditText::class.java)
|
||||
Whitebox.setInternalState(dialogFeedbackBinding, "feedbackItemEditText", ed)
|
||||
`when`(ed?.text).thenReturn(editable)
|
||||
`when`(editable.toString()).thenReturn("1234")
|
||||
|
||||
Assert.assertEquals(dialogFeedbackBinding.feedbackItemEditText?.text.toString(), "1234")
|
||||
dialog.submitFeedback()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package fr.free.nrw.commons.feedback
|
||||
|
||||
import fr.free.nrw.commons.feedback.model.Feedback
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class FeedbackUnitTests {
|
||||
private lateinit var feedback: Feedback
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
feedback = Feedback("123", "apiLevel", "title", "androidVersion", "deviceModel", "mfg", "deviceName", "wifi")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testVersion() {
|
||||
feedback.version = "456"
|
||||
Assert.assertEquals(feedback.version, "456")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testApiLevel() {
|
||||
Assert.assertEquals(feedback.apiLevel, "apiLevel")
|
||||
feedback.apiLevel = "29"
|
||||
Assert.assertEquals(feedback.apiLevel, "29")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTitle() {
|
||||
feedback.title = "myTitle"
|
||||
Assert.assertEquals(feedback.title, "myTitle")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAndroidVersion() {
|
||||
feedback.androidVersion = "PIE"
|
||||
Assert.assertEquals(feedback.androidVersion, "PIE")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeviceModel() {
|
||||
feedback.deviceModel = "My Device"
|
||||
Assert.assertEquals(feedback.deviceModel, "My Device")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeviceMfg() {
|
||||
feedback.deviceManufacturer = "MYCOMPANY"
|
||||
Assert.assertEquals(feedback.deviceManufacturer, "MYCOMPANY")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDeviceName() {
|
||||
feedback.device = "my_name"
|
||||
Assert.assertEquals(feedback.device, "my_name")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNetworkType() {
|
||||
feedback.networkType = "network"
|
||||
Assert.assertEquals(feedback.networkType, "network")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.navtab
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
|
@ -7,20 +8,33 @@ import android.net.Uri
|
|||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import fr.free.nrw.commons.CommonsApplication
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.TestAppAdapter
|
||||
import fr.free.nrw.commons.TestCommonsApplication
|
||||
import fr.free.nrw.commons.actions.PageEditClient
|
||||
import fr.free.nrw.commons.feedback.FeedbackDialog
|
||||
import fr.free.nrw.commons.feedback.model.Feedback
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||
import fr.free.nrw.commons.profile.ProfileActivity
|
||||
import fr.free.nrw.commons.utils.ConfigUtils
|
||||
import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.SingleSource
|
||||
import io.reactivex.functions.Function
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.*
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.powermock.reflect.Whitebox
|
||||
import org.robolectric.Robolectric
|
||||
|
|
@ -31,7 +45,10 @@ import org.robolectric.annotation.Config
|
|||
import org.robolectric.annotation.LooperMode
|
||||
import org.robolectric.shadows.ShadowActivity
|
||||
import org.robolectric.shadows.ShadowAlertDialog
|
||||
import org.robolectric.shadows.ShadowDialog
|
||||
import org.wikipedia.AppAdapter
|
||||
import java.lang.reflect.Method
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
|
|
@ -51,10 +68,14 @@ class MoreBottomSheetFragmentUnitTests {
|
|||
@Mock
|
||||
private lateinit var morePeerReview: TextView
|
||||
|
||||
@Mock
|
||||
private lateinit var pageEditClient: PageEditClient
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
context = RuntimeEnvironment.application.applicationContext
|
||||
AppAdapter.set(TestAppAdapter())
|
||||
|
||||
activity = Robolectric.buildActivity(ProfileActivity::class.java).create().get()
|
||||
fragment = MoreBottomSheetFragment()
|
||||
|
|
@ -65,6 +86,7 @@ class MoreBottomSheetFragmentUnitTests {
|
|||
|
||||
Whitebox.setInternalState(fragment, "store", store)
|
||||
Whitebox.setInternalState(fragment, "morePeerReview", morePeerReview)
|
||||
Whitebox.setInternalState(fragment, "pageEditClient", pageEditClient)
|
||||
|
||||
`when`(store.getBoolean(CommonsApplication.IS_LIMITED_CONNECTION_MODE_ENABLED)).thenReturn(
|
||||
true
|
||||
|
|
@ -101,8 +123,18 @@ class MoreBottomSheetFragmentUnitTests {
|
|||
fun testOnFeedbackClicked() {
|
||||
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
||||
fragment.onFeedbackClicked()
|
||||
val dialog: AlertDialog = ShadowAlertDialog.getLatestDialog() as AlertDialog
|
||||
Assert.assertEquals(dialog.isShowing, true)
|
||||
ShadowDialog.getLatestDialog().findViewById<Button>(R.id.btn_submit_feedback).performClick()
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testUploadFeedback() {
|
||||
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
||||
val feedback = mock(Feedback::class.java)
|
||||
val observable: Observable<Boolean> = Observable.just(false)
|
||||
val observable2: Observable<Boolean> = Observable.just(true)
|
||||
doReturn(observable, observable2).`when`(pageEditClient).prependEdit(anyString(), anyString(), anyString())
|
||||
fragment.uploadFeedback(feedback)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue