Login helper
This commit is contained in:
parent
d48c627c3b
commit
86dc89e764
|
@ -5,10 +5,11 @@ android {
|
|||
buildToolsVersion "28.0.3"
|
||||
defaultConfig {
|
||||
applicationId "fr.gouv.etalab.mastodon"
|
||||
minSdkVersion 15
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
versionCode 201
|
||||
versionName "1.39.0"
|
||||
multiDexEnabled true
|
||||
}
|
||||
flavorDimensions "default"
|
||||
buildTypes {
|
||||
|
@ -78,5 +79,6 @@ dependencies {
|
|||
implementation 'com.github.franmontiel:LocaleChanger:0.9.2'
|
||||
implementation 'com.github.stom79:SparkButton:1.0.10'
|
||||
implementation 'com.github.GrenderG:Toasty:1.3.0'
|
||||
implementation 'com.elconfidencial.bubbleshowcase:bubbleshowcase:1.3.1'
|
||||
playstoreImplementation "io.github.kobakei:ratethisapp:$ratethisappLibraryVersion"
|
||||
}
|
||||
|
|
|
@ -19,11 +19,13 @@ import android.content.Context;
|
|||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
|
@ -48,6 +50,10 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.elconfidencial.bubbleshowcase.BubbleShowCase;
|
||||
import com.elconfidencial.bubbleshowcase.BubbleShowCaseBuilder;
|
||||
import com.elconfidencial.bubbleshowcase.BubbleShowCaseListener;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -84,6 +90,7 @@ public class LoginActivity extends BaseActivity {
|
|||
private EditText login_passwd;
|
||||
boolean isLoadingInstance = false;
|
||||
private String oldSearch;
|
||||
private ImageView info_uid, info_instance, info_pwd, info_2FA;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -168,7 +175,38 @@ public class LoginActivity extends BaseActivity {
|
|||
login_instance = findViewById(R.id.login_instance);
|
||||
login_uid = findViewById(R.id.login_uid);
|
||||
login_passwd = findViewById(R.id.login_passwd);
|
||||
info_uid = findViewById(R.id.info_uid);
|
||||
info_instance = findViewById(R.id.info_instance);
|
||||
info_pwd = findViewById(R.id.info_pwd);
|
||||
info_2FA = findViewById(R.id.info_2FA);
|
||||
|
||||
info_instance.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showcaseInstance(false);
|
||||
}
|
||||
});
|
||||
|
||||
info_uid.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showCaseLogin(false);
|
||||
}
|
||||
});
|
||||
info_pwd.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showCasePassword(false);
|
||||
}
|
||||
});
|
||||
info_2FA.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showCase2FA(false);
|
||||
}
|
||||
});
|
||||
|
||||
showcaseInstance(true);
|
||||
|
||||
login_instance.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
|
@ -254,6 +292,7 @@ public class LoginActivity extends BaseActivity {
|
|||
connectionButton.setEnabled(false);
|
||||
login_two_step = findViewById(R.id.login_two_step);
|
||||
login_two_step.setVisibility(View.GONE);
|
||||
info_2FA.setVisibility(View.GONE);
|
||||
login_two_step.setPaintFlags(login_two_step.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
||||
login_two_step.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
|
@ -275,6 +314,7 @@ public class LoginActivity extends BaseActivity {
|
|||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
connectionButton.setEnabled(false);
|
||||
login_two_step.setVisibility(View.INVISIBLE);
|
||||
info_2FA.setVisibility(View.INVISIBLE);
|
||||
TextInputLayout login_instance_layout = findViewById(R.id.login_instance_layout);
|
||||
if (!hasFocus) {
|
||||
retrievesClientId();
|
||||
|
@ -372,6 +412,8 @@ public class LoginActivity extends BaseActivity {
|
|||
editor.apply();
|
||||
connectionButton.setEnabled(true);
|
||||
login_two_step.setVisibility(View.VISIBLE);
|
||||
info_2FA.setVisibility(View.VISIBLE);
|
||||
showCase2FA(true);
|
||||
if( client_id_for_webview){
|
||||
boolean embedded_browser = sharedpreferences.getBoolean(Helper.SET_EMBEDDED_BROWSER, true);
|
||||
if( embedded_browser) {
|
||||
|
@ -525,4 +567,166 @@ public class LoginActivity extends BaseActivity {
|
|||
queryString += "&" + Helper.SCOPE +"=" + Helper.OAUTH_SCOPES;
|
||||
return Helper.instanceWithProtocol(instance) + Helper.EP_AUTHORIZE + "?" + queryString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void showcaseInstance(final boolean loop){
|
||||
|
||||
BubbleShowCaseBuilder showCaseBuilder = new BubbleShowCaseBuilder(LoginActivity.this)
|
||||
.title(getString(R.string.instance))
|
||||
.description(getString(R.string.showcase_instance))
|
||||
.arrowPosition(BubbleShowCase.ArrowPosition.TOP)
|
||||
.backgroundColor(ContextCompat.getColor(LoginActivity.this, R.color.mastodonC4))
|
||||
.textColor(Color.WHITE)
|
||||
.titleTextSize(17)
|
||||
.descriptionTextSize(15);
|
||||
if( loop)
|
||||
showCaseBuilder.showOnce("BUBBLE_SHOW_CASE_INSTANCE_ID");
|
||||
showCaseBuilder.listener(new BubbleShowCaseListener (){
|
||||
@Override
|
||||
public void onTargetClick(BubbleShowCase bubbleShowCase) {
|
||||
if( loop) {
|
||||
bubbleShowCase.finishSequence();
|
||||
showCaseLogin(true);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onCloseActionImageClick(BubbleShowCase bubbleShowCase) {
|
||||
if(loop) {
|
||||
bubbleShowCase.finishSequence();
|
||||
showCaseLogin(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBubbleClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackgroundDimClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
.targetView(login_instance)
|
||||
.show();
|
||||
}
|
||||
private void showCaseLogin(final boolean loop){
|
||||
BubbleShowCaseBuilder showCaseBuilder = new BubbleShowCaseBuilder(LoginActivity.this) //Activity instance
|
||||
.title(getString(R.string.login))
|
||||
.description(getString(R.string.showcase_uid))
|
||||
.arrowPosition(BubbleShowCase.ArrowPosition.TOP)
|
||||
.backgroundColor(ContextCompat.getColor(LoginActivity.this, R.color.mastodonC4))
|
||||
.textColor(Color.WHITE)
|
||||
.titleTextSize(17)
|
||||
.descriptionTextSize(15);
|
||||
if( loop)
|
||||
showCaseBuilder.showOnce("BUBBLE_SHOW_CASE_UID_ID");
|
||||
showCaseBuilder.listener(new BubbleShowCaseListener (){
|
||||
@Override
|
||||
public void onTargetClick(BubbleShowCase bubbleShowCase) {
|
||||
if( loop) {
|
||||
bubbleShowCase.finishSequence();
|
||||
showCasePassword(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseActionImageClick(BubbleShowCase bubbleShowCase) {
|
||||
if( loop) {
|
||||
bubbleShowCase.finishSequence();
|
||||
showCasePassword(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBubbleClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackgroundDimClick(BubbleShowCase bubbleShowCase) {
|
||||
}
|
||||
|
||||
})
|
||||
.targetView(login_uid)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showCasePassword(boolean loop){
|
||||
BubbleShowCaseBuilder showCaseBuilder = new BubbleShowCaseBuilder(LoginActivity.this)
|
||||
.title(getString(R.string.password))
|
||||
.description(getString(R.string.showcase_pwd))
|
||||
.arrowPosition(BubbleShowCase.ArrowPosition.BOTTOM)
|
||||
.backgroundColor(ContextCompat.getColor(LoginActivity.this, R.color.mastodonC4))
|
||||
.textColor(Color.WHITE)
|
||||
.titleTextSize(17)
|
||||
.descriptionTextSize(15);
|
||||
if( loop)
|
||||
showCaseBuilder.showOnce("BUBBLE_SHOW_CASE_PASSWORD_ID");
|
||||
showCaseBuilder.listener(new BubbleShowCaseListener (){
|
||||
@Override
|
||||
public void onTargetClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseActionImageClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBubbleClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackgroundDimClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
.targetView(login_passwd)
|
||||
.show();
|
||||
}
|
||||
|
||||
|
||||
private void showCase2FA(boolean loop){
|
||||
BubbleShowCaseBuilder showCaseBuilder = new BubbleShowCaseBuilder(LoginActivity.this)
|
||||
.title(getString(R.string.two_factor_authentification))
|
||||
.description(getString(R.string.showcase_2FA))
|
||||
.arrowPosition(BubbleShowCase.ArrowPosition.BOTTOM)
|
||||
.backgroundColor(ContextCompat.getColor(LoginActivity.this, R.color.mastodonC4))
|
||||
.textColor(Color.WHITE)
|
||||
.titleTextSize(17)
|
||||
.descriptionTextSize(15);
|
||||
if( loop)
|
||||
showCaseBuilder.showOnce("BUBBLE_SHOW_CASE_2FA_ID");
|
||||
showCaseBuilder.listener(new BubbleShowCaseListener (){
|
||||
@Override
|
||||
public void onTargetClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseActionImageClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBubbleClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackgroundDimClick(BubbleShowCase bubbleShowCase) {
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
.targetView(login_passwd)
|
||||
.show();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF2b90d9"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
|
||||
</vector>
|
|
@ -57,48 +57,93 @@
|
|||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:errorEnabled="true">
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/login_instance"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:maxLines="1"
|
||||
android:inputType="textWebEmailAddress"
|
||||
android:hint="@string/instance_example"
|
||||
/>
|
||||
android:orientation="horizontal">
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/login_instance"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:maxLines="1"
|
||||
android:inputType="textWebEmailAddress"
|
||||
android:hint="@string/instance_example"
|
||||
/>
|
||||
<ImageView
|
||||
android:contentDescription="@string/more_information"
|
||||
android:id="@+id/info_instance"
|
||||
android:src="@drawable/ic_info_login"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp" />
|
||||
</LinearLayout>
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_two_step"
|
||||
android:textAllCaps="false"
|
||||
android:gravity="center"
|
||||
android:drawablePadding="10dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/colorAccent"
|
||||
android:text="@string/two_factor_authentification" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/login_uid"
|
||||
android:layout_width="300dp"
|
||||
android:maxLines="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textEmailAddress"
|
||||
android:hint="@string/email"
|
||||
/>
|
||||
<EditText
|
||||
android:id = "@+id/login_passwd"
|
||||
android:inputType="textPassword"
|
||||
android:maxLines="1"
|
||||
android:hint="@string/password"
|
||||
<LinearLayout
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/login_two_step"
|
||||
android:textAllCaps="false"
|
||||
android:gravity="center"
|
||||
android:drawablePadding="10dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/colorAccent"
|
||||
android:text="@string/two_factor_authentification" />
|
||||
<ImageView
|
||||
android:contentDescription="@string/more_information"
|
||||
android:id="@+id/info_2FA"
|
||||
android:src="@drawable/ic_info_login"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<EditText
|
||||
android:id="@+id/login_uid"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textEmailAddress"
|
||||
android:hint="@string/email"
|
||||
/>
|
||||
<ImageView
|
||||
android:contentDescription="@string/more_information"
|
||||
android:id="@+id/info_uid"
|
||||
android:src="@drawable/ic_info_login"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<EditText
|
||||
android:id = "@+id/login_passwd"
|
||||
android:inputType="textPassword"
|
||||
android:maxLines="1"
|
||||
android:hint="@string/password"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
<ImageView
|
||||
android:contentDescription="@string/more_information"
|
||||
android:id="@+id/info_pwd"
|
||||
android:src="@drawable/ic_info_login"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp" />
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="10dp"
|
||||
|
|
|
@ -62,47 +62,94 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:errorEnabled="true">
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/login_instance"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textWebEmailAddress"
|
||||
android:maxLines="1"
|
||||
android:hint="@string/instance_example"
|
||||
/>
|
||||
android:orientation="horizontal">
|
||||
<AutoCompleteTextView
|
||||
android:id="@+id/login_instance"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textWebEmailAddress"
|
||||
android:maxLines="1"
|
||||
android:hint="@string/instance_example"
|
||||
/>
|
||||
<ImageView
|
||||
android:contentDescription="@string/more_information"
|
||||
android:id="@+id/info_instance"
|
||||
android:src="@drawable/ic_info_login"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp" />
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/login_two_step"
|
||||
android:textAllCaps="false"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
android:drawablePadding="10dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_gravity="center"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/colorAccent"
|
||||
android:text="@string/two_factor_authentification" />
|
||||
<EditText
|
||||
android:id="@+id/login_uid"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/login_two_step"
|
||||
android:textAllCaps="false"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
android:drawablePadding="10dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/colorAccent"
|
||||
android:text="@string/two_factor_authentification" />
|
||||
<ImageView
|
||||
android:contentDescription="@string/more_information"
|
||||
android:id="@+id/info_2FA"
|
||||
android:src="@drawable/ic_info_login"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:inputType="textEmailAddress"
|
||||
android:hint="@string/email"
|
||||
/>
|
||||
<EditText
|
||||
android:id = "@+id/login_passwd"
|
||||
android:inputType="textPassword"
|
||||
android:hint="@string/password"
|
||||
android:maxLines="1"
|
||||
android:orientation="horizontal">
|
||||
<EditText
|
||||
android:id="@+id/login_uid"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:inputType="textEmailAddress"
|
||||
android:hint="@string/email"
|
||||
/>
|
||||
<ImageView
|
||||
android:contentDescription="@string/more_information"
|
||||
android:id="@+id/info_uid"
|
||||
android:src="@drawable/ic_info_login"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
android:orientation="horizontal">
|
||||
<EditText
|
||||
android:id = "@+id/login_passwd"
|
||||
android:inputType="textPassword"
|
||||
android:hint="@string/password"
|
||||
android:maxLines="1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
<ImageView
|
||||
android:contentDescription="@string/more_information"
|
||||
android:id="@+id/info_pwd"
|
||||
android:src="@drawable/ic_info_login"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp" />
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="10dp"
|
||||
|
|
|
@ -720,4 +720,19 @@
|
|||
<item>1 day</item>
|
||||
<item>1 week</item>
|
||||
</string-array>
|
||||
|
||||
|
||||
<string name="showcase_instance">
|
||||
In this field, you need to write your instance host name.\nFor example, if you created your account on https://mastodon.social\nJust write <b>mastodon.social</b> (without https://)\n
|
||||
You can start writing first letters and names will be suggested.\n\n
|
||||
⚠ The Login button will only work if the instance name is valid and the instance is up!
|
||||
</string>
|
||||
<string name="showcase_uid">
|
||||
In this field, write the email that is attached to your Mastodon account.
|
||||
</string>
|
||||
<string name="showcase_pwd">
|
||||
Last step is to enter your password and click on Login.
|
||||
</string>
|
||||
<string name="more_information">More information</string>
|
||||
<string name="showcase_2FA">If you use 2FA (Two-factor authentication), you need to use this link.\nYou can also use it if you do not want to enter your credentials here.</string>
|
||||
</resources>
|
Loading…
Reference in New Issue