User credentials are saved and retrieved from the SQLite database. Next I want to retrieve all songs from icarus and return it to java/kotlin. Some code cleanup
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
+392
-548
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".activities.DemoStreamActivity"
|
||||
android:name=".activities.LoginActivity"
|
||||
android:label="@string/title_activity_demo_stream"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
<intent-filter>
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace repository { namespace local {
|
||||
const auto dbPath = pathOfDatabase(appPath);
|
||||
|
||||
SQLite::Database db(dbPath, SQLite::OPEN_READONLY);
|
||||
//SQLite::Database db(m_tableName, SQLite::OPEN_READONLY);
|
||||
return true;
|
||||
} catch (std::exception& ex) {
|
||||
auto msg = ex.what();
|
||||
@@ -39,7 +38,7 @@ namespace repository { namespace local {
|
||||
auto msg = ex.what();
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,11 +46,8 @@ namespace repository { namespace local {
|
||||
{
|
||||
try {
|
||||
const auto dbPath = pathOfDatabase(appPath);
|
||||
//std::fstream cret(dbPath, std::ios::out);
|
||||
//cret.close();
|
||||
|
||||
SQLite::Database db(dbPath, SQLite::OPEN_CREATE | SQLite::OPEN_READWRITE);
|
||||
//SQLite::Database db(m_tableName, SQLite::OPEN_CREATE);
|
||||
} catch (std::exception& ex) {
|
||||
auto msg = ex.what();
|
||||
}
|
||||
|
||||
+125
-49
@@ -30,24 +30,23 @@
|
||||
#include "UserRepository.h"
|
||||
|
||||
|
||||
model::Song retrieveSong(const std::string&, const std::string&);
|
||||
model::Song retrieveSong(const std::string&, const std::string&, const int);
|
||||
|
||||
model::User retrieveCredentials(const std::string&);
|
||||
|
||||
std::string fetchToken(const std::string&, const std::string&, const std::string&);
|
||||
|
||||
bool doesDatabaseExist(const std::string&);
|
||||
bool userCredentialExist(const std::string&);
|
||||
|
||||
void saveCredentials(const model::User&, const std::string&);
|
||||
|
||||
|
||||
model::Song retrieveSong(const std::string& token, const std::string& baseUri)
|
||||
model::Song retrieveSong(const std::string& token, const std::string& baseUri, const int songId)
|
||||
{
|
||||
repository::SongRepository songRepo;
|
||||
model::Song song;
|
||||
song.id = 1;
|
||||
song.title = "Smooth";
|
||||
song.album = "Amaze";
|
||||
song.artist = "The Herb";
|
||||
song.genre = "Blazing";
|
||||
song.duration = 420;
|
||||
song.year = 420;
|
||||
model::Song song(songId, "Smooth", "Amaze", "The Herb", "Blazing",
|
||||
420, 420);
|
||||
|
||||
song = songRepo.retrieveSong(token, baseUri, song);
|
||||
|
||||
@@ -55,6 +54,15 @@ model::Song retrieveSong(const std::string& token, const std::string& baseUri)
|
||||
}
|
||||
|
||||
|
||||
model::User retrieveCredentials(const std::string& dataPath)
|
||||
{
|
||||
repository::local::UserRepository userRepo;
|
||||
auto user = userRepo.retrieveUserCredentials(dataPath);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
std::string fetchToken(const std::string& username, const std::string& password,
|
||||
const std::string& apiUri)
|
||||
{
|
||||
@@ -68,6 +76,22 @@ std::string fetchToken(const std::string& username, const std::string& password,
|
||||
}
|
||||
|
||||
|
||||
bool doesDatabaseExist(const std::string& dataPath)
|
||||
{
|
||||
repository::local::UserRepository userRepo;
|
||||
const auto result = userRepo.databaseExist(dataPath);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool userCredentialExist(const std::string& dataPath)
|
||||
{
|
||||
repository::local::UserRepository userRepo;
|
||||
|
||||
return userRepo.isTableEmpty(dataPath);
|
||||
}
|
||||
|
||||
|
||||
void iterateDirectory(const std::string& path)
|
||||
{
|
||||
/**
|
||||
@@ -85,58 +109,37 @@ void iterateDirectory(const std::string& path)
|
||||
|
||||
void saveCredentials(const model::User& user, const std::string& appDirectory)
|
||||
{
|
||||
std::string filePath(appDirectory);
|
||||
filePath.append("/");
|
||||
repository::local::UserRepository userRepo;
|
||||
|
||||
if (!userRepo.databaseExist(filePath)) {
|
||||
userRepo.initializedDatabase(filePath);
|
||||
if (!userRepo.databaseExist(appDirectory)) {
|
||||
userRepo.initializedDatabase(appDirectory);
|
||||
}
|
||||
if (!userRepo.doesUserTableExist(filePath)) {
|
||||
userRepo.createUserTable(filePath);
|
||||
if (!userRepo.doesUserTableExist(appDirectory)) {
|
||||
userRepo.createUserTable(appDirectory);
|
||||
}
|
||||
|
||||
if (userRepo.isTableEmpty(filePath)) {
|
||||
userRepo.deleteUserTable(filePath);
|
||||
if (userRepo.isTableEmpty(appDirectory)) {
|
||||
userRepo.deleteUserTable(appDirectory);
|
||||
}
|
||||
|
||||
userRepo.saveUserCred(user, filePath);
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring
|
||||
JNICALL
|
||||
Java_com_example_mear_activities_DemoStreamActivity_logUser(
|
||||
JNIEnv *env,
|
||||
jobject thisObj,
|
||||
jstring username,
|
||||
jstring password,
|
||||
jstring apiUri ) {
|
||||
|
||||
const std::string usr = env->GetStringUTFChars(username, NULL);
|
||||
const std::string pass = env->GetStringUTFChars(password, NULL);
|
||||
const std::string api = env->GetStringUTFChars(apiUri, NULL);
|
||||
|
||||
auto token = fetchToken(usr, pass, api);
|
||||
|
||||
return env->NewStringUTF(token.c_str());
|
||||
userRepo.saveUserCred(user, appDirectory);
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject
|
||||
JNICALL
|
||||
Java_com_example_mear_activities_DemoStreamActivity_retrieveSong(
|
||||
Java_com_example_mear_activities_LoginActivity_retrieveSong(
|
||||
JNIEnv *env,
|
||||
jobject thisObj,
|
||||
jstring token,
|
||||
jstring apiUri
|
||||
)
|
||||
jstring apiUri,
|
||||
jint idOfSong
|
||||
)
|
||||
{
|
||||
const std::string tok = env->GetStringUTFChars(token, NULL);
|
||||
const std::string baseUri = env->GetStringUTFChars(apiUri, NULL);
|
||||
auto song = retrieveSong(tok, baseUri);
|
||||
auto song = retrieveSong(tok, baseUri, idOfSong);
|
||||
|
||||
jclass songClass = env->FindClass( "com/example/mear/models/Song");
|
||||
jmethodID jconstructor = env->GetMethodID( songClass, "<init>", "()V" );
|
||||
@@ -169,11 +172,87 @@ Java_com_example_mear_activities_DemoStreamActivity_retrieveSong(
|
||||
return songObj;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject
|
||||
JNICALL
|
||||
Java_com_example_mear_activities_LoginActivity_retrieveUserCredentials(
|
||||
JNIEnv *env,
|
||||
jobject thisObj,
|
||||
jstring dataPath
|
||||
) {
|
||||
jclass userClass = env->FindClass("com/example/mear/models/User");
|
||||
jmethodID userContructor = env->GetMethodID(userClass, "<init>", "()V");
|
||||
jobject userObj = env->NewObject(userClass, userContructor);
|
||||
|
||||
const std::string dataPathStr = env->GetStringUTFChars(dataPath, nullptr);
|
||||
auto user = retrieveCredentials(dataPathStr);
|
||||
|
||||
jmethodID usernameId = env->GetMethodID(userClass, "setUsername", "(Ljava/lang/String;)V");
|
||||
jmethodID passwordId = env->GetMethodID(userClass, "setPassword", "(Ljava/lang/String;)V");
|
||||
|
||||
jstring username = env->NewStringUTF(user.username.c_str());
|
||||
jstring password = env->NewStringUTF(user.password.c_str());
|
||||
|
||||
env->CallVoidMethod(userObj, usernameId, username);
|
||||
env->CallVoidMethod(userObj, passwordId, password);
|
||||
|
||||
return userObj;
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring
|
||||
JNICALL
|
||||
Java_com_example_mear_activities_LoginActivity_logUser(
|
||||
JNIEnv *env,
|
||||
jobject thisObj,
|
||||
jstring username,
|
||||
jstring password,
|
||||
jstring apiUri ) {
|
||||
|
||||
const std::string usr = env->GetStringUTFChars(username, NULL);
|
||||
const std::string pass = env->GetStringUTFChars(password, NULL);
|
||||
const std::string api = env->GetStringUTFChars(apiUri, NULL);
|
||||
|
||||
auto token = fetchToken(usr, pass, api);
|
||||
|
||||
return env->NewStringUTF(token.c_str());
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean
|
||||
JNICALL
|
||||
Java_com_example_mear_activities_LoginActivity_isUserTableEmpty(
|
||||
JNIEnv *env,
|
||||
jobject thisObj,
|
||||
jstring dataPath
|
||||
) {
|
||||
const std::string dataPathStr = env->GetStringUTFChars(dataPath, NULL);
|
||||
jboolean result = userCredentialExist(dataPathStr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean
|
||||
JNICALL
|
||||
Java_com_example_mear_activities_LoginActivity_doesDatabaseExist(
|
||||
JNIEnv *env,
|
||||
jobject thidObj,
|
||||
jstring dataPath
|
||||
) {
|
||||
const std::string dataPathStr = env->GetStringUTFChars(dataPath, NULL);
|
||||
jboolean result = doesDatabaseExist(dataPathStr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void
|
||||
JNICALL
|
||||
Java_com_example_mear_activities_DemoStreamActivity_pathIteratorDemo(
|
||||
Java_com_example_mear_activities_LoginActivity_pathIteratorDemo(
|
||||
JNIEnv *env,
|
||||
jobject thisObj,
|
||||
jstring path
|
||||
@@ -187,21 +266,18 @@ Java_com_example_mear_activities_DemoStreamActivity_pathIteratorDemo(
|
||||
extern "C"
|
||||
JNIEXPORT void
|
||||
JNICALL
|
||||
Java_com_example_mear_activities_DemoStreamActivity_saveUserCredentials(
|
||||
Java_com_example_mear_activities_LoginActivity_saveUserCredentials(
|
||||
JNIEnv *env,
|
||||
jobject thisObj,
|
||||
jstring username,
|
||||
jstring password,
|
||||
jstring appDirectory
|
||||
) {
|
||||
|
||||
const std::string usernameStr = env->GetStringUTFChars(username, NULL);
|
||||
const std::string passwordStr = env->GetStringUTFChars(password, NULL);
|
||||
const std::string appDirectoryStr = env->GetStringUTFChars(appDirectory, NULL);
|
||||
|
||||
model::User user;
|
||||
user.username = usernameStr;
|
||||
user.password = passwordStr;
|
||||
model::User user(usernameStr, passwordStr);
|
||||
|
||||
saveCredentials(user, appDirectoryStr);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace repository { namespace local {
|
||||
try {
|
||||
const auto dbPath = pathOfDatabase(appPath);
|
||||
SQLite::Database db(dbPath, SQLite::OPEN_READONLY);
|
||||
//SQLite::Database db(m_tableName, SQLite::OPEN_READONLY);
|
||||
|
||||
std::string queryString("SELECT * FROM ");
|
||||
queryString.append(m_tableName);
|
||||
@@ -50,7 +49,6 @@ namespace repository { namespace local {
|
||||
try {
|
||||
const auto dbPath = pathOfDatabase(appPath);
|
||||
SQLite::Database db(dbPath, SQLite::OPEN_READONLY);
|
||||
//SQLite::Database db(m_tableName, SQLite::OPEN_READONLY);
|
||||
|
||||
return db.tableExists(m_tableName);
|
||||
} catch (std::exception& ex) {
|
||||
@@ -66,7 +64,6 @@ namespace repository { namespace local {
|
||||
try {
|
||||
const auto dbPath = pathOfDatabase(appPath);
|
||||
SQLite::Database db(dbPath, SQLite::OPEN_READWRITE);
|
||||
//SQLite::Database db(m_tableName, SQLite::OPEN_READWRITE);
|
||||
|
||||
std::string queryString("CREATE TABLE ");
|
||||
queryString.append(m_tableName);
|
||||
@@ -97,7 +94,6 @@ namespace repository { namespace local {
|
||||
try {
|
||||
const auto dbPath = pathOfDatabase(appPath);
|
||||
SQLite::Database db(dbPath, SQLite::OPEN_READWRITE);
|
||||
//SQLite::Database db(m_tableName, SQLite::OPEN_READWRITE);
|
||||
std::string queryString("INSERT INTO ");
|
||||
queryString.append(m_tableName);
|
||||
queryString.append(" (Username, Password) VALUES (?, ?)");
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace repository { namespace local {
|
||||
|
||||
model::User retrieveUserCredentials(const std::string&);
|
||||
|
||||
bool isEmpty(const std::string&);
|
||||
bool doesUserTableExist(const std::string&);
|
||||
|
||||
void createUserTable(const std::string&);
|
||||
|
||||
@@ -10,8 +10,22 @@
|
||||
|
||||
namespace model {
|
||||
|
||||
struct Song
|
||||
class Song
|
||||
{
|
||||
public:
|
||||
Song() = default;
|
||||
Song(const int id, const std::string& title, const std::string& artist,
|
||||
const std::string& album, const std::string& genre,
|
||||
const int duration, const int year) :
|
||||
id(id), title(title), artist(artist), album(album),
|
||||
genre(genre), duration(duration), year(year) { }
|
||||
Song(const int id, const std::string&& title, const std::string&& artist,
|
||||
const std::string&& album, const std::string&& genre,
|
||||
const int duration, const int year) :
|
||||
id(id), title(std::move(title)), artist(std::move(artist)),
|
||||
album(std::move(album)), genre(std::move(genre)), duration(duration),
|
||||
year(year) { }
|
||||
|
||||
int id;
|
||||
std::string title;
|
||||
std::string artist;
|
||||
|
||||
@@ -6,14 +6,17 @@
|
||||
#define MEAR_TOKEN_H
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace model {
|
||||
class Token
|
||||
{
|
||||
public:
|
||||
Token(const std::string& token) : token(token) { }
|
||||
Token(const std::string& accessToken) : accessToken(accessToken) { }
|
||||
Token(const std::string&& accessToken) :
|
||||
accessToken(std::move(accessToken)) { }
|
||||
|
||||
std::string token;
|
||||
std::string accessToken;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,18 @@
|
||||
#ifndef MEAR_USER_H
|
||||
#define MEAR_USER_H
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace model {
|
||||
struct User
|
||||
class User
|
||||
{
|
||||
public:
|
||||
User() = default;
|
||||
User(const std::string& user, const std::string& pass) :
|
||||
username(user), password(pass) { }
|
||||
User(const std::string&& user, const std::string&& pass) :
|
||||
username(std::move(user)), password(std::move(pass)) {}
|
||||
|
||||
std::string username;
|
||||
std::string password;
|
||||
|
||||
+31
-20
@@ -3,16 +3,16 @@ package com.example.mear.activities
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.support.design.widget.Snackbar
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import com.example.mear.R
|
||||
|
||||
import kotlinx.android.synthetic.main.activity_demo_stream.*
|
||||
import kotlinx.android.synthetic.main.content_demo_stream.*
|
||||
import kotlinx.android.synthetic.main.activity_login.*
|
||||
import kotlinx.android.synthetic.main.content_login.*
|
||||
import org.jetbrains.anko.toast
|
||||
|
||||
import com.example.mear.models.Song
|
||||
import com.example.mear.models.User
|
||||
|
||||
class DemoStreamActivity : BaseServiceActivity() {
|
||||
class LoginActivity : BaseServiceActivity() {
|
||||
|
||||
companion object {
|
||||
init {
|
||||
@@ -21,22 +21,31 @@ class DemoStreamActivity : BaseServiceActivity() {
|
||||
}
|
||||
|
||||
|
||||
private var token: String? = null
|
||||
private external fun retrieveSong(tok: String, api: String, songId: Int): Song
|
||||
|
||||
private external fun retrieveUserCredentials(path: String): User
|
||||
|
||||
// TODO: add external call to retrieve User credentials
|
||||
private external fun logUser(usr: String, pass: String, api: String): String
|
||||
private external fun retrieveSong(tok: String, api: String): Song
|
||||
//private external fun testSongStream(tok: String, id: Int)
|
||||
|
||||
private external fun doesDatabaseExist(path: String): Boolean
|
||||
private external fun isUserTableEmpty(path: String): Boolean
|
||||
|
||||
private external fun pathIteratorDemo(path: String)
|
||||
private external fun saveUserCredentials(username: String, password: String, appDir: String)
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_demo_stream)
|
||||
setContentView(R.layout.activity_login)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
val pa = appDirectory()
|
||||
if (doesDatabaseExist(pa) && !isUserTableEmpty(pa)) {
|
||||
val usr = retrieveUserCredentials(pa)
|
||||
username.setText(usr.username)
|
||||
password.setText(usr.password)
|
||||
}
|
||||
|
||||
doBindService()
|
||||
|
||||
demoStream.setOnClickListener {
|
||||
@@ -69,19 +78,14 @@ class DemoStreamActivity : BaseServiceActivity() {
|
||||
apiUriStr = ""
|
||||
}
|
||||
|
||||
token = logUser(usernameStr, passwordStr, apiUriStr)
|
||||
val token = logUser(usernameStr, passwordStr, apiUriStr)
|
||||
|
||||
try {
|
||||
|
||||
val s = retrieveSong(token!!, apiUriStr)
|
||||
musicService!!.icarusPlaySong(this.applicationContext, token!!, apiUriStr, s)
|
||||
val dir = Environment.getExternalStorageDirectory().absolutePath + "/music"
|
||||
val appRelPath: String = resources.getString(R.string.app_relative_path)
|
||||
var inStoragePath = Environment.getDataDirectory().toString()
|
||||
inStoragePath += "/data/$appRelPath"
|
||||
|
||||
if (saveCred) {
|
||||
saveUserCredentials(usernameStr, passwordStr, inStoragePath)
|
||||
val songId = 4
|
||||
val song = retrieveSong(token, apiUriStr, songId)
|
||||
val pa = appDirectory()
|
||||
if (saveCred && isUserTableEmpty(pa)) {
|
||||
saveUserCredentials(usernameStr, passwordStr, pa)
|
||||
}
|
||||
}
|
||||
catch (ex: Exception) {
|
||||
@@ -89,6 +93,13 @@ class DemoStreamActivity : BaseServiceActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun appDirectory(): String {
|
||||
return Environment.getDataDirectory().toString() + "/data/" +
|
||||
resources.getString(R.string.app_relative_path)
|
||||
}
|
||||
|
||||
|
||||
private fun validFields(): Boolean {
|
||||
if (username.text.isEmpty()) {
|
||||
return false
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.example.mear.constants
|
||||
|
||||
import android.os.Bundle
|
||||
import android.content.res.Resources
|
||||
import android.os.Environment
|
||||
import com.example.mear.R
|
||||
|
||||
import kotlinx.android.synthetic.main.activity_login.*
|
||||
import kotlinx.android.synthetic.main.content_login.*
|
||||
|
||||
object AppDataPath {
|
||||
val APP_DATA_PATH: String = Environment.getDataDirectory().toString()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.example.mear.models
|
||||
|
||||
class Token (var accessToken: String = "")
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.example.mear.models
|
||||
|
||||
class User (var username: String = "", var password: String = "")
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activities.DemoStreamActivity">
|
||||
tools:context=".activities.LoginActivity">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -28,6 +28,6 @@
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
app:srcCompat="@android:drawable/ic_dialog_email" />
|
||||
|
||||
<include layout="@layout/content_demo_stream" />
|
||||
<include layout="@layout/content_login" />
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
+3
-4
@@ -5,8 +5,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:context=".activities.DemoStreamActivity"
|
||||
tools:showIn="@layout/activity_demo_stream">
|
||||
tools:context=".activities.LoginActivity"
|
||||
tools:showIn="@layout/activity_login">
|
||||
|
||||
<Button
|
||||
android:id="@+id/demoStream"
|
||||
@@ -27,7 +27,6 @@
|
||||
android:ems="10"
|
||||
android:hint="username"
|
||||
android:inputType="textPersonName"
|
||||
android:text="kverse"
|
||||
app:layout_constraintBottom_toTopOf="@+id/password"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
@@ -40,7 +39,6 @@
|
||||
android:ems="10"
|
||||
android:hint="password"
|
||||
android:inputType="textPassword"
|
||||
android:text="demolaugh"
|
||||
app:layout_constraintBottom_toTopOf="@+id/apiUri"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
@@ -53,6 +51,7 @@
|
||||
android:ems="10"
|
||||
android:hint="apiUri"
|
||||
android:inputType="textPersonName"
|
||||
android:text="https://www.soaricarus.com"
|
||||
app:layout_constraintBottom_toTopOf="@+id/saveUserCred"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
Reference in New Issue
Block a user