mirror of
https://github.com/vernu/textbee.git
synced 2026-02-20 15:44:31 -05:00
ui(android): major ui/ux improvement on the android app and add crashlytics
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'com.google.gms.google-services'
|
||||
id 'com.google.firebase.crashlytics'
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -37,7 +38,7 @@ android {
|
||||
dependencies {
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation 'com.google.android.material:material:1.8.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
@@ -47,6 +48,7 @@ dependencies {
|
||||
implementation 'com.google.firebase:firebase-analytics'
|
||||
implementation 'com.google.firebase:firebase-messaging'
|
||||
implementation 'com.google.firebase:firebase-messaging-directboot'
|
||||
implementation 'com.google.firebase:firebase-crashlytics'
|
||||
|
||||
implementation 'com.google.code.gson:gson:2.9.0'
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||
|
||||
@@ -55,7 +55,8 @@
|
||||
|
||||
<activity
|
||||
android:name=".activities.MainActivity"
|
||||
android:exported="true">
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.SMSGateway.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
||||
@@ -7,16 +7,21 @@ import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics;
|
||||
import com.vernu.sms.services.StickyNotificationService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TextBeeUtils {
|
||||
private static final String TAG = "TextBeeUtils";
|
||||
|
||||
public static boolean isPermissionGranted(Context context, String permission) {
|
||||
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
@@ -50,4 +55,53 @@ public class TextBeeUtils {
|
||||
Intent notificationIntent = new Intent(context, StickyNotificationService.class);
|
||||
context.stopService(notificationIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a non-fatal exception to Crashlytics with additional context information
|
||||
*
|
||||
* @param throwable The exception to log
|
||||
* @param message A message describing what happened
|
||||
* @param customData Optional map of custom key-value pairs to add as context
|
||||
*/
|
||||
public static void logException(Throwable throwable, String message, Map<String, Object> customData) {
|
||||
try {
|
||||
Log.e(TAG, message, throwable);
|
||||
|
||||
FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
|
||||
crashlytics.log(message);
|
||||
|
||||
// Add any custom data as key-value pairs
|
||||
if (customData != null) {
|
||||
for (Map.Entry<String, Object> entry : customData.entrySet()) {
|
||||
if (entry.getValue() instanceof String) {
|
||||
crashlytics.setCustomKey(entry.getKey(), (String) entry.getValue());
|
||||
} else if (entry.getValue() instanceof Boolean) {
|
||||
crashlytics.setCustomKey(entry.getKey(), (Boolean) entry.getValue());
|
||||
} else if (entry.getValue() instanceof Integer) {
|
||||
crashlytics.setCustomKey(entry.getKey(), (Integer) entry.getValue());
|
||||
} else if (entry.getValue() instanceof Long) {
|
||||
crashlytics.setCustomKey(entry.getKey(), (Long) entry.getValue());
|
||||
} else if (entry.getValue() instanceof Float) {
|
||||
crashlytics.setCustomKey(entry.getKey(), (Float) entry.getValue());
|
||||
} else if (entry.getValue() instanceof Double) {
|
||||
crashlytics.setCustomKey(entry.getKey(), (Double) entry.getValue());
|
||||
} else if (entry.getValue() != null) {
|
||||
crashlytics.setCustomKey(entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Record the exception
|
||||
crashlytics.recordException(throwable);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error logging exception to Crashlytics", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified method to log a non-fatal exception with just a message
|
||||
*/
|
||||
public static void logException(Throwable throwable, String message) {
|
||||
logException(throwable, message, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.vernu.sms.R;
|
||||
import com.vernu.sms.dtos.RegisterDeviceInputDTO;
|
||||
import com.vernu.sms.dtos.RegisterDeviceResponseDTO;
|
||||
import com.vernu.sms.helpers.SharedPreferenceHelper;
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import retrofit2.Call;
|
||||
@@ -41,10 +42,10 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private Context mContext;
|
||||
private Switch gatewaySwitch, receiveSMSSwitch;
|
||||
private EditText apiKeyEditText, fcmTokenEditText;
|
||||
private Button registerDeviceBtn, grantSMSPermissionBtn, scanQRBtn;
|
||||
private EditText apiKeyEditText, fcmTokenEditText, deviceIdEditText;
|
||||
private Button registerDeviceBtn, grantSMSPermissionBtn, scanQRBtn, checkUpdatesBtn;
|
||||
private ImageButton copyDeviceIdImgBtn;
|
||||
private TextView deviceBrandAndModelTxt, deviceIdTxt;
|
||||
private TextView deviceBrandAndModelTxt, deviceIdTxt, appVersionNameTxt, appVersionCodeTxt;
|
||||
private RadioGroup defaultSimSlotRadioGroup;
|
||||
private static final int SCAN_QR_REQUEST_CODE = 49374;
|
||||
private static final int PERMISSION_REQUEST_CODE = 0;
|
||||
@@ -62,6 +63,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
receiveSMSSwitch = findViewById(R.id.receiveSMSSwitch);
|
||||
apiKeyEditText = findViewById(R.id.apiKeyEditText);
|
||||
fcmTokenEditText = findViewById(R.id.fcmTokenEditText);
|
||||
deviceIdEditText = findViewById(R.id.deviceIdEditText);
|
||||
registerDeviceBtn = findViewById(R.id.registerDeviceBtn);
|
||||
grantSMSPermissionBtn = findViewById(R.id.grantSMSPermissionBtn);
|
||||
scanQRBtn = findViewById(R.id.scanQRButton);
|
||||
@@ -69,9 +71,25 @@ public class MainActivity extends AppCompatActivity {
|
||||
deviceIdTxt = findViewById(R.id.deviceIdTxt);
|
||||
copyDeviceIdImgBtn = findViewById(R.id.copyDeviceIdImgBtn);
|
||||
defaultSimSlotRadioGroup = findViewById(R.id.defaultSimSlotRadioGroup);
|
||||
appVersionNameTxt = findViewById(R.id.appVersionNameTxt);
|
||||
appVersionCodeTxt = findViewById(R.id.appVersionCodeTxt);
|
||||
checkUpdatesBtn = findViewById(R.id.checkUpdatesBtn);
|
||||
|
||||
deviceIdTxt.setText(deviceId);
|
||||
deviceIdEditText.setText(deviceId);
|
||||
deviceBrandAndModelTxt.setText(Build.BRAND + " " + Build.MODEL);
|
||||
|
||||
// Set app version information
|
||||
String versionName = BuildConfig.VERSION_NAME;
|
||||
appVersionNameTxt.setText(versionName);
|
||||
appVersionCodeTxt.setText(String.valueOf(BuildConfig.VERSION_CODE));
|
||||
|
||||
// Initialize Crashlytics with user information
|
||||
FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
|
||||
crashlytics.setCustomKey("device_id", deviceId != null ? deviceId : "not_registered");
|
||||
crashlytics.setCustomKey("device_model", Build.MODEL);
|
||||
crashlytics.setCustomKey("app_version", versionName);
|
||||
crashlytics.setCustomKey("app_version_code", BuildConfig.VERSION_CODE);
|
||||
|
||||
if (deviceId == null || deviceId.isEmpty()) {
|
||||
registerDeviceBtn.setText("Register");
|
||||
@@ -117,7 +135,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
public void onResponse(Call<RegisterDeviceResponseDTO> call, Response<RegisterDeviceResponseDTO> response) {
|
||||
Log.d(TAG, response.toString());
|
||||
if (!response.isSuccessful()) {
|
||||
Snackbar.make(view, response.message(), Snackbar.LENGTH_LONG).show();
|
||||
Snackbar.make(view, response.message().isEmpty() ? "An error occurred :( "+ response.code() : response.message(), Snackbar.LENGTH_LONG).show();
|
||||
compoundButton.setEnabled(true);
|
||||
return;
|
||||
}
|
||||
@@ -137,6 +155,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
Snackbar.make(view, "An error occurred :(", Snackbar.LENGTH_LONG).show();
|
||||
Log.e(TAG, "API_ERROR "+ t.getMessage());
|
||||
Log.e(TAG, "API_ERROR "+ t.getLocalizedMessage());
|
||||
TextBeeUtils.logException(t, "Error updating device");
|
||||
compoundButton.setEnabled(true);
|
||||
}
|
||||
});
|
||||
@@ -165,29 +184,50 @@ public class MainActivity extends AppCompatActivity {
|
||||
intentIntegrator.setRequestCode(SCAN_QR_REQUEST_CODE);
|
||||
intentIntegrator.initiateScan();
|
||||
});
|
||||
|
||||
checkUpdatesBtn.setOnClickListener(view -> {
|
||||
String versionInfo = BuildConfig.VERSION_NAME + "(" + BuildConfig.VERSION_CODE + ")";
|
||||
String encodedVersionInfo = android.net.Uri.encode(versionInfo);
|
||||
String downloadUrl = "https://textbee.dev/download?currentVersion=" + encodedVersionInfo;
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(downloadUrl));
|
||||
startActivity(browserIntent);
|
||||
});
|
||||
}
|
||||
|
||||
private void renderAvailableSimOptions() {
|
||||
try {
|
||||
defaultSimSlotRadioGroup.removeAllViews();
|
||||
|
||||
// Set radio group styling for dark mode compatibility
|
||||
defaultSimSlotRadioGroup.setBackgroundColor(getResources().getColor(R.color.background_secondary));
|
||||
defaultSimSlotRadioGroup.setPadding(16, 8, 16, 8);
|
||||
|
||||
// Create the default radio button with proper styling
|
||||
RadioButton defaultSimSlotRadioBtn = new RadioButton(mContext);
|
||||
defaultSimSlotRadioBtn.setText("Device Default");
|
||||
defaultSimSlotRadioBtn.setId((int)123456);
|
||||
applyRadioButtonStyle(defaultSimSlotRadioBtn);
|
||||
defaultSimSlotRadioGroup.addView(defaultSimSlotRadioBtn);
|
||||
|
||||
// Create radio buttons for each SIM with proper styling
|
||||
TextBeeUtils.getAvailableSimSlots(mContext).forEach(subscriptionInfo -> {
|
||||
String simInfo = "SIM " + (subscriptionInfo.getSimSlotIndex() + 1) + " (" + subscriptionInfo.getDisplayName() + ")";
|
||||
RadioButton radioButton = new RadioButton(mContext);
|
||||
radioButton.setText(simInfo);
|
||||
radioButton.setId(subscriptionInfo.getSubscriptionId());
|
||||
applyRadioButtonStyle(radioButton);
|
||||
defaultSimSlotRadioGroup.addView(radioButton);
|
||||
});
|
||||
|
||||
// Check the preferred SIM based on saved preferences
|
||||
int preferredSim = SharedPreferenceHelper.getSharedPreferenceInt(mContext, AppConstants.SHARED_PREFS_PREFERRED_SIM_KEY, -1);
|
||||
if (preferredSim == -1) {
|
||||
defaultSimSlotRadioGroup.check(defaultSimSlotRadioBtn.getId());
|
||||
} else {
|
||||
defaultSimSlotRadioGroup.check(preferredSim);
|
||||
}
|
||||
|
||||
// Set the listener for SIM selection changes
|
||||
defaultSimSlotRadioGroup.setOnCheckedChangeListener((radioGroup, i) -> {
|
||||
RadioButton radioButton = findViewById(i);
|
||||
if (radioButton == null) {
|
||||
@@ -205,6 +245,42 @@ public class MainActivity extends AppCompatActivity {
|
||||
Log.e(TAG, "SIM_SLOT_ERROR "+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the custom radio button style to a programmatically created radio button
|
||||
*/
|
||||
private void applyRadioButtonStyle(RadioButton radioButton) {
|
||||
// Set text color using the color state list for proper dark/light mode handling
|
||||
setRadioButtonTextColor(radioButton);
|
||||
|
||||
// Set button tint for the radio circle
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
radioButton.setButtonTintList(getResources().getColorStateList(R.color.radio_button_tint, getTheme()));
|
||||
} else {
|
||||
radioButton.setButtonTintList(getResources().getColorStateList(R.color.radio_button_tint));
|
||||
}
|
||||
}
|
||||
|
||||
// Add proper padding for better touch experience
|
||||
radioButton.setPadding(
|
||||
radioButton.getPaddingLeft() + 8,
|
||||
radioButton.getPaddingTop() + 12,
|
||||
radioButton.getPaddingRight(),
|
||||
radioButton.getPaddingBottom() + 12
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to set radio button text color in a backward-compatible way
|
||||
*/
|
||||
private void setRadioButtonTextColor(RadioButton radioButton) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
radioButton.setTextColor(getResources().getColorStateList(R.color.radio_button_text_color, getTheme()));
|
||||
} else {
|
||||
radioButton.setTextColor(getResources().getColorStateList(R.color.radio_button_text_color));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
|
||||
@@ -225,8 +301,9 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void handleRegisterDevice() {
|
||||
|
||||
String newKey = apiKeyEditText.getText().toString();
|
||||
String deviceIdInput = deviceIdEditText.getText().toString();
|
||||
|
||||
registerDeviceBtn.setEnabled(false);
|
||||
registerDeviceBtn.setText("Loading...");
|
||||
View view = findViewById(R.id.registerDeviceBtn);
|
||||
@@ -252,6 +329,50 @@ public class MainActivity extends AppCompatActivity {
|
||||
registerDeviceInput.setOs(Build.VERSION.BASE_OS);
|
||||
registerDeviceInput.setAppVersionCode(BuildConfig.VERSION_CODE);
|
||||
registerDeviceInput.setAppVersionName(BuildConfig.VERSION_NAME);
|
||||
|
||||
// If the user provided a device ID, use it for updating instead of creating new
|
||||
if (!deviceIdInput.isEmpty()) {
|
||||
Log.d(TAG, "Updating device with deviceId: "+ deviceIdInput);
|
||||
Call<RegisterDeviceResponseDTO> apiCall = ApiManager.getApiService().updateDevice(deviceIdInput, newKey, registerDeviceInput);
|
||||
apiCall.enqueue(new Callback<RegisterDeviceResponseDTO>() {
|
||||
@Override
|
||||
public void onResponse(Call<RegisterDeviceResponseDTO> call, Response<RegisterDeviceResponseDTO> response) {
|
||||
Log.d(TAG, response.toString());
|
||||
if (!response.isSuccessful()) {
|
||||
Snackbar.make(view, response.message().isEmpty() ? "An error occurred :( "+ response.code() : response.message(), Snackbar.LENGTH_LONG).show();
|
||||
registerDeviceBtn.setEnabled(true);
|
||||
registerDeviceBtn.setText("Update");
|
||||
return;
|
||||
}
|
||||
SharedPreferenceHelper.setSharedPreferenceString(mContext, AppConstants.SHARED_PREFS_API_KEY_KEY, newKey);
|
||||
Snackbar.make(view, "Device Updated Successfully :)", Snackbar.LENGTH_LONG).show();
|
||||
|
||||
// Update deviceId from response if available
|
||||
if (response.body() != null && response.body().data != null && response.body().data.get("_id") != null) {
|
||||
deviceId = response.body().data.get("_id").toString();
|
||||
deviceIdTxt.setText(deviceId);
|
||||
deviceIdEditText.setText(deviceId);
|
||||
SharedPreferenceHelper.setSharedPreferenceString(mContext, AppConstants.SHARED_PREFS_DEVICE_ID_KEY, deviceId);
|
||||
SharedPreferenceHelper.setSharedPreferenceBoolean(mContext, AppConstants.SHARED_PREFS_GATEWAY_ENABLED_KEY, registerDeviceInput.isEnabled());
|
||||
gatewaySwitch.setChecked(registerDeviceInput.isEnabled());
|
||||
}
|
||||
|
||||
registerDeviceBtn.setEnabled(true);
|
||||
registerDeviceBtn.setText("Update");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<RegisterDeviceResponseDTO> call, Throwable t) {
|
||||
Snackbar.make(view, "An error occurred :(", Snackbar.LENGTH_LONG).show();
|
||||
Log.e(TAG, "API_ERROR "+ t.getMessage());
|
||||
Log.e(TAG, "API_ERROR "+ t.getLocalizedMessage());
|
||||
TextBeeUtils.logException(t, "Error registering device");
|
||||
registerDeviceBtn.setEnabled(true);
|
||||
registerDeviceBtn.setText("Update");
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Call<RegisterDeviceResponseDTO> apiCall = ApiManager.getApiService().registerDevice(newKey, registerDeviceInput);
|
||||
apiCall.enqueue(new Callback<RegisterDeviceResponseDTO>() {
|
||||
@@ -259,25 +380,32 @@ public class MainActivity extends AppCompatActivity {
|
||||
public void onResponse(Call<RegisterDeviceResponseDTO> call, Response<RegisterDeviceResponseDTO> response) {
|
||||
Log.d(TAG, response.toString());
|
||||
if (!response.isSuccessful()) {
|
||||
Snackbar.make(view, response.message(), Snackbar.LENGTH_LONG).show();
|
||||
Snackbar.make(view, response.message().isEmpty() ? "An error occurred :( "+ response.code() : response.message(), Snackbar.LENGTH_LONG).show();
|
||||
registerDeviceBtn.setEnabled(true);
|
||||
registerDeviceBtn.setText("Update");
|
||||
return;
|
||||
}
|
||||
SharedPreferenceHelper.setSharedPreferenceString(mContext, AppConstants.SHARED_PREFS_API_KEY_KEY, newKey);
|
||||
Snackbar.make(view, "Device Registration Successful :)", Snackbar.LENGTH_LONG).show();
|
||||
deviceId = response.body().data.get("_id").toString();
|
||||
deviceIdTxt.setText(deviceId);
|
||||
SharedPreferenceHelper.setSharedPreferenceString(mContext, AppConstants.SHARED_PREFS_DEVICE_ID_KEY, deviceId);
|
||||
|
||||
if (response.body() != null && response.body().data != null && response.body().data.get("_id") != null) {
|
||||
deviceId = response.body().data.get("_id").toString();
|
||||
deviceIdTxt.setText(deviceId);
|
||||
deviceIdEditText.setText(deviceId);
|
||||
SharedPreferenceHelper.setSharedPreferenceString(mContext, AppConstants.SHARED_PREFS_DEVICE_ID_KEY, deviceId);
|
||||
SharedPreferenceHelper.setSharedPreferenceBoolean(mContext, AppConstants.SHARED_PREFS_GATEWAY_ENABLED_KEY, registerDeviceInput.isEnabled());
|
||||
gatewaySwitch.setChecked(registerDeviceInput.isEnabled());
|
||||
}
|
||||
|
||||
registerDeviceBtn.setEnabled(true);
|
||||
registerDeviceBtn.setText("Update");
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Call<RegisterDeviceResponseDTO> call, Throwable t) {
|
||||
Snackbar.make(view, "An error occurred :(", Snackbar.LENGTH_LONG).show();
|
||||
Log.e(TAG, "API_ERROR "+ t.getMessage());
|
||||
Log.e(TAG, "API_ERROR "+ t.getLocalizedMessage());
|
||||
TextBeeUtils.logException(t, "Error registering device");
|
||||
registerDeviceBtn.setEnabled(true);
|
||||
registerDeviceBtn.setText("Update");
|
||||
}
|
||||
@@ -287,6 +415,9 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private void handleUpdateDevice() {
|
||||
String apiKey = apiKeyEditText.getText().toString();
|
||||
String deviceIdInput = deviceIdEditText.getText().toString();
|
||||
String deviceIdToUse = !deviceIdInput.isEmpty() ? deviceIdInput : deviceId;
|
||||
|
||||
registerDeviceBtn.setEnabled(false);
|
||||
registerDeviceBtn.setText("Loading...");
|
||||
View view = findViewById(R.id.registerDeviceBtn);
|
||||
@@ -313,18 +444,27 @@ public class MainActivity extends AppCompatActivity {
|
||||
updateDeviceInput.setAppVersionCode(BuildConfig.VERSION_CODE);
|
||||
updateDeviceInput.setAppVersionName(BuildConfig.VERSION_NAME);
|
||||
|
||||
Call<RegisterDeviceResponseDTO> apiCall = ApiManager.getApiService().updateDevice(deviceId, apiKey, updateDeviceInput);
|
||||
Call<RegisterDeviceResponseDTO> apiCall = ApiManager.getApiService().updateDevice(deviceIdToUse, apiKey, updateDeviceInput);
|
||||
apiCall.enqueue(new Callback<RegisterDeviceResponseDTO>() {
|
||||
@Override
|
||||
public void onResponse(Call<RegisterDeviceResponseDTO> call, Response<RegisterDeviceResponseDTO> response) {
|
||||
Log.d(TAG, response.toString());
|
||||
if (!response.isSuccessful()) {
|
||||
Snackbar.make(view, response.message(), Snackbar.LENGTH_LONG).show();
|
||||
Snackbar.make(view, response.message().isEmpty() ? "An error occurred :( "+ response.code() : response.message(), Snackbar.LENGTH_LONG).show();
|
||||
registerDeviceBtn.setEnabled(true);
|
||||
registerDeviceBtn.setText("Update");
|
||||
return;
|
||||
}
|
||||
SharedPreferenceHelper.setSharedPreferenceString(mContext, AppConstants.SHARED_PREFS_API_KEY_KEY, apiKey);
|
||||
|
||||
// Update deviceId from response if available
|
||||
if (response.body() != null && response.body().data != null && response.body().data.get("_id") != null) {
|
||||
deviceId = response.body().data.get("_id").toString();
|
||||
SharedPreferenceHelper.setSharedPreferenceString(mContext, AppConstants.SHARED_PREFS_DEVICE_ID_KEY, deviceId);
|
||||
deviceIdTxt.setText(deviceId);
|
||||
deviceIdEditText.setText(deviceId);
|
||||
}
|
||||
|
||||
Snackbar.make(view, "Device Updated Successfully :)", Snackbar.LENGTH_LONG).show();
|
||||
registerDeviceBtn.setEnabled(true);
|
||||
registerDeviceBtn.setText("Update");
|
||||
@@ -335,6 +475,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
Snackbar.make(view, "An error occurred :(", Snackbar.LENGTH_LONG).show();
|
||||
Log.e(TAG, "API_ERROR "+ t.getMessage());
|
||||
Log.e(TAG, "API_ERROR "+ t.getLocalizedMessage());
|
||||
TextBeeUtils.logException(t, "Error updating device");
|
||||
registerDeviceBtn.setEnabled(true);
|
||||
registerDeviceBtn.setText("Update");
|
||||
}
|
||||
@@ -364,7 +505,11 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
String scannedQR = intentResult.getContents();
|
||||
apiKeyEditText.setText(scannedQR);
|
||||
handleRegisterDevice();
|
||||
if(deviceIdEditText.getText().toString().isEmpty()) {
|
||||
handleRegisterDevice();
|
||||
} else {
|
||||
handleUpdateDevice();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_checked="true" android:color="?attr/colorPrimary" />
|
||||
<item android:state_enabled="false" android:color="@color/text_secondary" />
|
||||
<item android:color="@color/text_primary" />
|
||||
</selector>
|
||||
6
android/app/src/main/res/color/radio_button_tint.xml
Normal file
6
android/app/src/main/res/color/radio_button_tint.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_checked="true" android:color="?attr/colorPrimary" />
|
||||
<item android:state_enabled="false" android:color="@color/text_secondary" />
|
||||
<item android:color="@color/text_secondary" />
|
||||
</selector>
|
||||
10
android/app/src/main/res/drawable/ic_baseline_edit_24.xml
Normal file
10
android/app/src/main/res/drawable/ic_baseline_edit_24.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||
</vector>
|
||||
10
android/app/src/main/res/drawable/ic_baseline_info_24.xml
Normal file
10
android/app/src/main/res/drawable/ic_baseline_info_24.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
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>
|
||||
@@ -1,164 +1,122 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<RelativeLayout 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:layout_height="match_parent"
|
||||
android:background="@color/background_primary"
|
||||
tools:context=".activities.MainActivity">
|
||||
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scrollView2"
|
||||
<!-- Sticky Header Section -->
|
||||
<LinearLayout
|
||||
android:id="@+id/stickyHeader"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Header Section -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:background="?attr/colorPrimary"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enter your API key or scan the QR code below to get started"
|
||||
android:textSize="20dp"
|
||||
android:layout_margin="5dp"
|
||||
android:textAlignment="center"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#ccccccee"
|
||||
android:layout_margin="5dp"
|
||||
android:orientation="horizontal">
|
||||
android:text="textbee.dev - sms gateway"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/apiKeyEditText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:hint="API Key"
|
||||
android:inputType="text"
|
||||
android:minHeight="48dp"
|
||||
android:textIsSelectable="true" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/fcmTokenEditText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:enabled="false"
|
||||
android:gravity="start|top"
|
||||
android:hint="FCM Token"
|
||||
android:inputType="textMultiLine"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/registerDeviceBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Register" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/scanQRButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:drawableTop="@drawable/ic_baseline_qr_code_24"
|
||||
android:text="Scan"
|
||||
android:textColor="@color/black"
|
||||
android:theme="@style/Theme.Design.Light" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="Your ultimate solution for seamless SMS communication"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Device Info Card -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="-24dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/background_secondary"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_margin="5dp"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:padding="6dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:padding="3dp"
|
||||
android:src="@drawable/ic_baseline_phone_android_24"
|
||||
android:tint="?attr/colorPrimary" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="5dp"
|
||||
android:src="@drawable/ic_baseline_phone_android_24" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="3dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
|
||||
android:id="@+id/deviceBrandAndModelTxt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Device Brand, Model"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical">
|
||||
android:text="Device ID:"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Device ID"
|
||||
android:textStyle="italic" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deviceIdTxt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="ae5ce05c05cde3" />
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/deviceIdTxt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="2dp"
|
||||
android:text="ae5ce05c05cde3"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<ImageButton
|
||||
|
||||
android:id="@+id/copyDeviceIdImgBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:src="@drawable/ic_baseline_content_copy_24" />
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:padding="2dp"
|
||||
android:src="@drawable/ic_baseline_content_copy_24"
|
||||
android:tint="?attr/colorPrimary" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@@ -172,132 +130,478 @@
|
||||
android:id="@+id/gatewaySwitch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:minHeight="32dp"
|
||||
android:text="" />
|
||||
android:minHeight="32dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Status"
|
||||
android:textSize="16dp"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
<!-- Scrollable Content -->
|
||||
<ScrollView
|
||||
android:id="@+id/scrollView2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/stickyHeader">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- API Key Registration Card -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="30dp"
|
||||
android:orientation="vertical"
|
||||
android:padding="10px">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Configuration"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:background="#000000" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/grantSMSPermissionBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Grant Permissions"
|
||||
android:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="TextBee will only work if you grant SMS Permissions"
|
||||
android:textSize="14dp"
|
||||
android:textStyle="italic" />
|
||||
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#000000" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/receiveSMSSwitch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:minHeight="32dp"
|
||||
android:text="Receive SMS" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Toggle this if you want to receive SMS"
|
||||
android:textSize="14dp"
|
||||
android:textStyle="italic" />
|
||||
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#000000" />
|
||||
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/background_secondary"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Account Information"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- Device ID Input Field -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="Device ID (optional)"
|
||||
app:boxBackgroundColor="@android:color/transparent"
|
||||
app:boxStrokeColor="?attr/colorPrimary"
|
||||
app:hintTextColor="?attr/colorPrimary"
|
||||
app:endIconMode="custom"
|
||||
app:endIconDrawable="@drawable/ic_baseline_edit_24"
|
||||
app:endIconTint="?attr/colorPrimary"
|
||||
app:helperText="Leaving this field blank will register your device as new. If you have already registered this device previously, please enter the id here."
|
||||
app:helperTextTextColor="@color/text_secondary">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/deviceIdEditText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textIsSelectable="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="API Key"
|
||||
app:boxBackgroundColor="@android:color/transparent"
|
||||
app:boxStrokeColor="?attr/colorPrimary"
|
||||
app:hintTextColor="?attr/colorPrimary">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/apiKeyEditText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textIsSelectable="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/fcmTokenEditText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:enabled="false"
|
||||
android:gravity="start|top"
|
||||
android:hint="FCM Token"
|
||||
android:inputType="textMultiLine"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textColorHint="@color/text_secondary"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/registerDeviceBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:text="Connect"
|
||||
android:textColor="@color/white" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
<Button
|
||||
android:id="@+id/scanQRButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="5dp"
|
||||
android:drawableLeft="@drawable/ic_baseline_qr_code_24"
|
||||
android:text="Scan QR"
|
||||
android:textColor="@color/black"
|
||||
android:theme="@style/Theme.Design.Light" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- Configuration Card -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/background_secondary"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Configuration"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- Permissions Section -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="SMS Permissions"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="REQUIRED for textbee to function!"
|
||||
android:textColor="@android:color/holo_red_dark"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/grantSMSPermissionBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
android:text="Grant SMS Permissions"
|
||||
android:textColor="@color/white"
|
||||
android:visibility="visible" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/divider"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<!-- Receive SMS Toggle -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Receive SMS"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Toggle to enable SMS receiving"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<Switch
|
||||
android:id="@+id/receiveSMSSwitch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="32dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/divider"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<!-- Default SIM Selection -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Default SIM"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="Select your preferred SIM for sending SMS"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/defaultSimSlotRadioGroup"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"></RadioGroup>
|
||||
android:orientation="vertical"
|
||||
android:layout_marginStart="8dp" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Select your preferred SIM for sending SMS"
|
||||
android:textSize="14dp"
|
||||
android:textStyle="italic" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
<!-- How To Use Card -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#ccccccee"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="30dp"
|
||||
android:padding="12dp">
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardBackgroundColor="@color/background_secondary"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<TextView
|
||||
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="How To Use"
|
||||
android:textStyle="bold" />
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="How To Use"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:gravity="center"
|
||||
android:text="1"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Go to textbee.dev/dashboard"
|
||||
android:textColor="@color/text_primary" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:gravity="center"
|
||||
android:text="2"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Click 'Generate API Key / Get Started'"
|
||||
android:textColor="@color/text_primary" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:gravity="center"
|
||||
android:text="3"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Copy the API key or scan the QR code"
|
||||
android:textColor="@color/text_primary" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- App Version Info Card -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:cardBackgroundColor="@color/background_secondary"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Go to textbee.dev/dashboard and click `generate API Key / Get started`, then copy and paste the API key generated or scan the QR code" />
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@drawable/ic_baseline_info_24"
|
||||
android:tint="?attr/colorPrimary"
|
||||
android:layout_marginEnd="12dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="App Information"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="4dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Version: "
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/appVersionNameTxt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="1.0.0"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=" (Build: "
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginStart="4dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/appVersionCodeTxt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="100"
|
||||
android:textColor="@color/text_primary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=")"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/checkUpdatesBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="Check for Updates"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:background="@android:color/transparent"
|
||||
android:textAllCaps="false"
|
||||
android:paddingHorizontal="0dp"
|
||||
style="@style/Widget.AppCompat.Button.Borderless" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
17
android/app/src/main/res/values-night/colors.xml
Normal file
17
android/app/src/main/res/values-night/colors.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="purple_200">#FFBB86FC</color>
|
||||
<color name="purple_500">#FF6200EE</color>
|
||||
<color name="purple_700">#FF3700B3</color>
|
||||
<color name="teal_200">#FF03DAC5</color>
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
|
||||
<!-- Dark mode specific colors -->
|
||||
<color name="background_primary">#121212</color>
|
||||
<color name="background_secondary">#1E1E1E</color>
|
||||
<color name="text_primary">#FFFFFF</color>
|
||||
<color name="text_secondary">#B3FFFFFF</color> <!-- 70% white -->
|
||||
<color name="divider">#454545</color>
|
||||
</resources>
|
||||
@@ -11,6 +11,33 @@
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
<!-- Dark mode specific overrides -->
|
||||
<item name="android:textColorPrimary">@color/text_primary</item>
|
||||
<item name="android:textColorSecondary">@color/text_secondary</item>
|
||||
<item name="android:windowBackground">@color/background_primary</item>
|
||||
<item name="android:colorBackground">@color/background_primary</item>
|
||||
<item name="android:editTextColor">@color/text_primary</item>
|
||||
<item name="android:textColorHint">@color/text_secondary</item>
|
||||
</style>
|
||||
|
||||
<!-- Theme without action bar for MainActivity -->
|
||||
<style name="Theme.SMSGateway.NoActionBar" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">#4299E1</item>
|
||||
<item name="colorPrimaryVariant">#4299cc</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">#f35b04</item>
|
||||
<item name="colorSecondaryVariant">#f18701</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<!-- Dark mode specific overrides -->
|
||||
<item name="android:textColorPrimary">@color/text_primary</item>
|
||||
<item name="android:textColorSecondary">@color/text_secondary</item>
|
||||
<item name="android:windowBackground">@color/background_primary</item>
|
||||
<item name="android:colorBackground">@color/background_primary</item>
|
||||
<item name="android:editTextColor">@color/text_primary</item>
|
||||
<item name="android:textColorHint">@color/text_secondary</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -7,4 +7,11 @@
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
|
||||
<!-- Light mode specific colors -->
|
||||
<color name="background_primary">#FFFFFF</color>
|
||||
<color name="background_secondary">#F5F5F5</color>
|
||||
<color name="text_primary">#000000</color>
|
||||
<color name="text_secondary">#757575</color>
|
||||
<color name="divider">#E0E0E0</color>
|
||||
</resources>
|
||||
10
android/app/src/main/res/values/styles.xml
Normal file
10
android/app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="RadioButtonStyle" parent="Widget.AppCompat.CompoundButton.RadioButton">
|
||||
<item name="android:textColor">@color/radio_button_text_color</item>
|
||||
<item name="android:paddingStart">8dp</item>
|
||||
<item name="android:paddingTop">12dp</item>
|
||||
<item name="android:paddingBottom">12dp</item>
|
||||
<item name="android:buttonTint">?attr/colorPrimary</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -13,4 +13,18 @@
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
<!-- Theme without action bar for MainActivity -->
|
||||
<style name="Theme.SMSGateway.NoActionBar" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">#4299E1</item>
|
||||
<item name="colorPrimaryVariant">#4299cc</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">#f35b04</item>
|
||||
<item name="colorSecondaryVariant">#f18701</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -3,6 +3,7 @@ plugins {
|
||||
id 'com.android.application' version '7.1.2' apply false
|
||||
id 'com.android.library' version '7.1.2' apply false
|
||||
id 'com.google.gms.google-services' version '4.3.10' apply true
|
||||
id 'com.google.firebase.crashlytics' version '2.9.9' apply false
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
|
||||
Reference in New Issue
Block a user