diff --git a/app/build.gradle b/app/build.gradle
index 74065d0..ec09982 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,6 +1,7 @@
-buildscript {
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
}
-apply plugin: 'com.android.application'
repositories {
maven { url 'https://dl.bintray.com/galtashma/maven' }
@@ -31,13 +32,18 @@ android {
}
}
+configurations {
+ cleanedAnnotations
+ implementation.exclude group: 'org.jetbrains' , module:'annotations'
+}
+
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
testImplementation 'junit:junit:4.13.1'
- androidTestImplementation 'androidx.test:runner:1.4.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.1'
diff --git a/app/src/androidTest/java/com/galtashma/parsedashboard/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/galtashma/parsedashboard/ExampleInstrumentedTest.java
deleted file mode 100644
index 7b7bcba..0000000
--- a/app/src/androidTest/java/com/galtashma/parsedashboard/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.galtashma.parsedashboard;
-
-import android.content.Context;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() throws Exception {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.galtashma.parsedashboard", appContext.getPackageName());
- }
-}
diff --git a/app/src/androidTest/java/com/galtashma/parsedashboard/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/galtashma/parsedashboard/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..955ea8f
--- /dev/null
+++ b/app/src/androidTest/java/com/galtashma/parsedashboard/ExampleInstrumentedTest.kt
@@ -0,0 +1,22 @@
+package com.galtashma.parsedashboard
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.galtashma.parsedashboard", appContext.packageName)
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7fc8700..c154b55 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,7 +18,8 @@
+ android:theme="@style/AppTheme.NoActionBar.Dark"
+ android:exported="true">
diff --git a/app/src/main/java/com/galtashma/parsedashboard/Const.java b/app/src/main/java/com/galtashma/parsedashboard/Const.java
deleted file mode 100644
index b0c0fa2..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/Const.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.galtashma.parsedashboard;
-
-/**
- * Created by gal on 3/14/18.
- */
-
-public class Const {
- public static final String TAG = "ParseDashboard";
-
- public static final String BUNDLE_KEY_PARSE_APP_NAME = "app_name";
- public static final String BUNDLE_KEY_CLASS_NAME = "table_name";
- public static final String BUNDLE_KEY_CLASS_FIELDS_NAME = "table_fields";
- public static final String BUNDLE_KEY_OBJECT_ID = "object_id";
-
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/Const.kt b/app/src/main/java/com/galtashma/parsedashboard/Const.kt
new file mode 100644
index 0000000..bcd5dfc
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/Const.kt
@@ -0,0 +1,13 @@
+package com.galtashma.parsedashboard
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+object Const {
+ const val TAG = "ParseDashboard"
+ const val BUNDLE_KEY_PARSE_APP_NAME = "app_name"
+ const val BUNDLE_KEY_CLASS_NAME = "table_name"
+ const val BUNDLE_KEY_CLASS_FIELDS_NAME = "table_fields"
+ const val BUNDLE_KEY_OBJECT_ID = "object_id"
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/Hash.java b/app/src/main/java/com/galtashma/parsedashboard/Hash.java
deleted file mode 100644
index 182f7d7..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/Hash.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.galtashma.parsedashboard;
-
-import android.util.Log;
-
-import java.security.MessageDigest;
-
-public class Hash {
- private static String salt = "1m4bqk";
- public static String sha1(String value) {
- try {
- MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
- messageDigest.update((value + salt).getBytes("UTF-8"));
- byte[] bytes = messageDigest.digest();
- StringBuilder buffer = new StringBuilder();
- for (byte b : bytes) {
- buffer.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
- }
- String result = buffer.toString();
- Log.d(Const.TAG, "Hash result " + result);
-
- return result;
- } catch (Exception ignored) {
- ignored.printStackTrace();
- return null;
- }
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/Hash.kt b/app/src/main/java/com/galtashma/parsedashboard/Hash.kt
new file mode 100644
index 0000000..e35ad14
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/Hash.kt
@@ -0,0 +1,32 @@
+package com.galtashma.parsedashboard
+
+import android.util.Log
+import java.security.MessageDigest
+import kotlin.experimental.and
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+object Hash {
+ private const val salt = "1m4bqk"
+
+ fun sha1(value: String): String? {
+ try {
+ val messageDigest = MessageDigest.getInstance("SHA-1")
+ messageDigest.update((value + salt).toByteArray(Charsets.UTF_8))
+ val bytes = messageDigest.digest()
+ val buffer = StringBuilder()
+ bytes.forEach {
+ buffer.append(((it and 0xff.toByte()) + 0x100).toString(16).drop(1))
+ }
+ val result = buffer.toString()
+ Log.d(Const.TAG, "Hash result $result")
+
+ return result
+ } catch (ignored: Exception) {
+ ignored.printStackTrace()
+ return null
+ }
+ }
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/ListPreferenceStore.java b/app/src/main/java/com/galtashma/parsedashboard/ListPreferenceStore.java
deleted file mode 100644
index 8a76620..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/ListPreferenceStore.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.galtashma.parsedashboard;
-
-import com.appizona.yehiahd.fastsave.FastSave;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ListPreferenceStore {
- private List list;
- private String prefId;
-
- public ListPreferenceStore(String prefId) {
- this.prefId = prefId;
- list = load();
- }
-
- public List getList() {
- return list;
- }
-
- public void add(String key) {
- if (!exists(key)) {
- list.add(key);
- save();
- }
- }
-
- public void remove(String key) {
- if (list.contains(key)) {
- list.remove(key);
- }
- save();
- }
-
- public void reset() {
- list = new ArrayList<>();
- save();
- }
-
- public boolean exists(String key) {
- return list.contains(key);
- }
-
- public boolean isEmpty() {
- return list.isEmpty();
- }
-
- public int size() {
- return list.size();
- }
-
- private void save() {
- FastSave.getInstance().saveObjectsList(prefId, list);
- }
-
- private List load() {
- List l = FastSave.getInstance().getObjectsList(prefId, String.class);
- if (l != null) {
- return l;
- }
- return new ArrayList<>();
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/ListPreferenceStore.kt b/app/src/main/java/com/galtashma/parsedashboard/ListPreferenceStore.kt
new file mode 100644
index 0000000..52b2867
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/ListPreferenceStore.kt
@@ -0,0 +1,48 @@
+package com.galtashma.parsedashboard
+
+import com.appizona.yehiahd.fastsave.FastSave
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+class ListPreferenceStore(private val prefId: String) {
+ var list = load()
+
+ fun add(key: String) {
+ if (!exists(key)) {
+ list.add(key)
+ save()
+ }
+ }
+
+ fun remove(key: String) {
+ if (list.contains(key)) {
+ list.remove(key)
+ }
+ save()
+ }
+
+ fun reset() {
+ list = mutableListOf()
+ save()
+ }
+
+ fun exists(key: String) = list.contains(key)
+
+ fun isEmpty() = list.isEmpty()
+
+ fun size() = list.size
+
+ private fun save() {
+ FastSave.getInstance().saveObjectsList(prefId, list)
+ }
+
+ private fun load(): MutableList {
+ val l = FastSave.getInstance().getObjectsList(prefId, String::class.java)
+ if (l != null) {
+ return l
+ }
+ return mutableListOf()
+ }
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/ParseDashboardApplication.java b/app/src/main/java/com/galtashma/parsedashboard/ParseDashboardApplication.java
deleted file mode 100644
index adc257f..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/ParseDashboardApplication.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.galtashma.parsedashboard;
-
-import android.app.Application;
-
-import com.appizona.yehiahd.fastsave.FastSave;
-
-public class ParseDashboardApplication extends Application {
- @Override
- public void onCreate() {
- super.onCreate();
- FastSave.init(getApplicationContext());
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/ParseDashboardApplication.kt b/app/src/main/java/com/galtashma/parsedashboard/ParseDashboardApplication.kt
new file mode 100644
index 0000000..a2c44d0
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/ParseDashboardApplication.kt
@@ -0,0 +1,15 @@
+package com.galtashma.parsedashboard
+
+import android.app.Application
+import com.appizona.yehiahd.fastsave.FastSave
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+class ParseDashboardApplication : Application() {
+ override fun onCreate() {
+ super.onCreate()
+ FastSave.init(applicationContext)
+ }
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/ParseField.java b/app/src/main/java/com/galtashma/parsedashboard/ParseField.java
deleted file mode 100644
index 01f16a3..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/ParseField.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.galtashma.parsedashboard;
-
-/**
- * Created by gal on 3/16/18.
- */
-
-public class ParseField {
-
- public String value;
- public String key;
-
- public ParseField(String key, String value) {
- this.key = key;
- this.value = value;
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/ParseField.kt b/app/src/main/java/com/galtashma/parsedashboard/ParseField.kt
new file mode 100644
index 0000000..e8170b7
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/ParseField.kt
@@ -0,0 +1,7 @@
+package com.galtashma.parsedashboard
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+class ParseField(val key: String, val value: String)
diff --git a/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfig.java b/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfig.java
deleted file mode 100644
index 9e7a936..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfig.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.galtashma.parsedashboard;
-
-/**
- * Created by gal on 3/16/18.
- */
-
-public class ParseServerConfig {
-
- public String appName;
- public String appId;
- public String masterKey;
- public String serverUrl;
-
- public ParseServerConfig(){}
-
- public ParseServerConfig(String appName, String appId, String masterKey, String appUrl) {
- this.appName = appName;
- this.appId = appId;
- this.masterKey = masterKey;
- this.serverUrl = appUrl;
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfig.kt b/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfig.kt
new file mode 100644
index 0000000..8731525
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfig.kt
@@ -0,0 +1,12 @@
+package com.galtashma.parsedashboard
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+class ParseServerConfig(
+ val appName: String = "",
+ val appId: String = "",
+ val masterKey: String = "",
+ val serverUrl: String = ""
+)
diff --git a/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfigStorage.java b/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfigStorage.java
deleted file mode 100644
index eb788bc..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfigStorage.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.galtashma.parsedashboard;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import com.afollestad.ason.AsonArray;
-
-import java.util.List;
-
-/**
- * Created by gal on 3/16/18.
- */
-
-public class ParseServerConfigStorage {
-
- private static final String PREF_KEY = "parse_server_key";
- private static final String PREF_SERVERS_KEY = "parse_server_config_key";
-
- private final Context context;
-
- public ParseServerConfigStorage(Context context) {
- this.context = context;
- }
-
- public void saveServer(ParseServerConfig config) {
- AsonArray servers = getServersAson();
- servers.add(config);
- overrideServersAson(servers);
- }
-
- public void deleteServer(String appId) {
- List servers = getServers();
- ParseServerConfig toRemove = null;
-
- for (ParseServerConfig server : servers) {
- if (server.appId.equals(appId)) {
- toRemove = server;
- }
- }
-
- if (toRemove != null ) {
- servers.remove(toRemove);
- overrideServers(servers);
- }
- }
-
- public List getServers() {
- AsonArray servers = getServersAson();
- return servers.deserializeList(ParseServerConfig.class);
- }
-
- private AsonArray getServersAson() {
- SharedPreferences pref = context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);
- String input = pref.getString(PREF_SERVERS_KEY, "[]");
- return new AsonArray<>(input);
- }
-
- private void overrideServers(List servers) {
- AsonArray asonArray = new AsonArray<>();
- for (ParseServerConfig s : servers) {
- asonArray.add(s);
- }
-
- overrideServersAson(asonArray);
- }
-
- private void overrideServersAson(AsonArray servers) {
- SharedPreferences pref = context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = pref.edit();
- editor.putString(PREF_SERVERS_KEY, servers.toString());
- editor.commit();
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfigStorage.kt b/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfigStorage.kt
new file mode 100644
index 0000000..ddf7b95
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/ParseServerConfigStorage.kt
@@ -0,0 +1,62 @@
+package com.galtashma.parsedashboard
+
+import android.content.Context
+import com.afollestad.ason.AsonArray
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+private const val PREF_KEY = "parse_server_key"
+private const val PREF_SERVERS_KEY = "parse_server_config_key"
+
+class ParseServerConfigStorage(val context: Context) {
+ fun saveServer(config: ParseServerConfig) {
+ val servers = getServersAson()
+ servers.add(config)
+ overrideServersAson(servers)
+ }
+
+ fun deleteServer(appId: String) {
+ val servers = getServers()
+ var toRemove: ParseServerConfig? = null
+
+ servers.forEach {
+ if (it.appId == appId) {
+ toRemove = it
+ }
+ }
+
+ if (toRemove != null) {
+ servers.remove(toRemove)
+ overrideServers(servers)
+ }
+ }
+
+ fun getServers(): MutableList {
+ val servers = getServersAson()
+ return servers.deserializeList(ParseServerConfig::class.java)
+ }
+
+ private fun getServersAson(): AsonArray {
+ val pref = context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE)
+ val input = pref.getString(PREF_SERVERS_KEY, "[]")
+ return AsonArray(input)
+ }
+
+ private fun overrideServers(servers: List) {
+ val asonArray = AsonArray()
+ servers.forEach {
+ asonArray.add(it)
+ }
+
+ overrideServersAson(asonArray)
+ }
+
+ private fun overrideServersAson(servers: AsonArray) {
+ val pref = context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE)
+ val editor = pref.edit()
+ editor.putString(PREF_SERVERS_KEY, servers.toString())
+ editor.apply()
+ }
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/SortPreferenceStore.java b/app/src/main/java/com/galtashma/parsedashboard/SortPreferenceStore.java
deleted file mode 100644
index 74a9d9c..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/SortPreferenceStore.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.galtashma.parsedashboard;
-
-import com.appizona.yehiahd.fastsave.FastSave;
-
-public class SortPreferenceStore {
- private String prefId;
-
- public SortPreferenceStore(String prefId) {
- this.prefId = prefId;
- }
-
- public void update(String key, boolean asc) {
- FastSave.getInstance().saveObject(this.prefId, new SortPreferenceItem(key, asc));
- }
-
- public String getKey() {
- if (isEmpty()) {
- return "";
- }
- return getSavedItem().key;
- }
-
- public boolean isAsc() {
- if (isEmpty()) {
- return false;
- }
- return getSavedItem().asc;
- }
-
- public boolean isEmpty() {
- return !FastSave.getInstance().isKeyExists(this.prefId);
- }
-
- private SortPreferenceItem getSavedItem() {
- return FastSave.getInstance().getObject(this.prefId, SortPreferenceItem.class);
- }
-
- class SortPreferenceItem {
- private String key;
- private boolean asc;
-
- SortPreferenceItem(String key, boolean asc) {
- this.key = key;
- this.asc = asc;
- }
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/SortPreferenceStore.kt b/app/src/main/java/com/galtashma/parsedashboard/SortPreferenceStore.kt
new file mode 100644
index 0000000..9e9e47c
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/SortPreferenceStore.kt
@@ -0,0 +1,31 @@
+package com.galtashma.parsedashboard
+
+import com.appizona.yehiahd.fastsave.FastSave
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+class SortPreferenceStore(private val prefId: String) {
+ fun update(key: String, asc: Boolean) {
+ FastSave.getInstance().saveObject(prefId, SortPreferenceItem(key, asc))
+ }
+
+ fun getKey() = if (!isEmpty()) getSavedItem().key else ""
+
+ fun isAsc(): Boolean {
+ return if (isEmpty()) {
+ false
+ } else {
+ getSavedItem().asc
+ }
+ }
+
+ fun isEmpty() = !FastSave.getInstance().isKeyExists(this.prefId)
+
+ private fun getSavedItem(): SortPreferenceItem {
+ return FastSave.getInstance().getObject(this.prefId, SortPreferenceItem::class.java)
+ }
+
+ class SortPreferenceItem(val key: String, val asc: Boolean)
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseAppsAdapter.java b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseAppsAdapter.java
deleted file mode 100644
index e228352..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseAppsAdapter.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.galtashma.parsedashboard.adapters;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import androidx.annotation.NonNull;
-
-import com.galtashma.parsedashboard.ParseServerConfig;
-import com.galtashma.parsedashboard.R;
-import com.lucasurbas.listitemview.ListItemView;
-
-import java.util.List;
-
-/**
- * Created by gal on 3/16/18.
- */
-
-public class ParseAppsAdapter extends ArrayAdapter {
-
- public interface ParseAppAdapterListener{
- void onClickOpen(ParseServerConfig config);
- void onClickEdit(ParseServerConfig config);
- void onClickDelete(ParseServerConfig config);
- }
-
- private ParseAppAdapterListener listener;
-
- public ParseAppsAdapter(@NonNull Context context, @NonNull List objects) {
- super(context, R.layout.list_item_card, objects);
- }
-
- @NonNull
- public View getView(int position, View convertView, @NonNull ViewGroup parent) {
- final ParseServerConfig server = getItem(position);
-
- if(convertView == null) {
- convertView = LayoutInflater.from(this.getContext()).inflate(R.layout.list_item_card, parent, false);
- }
-
- ListItemView item = convertView.findViewById(R.id.parse_server_list_item);
- item.setTitle(server.appName);
- item.setSubtitle(server.serverUrl+"\n"+server.appId);
-
- item.setOnMenuItemClickListener(clickedItem -> {
- if (clickedItem.getItemId() == R.id.action_edit) {
- notifyEdit(server);
- } else if (clickedItem.getItemId() == R.id.action_remove) {
- notifyDelete(server);
- }
- });
- item.setOnClickListener(view -> notifyClick(server));
-
- return convertView;
- }
-
- private void notifyClick(ParseServerConfig config){
- if (listener!=null){
- listener.onClickOpen(config);
- }
- }
-
- private void notifyEdit(ParseServerConfig config){
- if (listener != null){
- listener.onClickEdit(config);
- }
- }
-
- private void notifyDelete(ParseServerConfig config){
- if (listener != null){
- this.listener.onClickDelete(config);
- }
- }
-
- public void setListener(ParseAppAdapterListener listener) {
- this.listener = listener;
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseAppsAdapter.kt b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseAppsAdapter.kt
new file mode 100644
index 0000000..9636730
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseAppsAdapter.kt
@@ -0,0 +1,76 @@
+package com.galtashma.parsedashboard.adapters
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import androidx.annotation.NonNull
+import com.galtashma.parsedashboard.ParseServerConfig
+import com.galtashma.parsedashboard.R
+import com.lucasurbas.listitemview.ListItemView
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+class ParseAppsAdapter(
+ @NonNull context: Context,
+ @NonNull objects: List
+) : ArrayAdapter(context, R.layout.list_item_card, objects) {
+
+ interface ParseAppAdapterListener {
+ fun onClickOpen(config: ParseServerConfig)
+ fun onClickEdit(config: ParseServerConfig)
+ fun onClickDelete(config: ParseServerConfig)
+ }
+
+ private lateinit var listener: ParseAppAdapterListener
+
+ override fun getView(
+ position: Int,
+ convertView: View?,
+ parent: ViewGroup
+ ): View {
+ val server = getItem(position)
+
+ var finalView = convertView
+ if (convertView == null) {
+ finalView = LayoutInflater.from(context)
+ .inflate(R.layout.list_item_card, parent, false)
+ }
+
+ val item = finalView?.findViewById(R.id.parse_server_list_item)
+ item?.title = server?.appName
+ item?.subtitle = "${server?.serverUrl}\n${server?.appId}"
+
+ if (server != null) {
+ item?.setOnMenuItemClickListener { clickedItem ->
+ if (clickedItem.itemId == R.id.action_edit) {
+ notifyEdit(server)
+ } else if (clickedItem.itemId == R.id.action_remove) {
+ notifyDelete(server)
+ }
+ }
+ item?.setOnClickListener { notifyClick(server) }
+ }
+
+ return finalView!!
+ }
+
+ private fun notifyClick(config: ParseServerConfig) {
+ listener.onClickOpen(config)
+ }
+
+ private fun notifyEdit(config: ParseServerConfig) {
+ listener.onClickEdit(config)
+ }
+
+ private fun notifyDelete(config: ParseServerConfig) {
+ listener.onClickDelete(config)
+ }
+
+ fun setListener(listener: ParseAppAdapterListener) {
+ this.listener = listener
+ }
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseClassesAdapter.java b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseClassesAdapter.java
deleted file mode 100644
index 4f10040..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseClassesAdapter.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.galtashma.parsedashboard.adapters;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import androidx.annotation.NonNull;
-
-import com.galtashma.parsedashboard.R;
-import com.lucasurbas.listitemview.ListItemView;
-import com.parse.ParseSchema;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-
-public class ParseClassesAdapter extends ArrayAdapter {
-
- public interface OnClickListener {
- void onSchemaClicked(ParseSchema schema);
- }
-
- private OnClickListener listener;
-
- public ParseClassesAdapter(@NonNull Context context) {
- super(context, R.layout.list_item);
- }
-
- public ParseClassesAdapter(@NonNull Context context, @NonNull List objects) {
- super(context, R.layout.list_item, objects);
- }
-
- @NonNull
- public View getView(int position, View convertView, @NonNull ViewGroup parent) {
- final ParseSchema schema = getItem(position);
- if (convertView == null) {
- convertView = LayoutInflater.from(this.getContext()).inflate(R.layout.list_item, parent, false);
- }
-
- ListItemView item = (ListItemView) convertView;
-
- item.setTitle(schema.getName());
- item.setSubtitle(getItemCountString(schema) + getSchemaString(schema));
-
- item.setOnClickListener(view -> {
- if (listener != null){
- listener.onSchemaClicked(schema);
- }
- });
-
- return convertView;
- }
-
- private String getItemCountString(ParseSchema schema) {
- int itemCount = schema.getCountIfFetched();
- if (itemCount != -1) {
- return "("+itemCount+")\t";
- }
-
- schema.setOnCountListener((count, exception) -> notifyDataSetChanged());
-
- return "";
- }
-
- private String getSchemaString(ParseSchema schema){
- List list = new ArrayList<>(schema.getFields().keySet());
- Collections.sort(list);
- return list.toString().replaceAll("\\[|\\]","").replaceAll(","," ");
- }
-
- public void setListener(OnClickListener listener) {
- this.listener = listener;
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseClassesAdapter.kt b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseClassesAdapter.kt
new file mode 100644
index 0000000..cb5f22c
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseClassesAdapter.kt
@@ -0,0 +1,73 @@
+package com.galtashma.parsedashboard.adapters
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import androidx.annotation.NonNull
+import com.galtashma.parsedashboard.R
+import com.lucasurbas.listitemview.ListItemView
+import com.parse.ParseSchema
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+class ParseClassesAdapter(
+ @NonNull context: Context
+) : ArrayAdapter(context, R.layout.list_item) {
+
+ interface OnClickListener {
+ fun onSchemaCLicked(schema: ParseSchema)
+ }
+
+ private lateinit var localListener: OnClickListener
+
+ override fun getView(
+ position: Int,
+ convertView: View?,
+ parent: ViewGroup
+ ): View {
+ var finalView = convertView
+ val schema = getItem(position)
+ if (convertView == null) {
+ finalView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false)
+ }
+
+ val item = finalView as ListItemView
+
+ item.title = schema?.name
+ if (schema != null) {
+ item.subtitle = getItemCountString(schema) + getSchemaString(schema)
+ }
+
+ item.setOnClickListener {
+ if (schema != null) {
+ localListener.onSchemaCLicked(schema)
+ }
+ }
+
+ return finalView
+ }
+
+ private fun getItemCountString(schema: ParseSchema): String {
+ val itemCount = schema.countIfFetched
+ if (itemCount != -1) {
+ return "($itemCount)\t"
+ }
+
+ schema.setOnCountListener { _, _ -> notifyDataSetChanged() }
+
+ return ""
+ }
+
+ private fun getSchemaString(schema: ParseSchema): String {
+ val list = schema.fields.keys.toList().sorted()
+ return list.toString().replace("\\[|\\]", "").replace(",", " ")
+ }
+
+ fun setListener(listener: OnClickListener) {
+ this.localListener = listener
+ }
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectFieldsAdapter.java b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectFieldsAdapter.java
deleted file mode 100644
index 2d7693d..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectFieldsAdapter.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.galtashma.parsedashboard.adapters;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import androidx.annotation.NonNull;
-
-import com.galtashma.parsedashboard.ParseField;
-import com.galtashma.parsedashboard.R;
-import com.lucasurbas.listitemview.ListItemView;
-
-import java.util.List;
-
-/**
- * Created by gal on 3/16/18.
- */
-
-public class ParseObjectFieldsAdapter extends ArrayAdapter {
-
- private View.OnLongClickListener longClickListener = null;
-
- public ParseObjectFieldsAdapter(@NonNull Context context, @NonNull List objects) {
- super(context, R.layout.list_item, objects);
- }
-
- @NonNull
- public View getView(int position, View convertView, @NonNull ViewGroup parent) {
- ParseField details = getItem(position);
- if (convertView == null) {
- convertView = LayoutInflater.from(this.getContext()).inflate(R.layout.list_item, parent, false);
- }
-
- ListItemView view = (ListItemView) convertView;
-
- if (details == null) {
- return convertView;
- }
-
- if (details.value == null || details.value.isEmpty()) {
- view.setTitle("");
- } else {
- view.setTitle(details.value);
- }
-
- view.setSubtitle(details.key);
- view.setOnLongClickListener(longClickListener);
-
- return convertView;
- }
-
- public void setLongClickListener(View.OnLongClickListener longClickListener) {
- this.longClickListener = longClickListener;
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectFieldsAdapter.kt b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectFieldsAdapter.kt
new file mode 100644
index 0000000..361418a
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectFieldsAdapter.kt
@@ -0,0 +1,53 @@
+package com.galtashma.parsedashboard.adapters
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import androidx.annotation.NonNull
+import com.galtashma.parsedashboard.ParseField
+import com.galtashma.parsedashboard.R
+import com.lucasurbas.listitemview.ListItemView
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+class ParseObjectFieldsAdapter(
+ @NonNull context: Context,
+ @NonNull objects: List
+) : ArrayAdapter(context, R.layout.list_item, objects) {
+
+ private var longClickListener: View.OnLongClickListener? = null
+
+ override fun getView(
+ position: Int,
+ convertView: View?,
+ parent: ViewGroup
+ ): View {
+ val details = getItem(position)
+
+ var finalView = convertView
+ if (convertView == null) {
+ finalView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false)
+ }
+
+ val view = finalView as ListItemView
+
+ if (details == null) {
+ return finalView
+ }
+
+ view.title = details.value.ifBlank { "" }
+
+ view.subtitle = details.key
+ view.setOnLongClickListener(longClickListener)
+
+ return finalView
+ }
+
+ fun setLongClickListener(longClickListener: View.OnLongClickListener) {
+ this.longClickListener = longClickListener
+ }
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectsAdapter.java b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectsAdapter.java
deleted file mode 100644
index 613c4b4..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectsAdapter.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package com.galtashma.parsedashboard.adapters;
-
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import androidx.annotation.NonNull;
-
-import com.galtashma.lazyparse.LazyList;
-import com.galtashma.lazyparse.LazyParseObjectHolder;
-import com.galtashma.lazyparse.ScrollInfiniteAdapter;
-import com.galtashma.parsedashboard.R;
-import com.lucasurbas.listitemview.ListItemView;
-import com.parse.ParseObject;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Created by gal on 3/14/18.
- */
-
-public class ParseObjectsAdapter extends ScrollInfiniteAdapter {
-
- private List previewFieldNames;
-
- public ParseObjectsAdapter(Context context, LazyList lazyValues) {
- super(context, lazyValues, R.layout.list_item, 15);
- previewFieldNames = Arrays.asList("createdAt", "updatedAt");
- }
-
- public ParseObjectsAdapter(Context context, LazyList lazyValues, List previewFields) {
- super(context, lazyValues, R.layout.list_item, 15);
- this.previewFieldNames = previewFields;
- }
-
- public void updatePreviewFields(List previewFields){
- this.previewFieldNames = previewFields;
- this.notifyDataSetChanged();
- }
-
- @Override
- public View renderReadyLazyObject(ParseObject t, View view, @NonNull ViewGroup viewGroup) {
- ListItemView item = (ListItemView) view;
- item.setTitle(t.getObjectId());
- item.setMultiline(true);
-
- Map fields = new HashMap<>();
- for (String fieldName : previewFieldNames) {
- String value = formatParseField(t, fieldName);
- if (value != null) {
- fields.put(fieldName, formatParseField(t, fieldName));
- }
- }
- item.setSubtitle(mapToString(fields));
- return view;
- }
-
- private String formatParseField(ParseObject t, String key) {
- if (key.equals("createdAt")) {
- return t.getCreatedAt().toString();
- }
- if (key.equals("updatedAt")) {
- return t.getCreatedAt().toString();
- }
-
- if (t.has(key)) {
- return t.get(key).toString();
- }
-
- return null;
- }
-
- @Override
- public View renderLoadingLazyObject(LazyParseObjectHolder lazyParseObjectHolder, View view, @NonNull ViewGroup viewGroup) {
- ListItemView item = (ListItemView) view;
- item.setTitle("Loading...");
- return view;
- }
-
- private String mapToString(Map map) {
- if (map.size() <= 0) {
- return "";
- }
-
- StringBuilder sb = new StringBuilder();
- for (String k : map.keySet()) {
- sb.append(k);
- sb.append(": ");
- sb.append(map.get(k));
- sb.append("\n");
- }
-
- sb.delete(sb.length()-1, sb.length()); // remove last \n
-
- return sb.toString();
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectsAdapter.kt b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectsAdapter.kt
new file mode 100644
index 0000000..360f34b
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/adapters/ParseObjectsAdapter.kt
@@ -0,0 +1,86 @@
+package com.galtashma.parsedashboard.adapters
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.NonNull
+import com.galtashma.lazyparse.LazyList
+import com.galtashma.lazyparse.LazyParseObjectHolder
+import com.galtashma.lazyparse.ScrollInfiniteAdapter
+import com.galtashma.parsedashboard.R
+import com.lucasurbas.listitemview.ListItemView
+import com.parse.ParseObject
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+class ParseObjectsAdapter(
+ context: Context,
+ lazyValues: LazyList,
+ private var previewFieldNames: List
+) : ScrollInfiniteAdapter(context, lazyValues, R.layout.list_item, 15) {
+
+ fun updatePreviewFields(previewFields: List){
+ previewFieldNames = previewFields
+ this.notifyDataSetChanged()
+ }
+
+ override fun renderReadyLazyObject(
+ parseObject: ParseObject,
+ view: View?,
+ @NonNull viewGroup: ViewGroup
+ ): View {
+ val item = view as ListItemView
+ item.title = parseObject.objectId
+ item.setMultiline(true)
+
+ val fields = HashMap()
+ for (fieldName in previewFieldNames) {
+ val value = formatParseField(parseObject, fieldName)
+ if (value != null) {
+ fields[fieldName] = formatParseField(parseObject, fieldName)
+ }
+ }
+ item.subtitle = mapToString(fields)
+ return view
+ }
+
+ private fun formatParseField(parseObject: ParseObject, key: String): String? {
+ if (key == "createdAt") {
+ return parseObject.createdAt.toString()
+ }
+ if (key == "updatedAt") {
+ return parseObject.createdAt.toString()
+ }
+
+ if (parseObject.has(key)) {
+ return parseObject.get(key).toString()
+ }
+
+ return null
+ }
+
+ override fun renderLoadingLazyObject(
+ lazyParseObjectHolder: LazyParseObjectHolder?,
+ view: View?,
+ viewGroup: ViewGroup
+ ): View {
+ val item = view as ListItemView
+ item.title = "Loading..."
+ return view
+ }
+
+ private fun mapToString(map: Map): String {
+ if (map.isEmpty()) return ""
+
+ val sb = StringBuilder()
+ for (k in map.keys) {
+ sb.append("$k: ${map[k]}\n")
+ }
+
+ sb.dropLast(1) // remove last \n
+
+ return sb.toString()
+ }
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/screens/AppsMenuParseActivity.java b/app/src/main/java/com/galtashma/parsedashboard/screens/AppsMenuParseActivity.java
deleted file mode 100644
index 5d08bfa..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/screens/AppsMenuParseActivity.java
+++ /dev/null
@@ -1,193 +0,0 @@
-package com.galtashma.parsedashboard.screens;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.ListView;
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
-
-import com.afollestad.materialdialogs.DialogAction;
-import com.afollestad.materialdialogs.MaterialDialog;
-import com.galtashma.parsedashboard.ParseServerConfig;
-import com.galtashma.parsedashboard.ParseServerConfigStorage;
-import com.galtashma.parsedashboard.R;
-import com.galtashma.parsedashboard.adapters.ParseAppsAdapter;
-import com.galtashma.parsedashboard.Const;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import com.google.android.material.snackbar.Snackbar;
-import com.parse.Parse;
-import com.vlonjatg.progressactivity.ProgressRelativeLayout;
-import com.vorlonsoft.android.rate.AppRate;
-
-import java.util.List;
-
-import okhttp3.OkHttpClient;
-import okhttp3.logging.HttpLoggingInterceptor;
-
-
-public class AppsMenuParseActivity extends AppCompatActivity implements MaterialDialog.SingleButtonCallback, ParseAppsAdapter.ParseAppAdapterListener {
-
- private ParseServerConfigStorage storage;
-
- private ParseAppsAdapter adapter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_apps_menu);
- Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- FloatingActionButton fab = findViewById(R.id.fab);
- fab.setOnClickListener(view -> showDialog());
-
- storage = new ParseServerConfigStorage(getApplicationContext());
- toggleMainScreen(isMainScreenEmpty());
-
- List list = storage.getServers();
- adapter = new ParseAppsAdapter(this, list);
- ListView listView = findViewById(R.id.list_view);
- listView.setAdapter(adapter);
- adapter.setListener(this);
-
- AppRate.with(this)
- .setInstallDays((byte) 2)
- .setLaunchTimes((byte) 4)
- .setShowLaterButton(true)
- .setShowNeverButton(true)
- .monitor();
-
- // Show dialog after 40 seconds
- final Handler handler = new Handler();
- handler.postDelayed(() -> AppRate.showRateDialogIfMeetsConditions(AppsMenuParseActivity.this), 1000*40);
- }
-
- private boolean isMainScreenEmpty() {
- return storage.getServers().isEmpty();
- }
-
- private void toggleMainScreen(boolean isEmpty) {
- ProgressRelativeLayout layout = findViewById(R.id.stateful_layout);
- if (isEmpty) {
- layout.showEmpty(R.drawable.ic_parse_24dp, getString(R.string.empty_state_apps_screen_short), getString(R.string.empty_state_apps_screen_long));
- } else {
- layout.showContent();
- }
- }
-
- private void showDialog() {
- new MaterialDialog.Builder(this)
- .title("Add Parse Server")
- .customView(R.layout.dialog_add_app, true)
- .positiveText("OK")
- .onPositive(this)
- .show();
- }
-
- @Override
- public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
- ParseServerConfig serverConfig = getConfigFromDialog(dialog);
- storage.saveServer(serverConfig);
- adapter.add(serverConfig);
- adapter.notifyDataSetChanged();
- toggleMainScreen(isMainScreenEmpty());
- }
-
- private ParseServerConfig getConfigFromDialog(MaterialDialog dialog) {
- View v = dialog.getCustomView();
- EditText appName = v.findViewById(R.id.inputAppName);
- EditText appId = v.findViewById(R.id.inputAppId);
- EditText masterKey = v.findViewById(R.id.inputAppMasterKey);
- EditText serverUrl = v.findViewById(R.id.inputServerUrl);
- return new ParseServerConfig(
- appName.getText().toString(),
- appId.getText().toString(),
- masterKey.getText().toString(),
- serverUrl.getText().toString());
- }
-
- @Override
- public void onClickOpen(ParseServerConfig config) {
- String error = checkForParseConfigError(config);
- if (error != null) {
- Snackbar.make(findViewById(R.id.stateful_layout), error, Snackbar.LENGTH_LONG).show();
- return;
- }
-
- // Re init parse sdk so we can open a new parse app
- Parse.destroy();
- initParse(config.appId, config.serverUrl, config.masterKey);
-
- Intent i = new Intent(this, SingleAppParseActivity.class);
- i.putExtra(Const.BUNDLE_KEY_PARSE_APP_NAME, config.appName);
- this.startActivityForResult(i, 1);
- }
-
- // Validate parse server config. If No error returns null, otherwise returns error message.
- private String checkForParseConfigError(ParseServerConfig config) {
- if (config.appId.equals("")) {
- return getString(R.string.error_app_id_missing);
- }
- if (config.serverUrl.equals("")) {
- return getString(R.string.error_server_url_missing);
- }
- if (!config.serverUrl.startsWith("http://") && !config.serverUrl.startsWith("https://")){
- return getString(R.string.error_server_url_malformed);
- }
- if (config.masterKey.equals("")) {
- return getString(R.string.error_master_key_missing);
- }
- return null;
- }
-
- @Override
- public void onClickEdit(final ParseServerConfig config) {
- MaterialDialog dialog = new MaterialDialog.Builder(this)
- .title("Edit Parse Server")
- .customView(R.layout.dialog_add_app, true)
- .positiveText("OK")
- .onPositive((thisDialog, which) -> {
- adapter.remove(config);
- storage.deleteServer(config.appId);
- ParseServerConfig newConfig = getConfigFromDialog(thisDialog);
- adapter.add(newConfig);
- storage.saveServer(newConfig);
- adapter.notifyDataSetChanged();
- })
- .show();
-
- View v = dialog.getCustomView();
- ((EditText)v.findViewById(R.id.inputAppName)).setText(config.appName);
- ((EditText)v.findViewById(R.id.inputAppId)).setText(config.appId);
- ((EditText)v.findViewById(R.id.inputAppMasterKey)).setText(config.masterKey);
- ((EditText)v.findViewById(R.id.inputServerUrl)).setText(config.serverUrl);
- }
-
- @Override
- public void onClickDelete(ParseServerConfig config) {
- storage.deleteServer(config.appId);
- adapter.remove(config);
- adapter.notifyDataSetChanged();
- toggleMainScreen(isMainScreenEmpty());
- }
-
- private void initParse(String appId, String serverUrl, String masterKey) {
- Log.i("ParseDashboard", "Starting client for " + serverUrl + " appId: " + appId);
- OkHttpClient.Builder builder = new OkHttpClient.Builder();
- HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
- httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
- builder.networkInterceptors().add(httpLoggingInterceptor);
-
- Parse.initialize(new Parse.Configuration.Builder(this)
- .applicationId(appId)
- .server(serverUrl)
- .masterKey(masterKey)
- .clientBuilder(builder)
- .build());
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/screens/AppsMenuParseActivity.kt b/app/src/main/java/com/galtashma/parsedashboard/screens/AppsMenuParseActivity.kt
new file mode 100644
index 0000000..7d3ac47
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/screens/AppsMenuParseActivity.kt
@@ -0,0 +1,210 @@
+package com.galtashma.parsedashboard.screens
+
+import android.content.Intent
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.os.PersistableBundle
+import android.util.Log
+import android.widget.EditText
+import android.widget.ListView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.widget.Toolbar
+import com.afollestad.materialdialogs.DialogAction
+import com.afollestad.materialdialogs.MaterialDialog
+import com.galtashma.parsedashboard.Const
+import com.galtashma.parsedashboard.ParseServerConfig
+import com.galtashma.parsedashboard.ParseServerConfigStorage
+import com.galtashma.parsedashboard.R
+import com.galtashma.parsedashboard.adapters.ParseAppsAdapter
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+import com.google.android.material.snackbar.Snackbar
+import com.parse.Parse
+import com.vlonjatg.progressactivity.ProgressRelativeLayout
+import com.vorlonsoft.android.rate.AppRate
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+class AppsMenuParseActivity :
+ AppCompatActivity(),
+ MaterialDialog.SingleButtonCallback,
+ ParseAppsAdapter.ParseAppAdapterListener {
+
+ private lateinit var storage: ParseServerConfigStorage
+ private lateinit var adapter: ParseAppsAdapter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_apps_menu)
+ val toolbar = findViewById(R.id.toolbar)
+ setSupportActionBar(toolbar)
+
+ val fab = findViewById(R.id.fab)
+ fab.setOnClickListener { showDialog() }
+
+ storage = ParseServerConfigStorage(applicationContext)
+ toggleMainScreen(isMainScreenEmpty())
+
+ val list = storage.getServers()
+ adapter = ParseAppsAdapter(this, list)
+ val listView = findViewById(R.id.list_view)
+ listView.adapter = adapter
+ adapter.setListener(this)
+
+ AppRate.with(this)
+ .setInstallDays(2)
+ .setLaunchTimes(4)
+ .setShowLaterButton(true)
+ .setShowNeverButton(true)
+ .monitor()
+
+ // Show dialog after 40 seconds
+ Handler(Looper.getMainLooper()).postDelayed({
+ AppRate.showRateDialogIfMeetsConditions(this)
+ }, 1000L * 40)
+ }
+
+ private fun isMainScreenEmpty() = storage.getServers().isEmpty()
+
+ private fun toggleMainScreen(isEmpty: Boolean) {
+ val layout = findViewById(R.id.stateful_layout)
+ if (isEmpty) {
+ layout.showEmpty(
+ R.drawable.ic_parse_24dp,
+ getString(R.string.empty_state_apps_screen_short),
+ getString(R.string.empty_state_apps_screen_long)
+ )
+ } else {
+ layout.showContent()
+ }
+ }
+
+ private fun showDialog() {
+ MaterialDialog.Builder(this)
+ .title("Add Parse Server")
+ .customView(R.layout.dialog_add_app, true)
+ .positiveText("OK")
+ .onPositive(this)
+ .show()
+ }
+
+ override fun onClick(dialog: MaterialDialog, which: DialogAction) {
+ val serverConfig = getConfigFromDialog(dialog)
+ storage.saveServer(serverConfig)
+ adapter.add(serverConfig)
+ adapter.notifyDataSetChanged()
+ toggleMainScreen(isMainScreenEmpty())
+ }
+
+ private fun getConfigFromDialog(dialog: MaterialDialog): ParseServerConfig {
+ val view = dialog.customView
+ view?.apply {
+ val appName = findViewById(R.id.inputAppName)
+ val appId = findViewById(R.id.inputAppId)
+ val masterKey = findViewById(R.id.inputAppMasterKey)
+ val serverUrl = findViewById(R.id.inputServerUrl)
+
+ return ParseServerConfig(
+ appName?.text.toString(),
+ appId?.text.toString(),
+ masterKey?.text.toString(),
+ serverUrl?.text.toString()
+ )
+ }
+
+ // If view is somehow null
+ return ParseServerConfig(
+ "",
+ "",
+ "",
+ ""
+ )
+ }
+
+ override fun onClickOpen(config: ParseServerConfig) {
+ val error = checkForParseConfigError(config)
+ if (error != null) {
+ Snackbar.make(findViewById(R.id.stateful_layout), error, Snackbar.LENGTH_LONG).show()
+ return
+ }
+
+ // Re init parse sdk so we can open a new parse app
+ Parse.destroy()
+ initParse(config.appId, config.serverUrl, config.masterKey)
+
+ val i = Intent(this, SingleAppParseActivity::class.java)
+ i.putExtra(Const.BUNDLE_KEY_PARSE_APP_NAME, config.appName)
+ startActivityForResult(i, 1)
+ }
+
+ // Validate parse server config. If no error returns null, otherwise returns error message.
+ private fun checkForParseConfigError(config: ParseServerConfig): String? {
+ if (config.appId == "") {
+ return getString(R.string.error_app_id_missing)
+ }
+ if (config.serverUrl == "") {
+ return getString(R.string.error_server_url_missing)
+ }
+ if (!config.serverUrl.startsWith("http://") && !config.serverUrl.startsWith("https://")) {
+ return getString(R.string.error_server_url_malformed)
+ }
+ if (config.masterKey == "") {
+ return getString(R.string.error_master_key_missing)
+ }
+ return null
+ }
+
+ override fun onClickEdit(config: ParseServerConfig) {
+ val dialog = MaterialDialog.Builder(this)
+ .title("Edit Parse Server")
+ .customView(R.layout.dialog_add_app, true)
+ .positiveText("OK")
+ .onPositive { thisDialog, _ ->
+ adapter.remove(config)
+ storage.deleteServer(config.appId)
+ val newConfig = getConfigFromDialog(thisDialog)
+ adapter.add(newConfig)
+ storage.saveServer(newConfig)
+ adapter.notifyDataSetChanged()
+ }
+ .show()
+
+ val view = dialog.customView
+ view?.apply {
+ findViewById(R.id.inputAppName).setText(config.appName)
+ findViewById(R.id.inputAppId).setText(config.appId)
+ findViewById(R.id.inputAppMasterKey).setText(config.masterKey)
+ findViewById(R.id.inputServerUrl).setText(config.serverUrl)
+ }
+ }
+
+ override fun onClickDelete(config: ParseServerConfig) {
+ storage.deleteServer(config.appId)
+ adapter.remove(config)
+ adapter.notifyDataSetChanged()
+ toggleMainScreen(isMainScreenEmpty())
+ }
+
+ private fun initParse(
+ appId: String,
+ serverUrl: String,
+ clientKey: String
+ ) {
+ Log.i("ParseDashboard", "Starting client for $serverUrl appId: $appId")
+ val builder = OkHttpClient.Builder()
+ val httpLoggingInterceptor = HttpLoggingInterceptor()
+ httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
+ builder.networkInterceptors().add(httpLoggingInterceptor)
+
+ Parse.initialize(Parse.Configuration.Builder(this)
+ .applicationId(appId)
+ .server(serverUrl)
+ .masterKey(clientKey)
+ .clientBuilder(builder)
+ .build())
+ }
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/screens/SingleAppParseActivity.java b/app/src/main/java/com/galtashma/parsedashboard/screens/SingleAppParseActivity.java
deleted file mode 100644
index 8102ddf..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/screens/SingleAppParseActivity.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.galtashma.parsedashboard.screens;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.ListView;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
-
-import com.galtashma.parsedashboard.Const;
-import com.galtashma.parsedashboard.R;
-import com.galtashma.parsedashboard.adapters.ParseClassesAdapter;
-import com.parse.ParseSchema;
-import com.vlonjatg.progressactivity.ProgressRelativeLayout;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import bolts.Continuation;
-
-
-public class SingleAppParseActivity extends AppCompatActivity {
-
- private ParseClassesAdapter adapter;
- private ProgressRelativeLayout statefulLayout;
-
- private Map schemas = new HashMap<>();
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_single_app);
- Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- String appName = "";
-
- Bundle extra = getIntent().getExtras();
- if (extra == null) {
- extra = savedInstanceState;
- }
-
- if (extra != null && extra.containsKey(Const.BUNDLE_KEY_PARSE_APP_NAME)) {
- appName = extra.getString(Const.BUNDLE_KEY_PARSE_APP_NAME);
- }
-
- setTitle(appName);
-
- statefulLayout = findViewById(R.id.stateful_layout);
- adapter = new ParseClassesAdapter(this);
- adapter.setListener(schema -> showTable(schema.getName()));
- ListView listView = findViewById(R.id.list_view);
- listView.setAdapter(adapter);
- fetchSchemasAsync();
- }
-
- private void fetchSchemasAsync() {
- statefulLayout.showLoading();
- ParseSchema.getParseSchemasAsync().continueWith((Continuation, Void>) task -> {
- if (task.isFaulted() || task.isCancelled()) {
- showErrorOnUIThread(getString(R.string.schemas_screen_error_title), task.getError());
- Log.e("ParseDashboard","Error fetching from " + " parse server.", task.getError());
- return null;
- }
-
- Log.i(Const.TAG, "found schemas " + task.getResult());
- List s = task.getResult();
- updateListOnUIThread(s);
- for (ParseSchema ps : s) {
- schemas.put(ps.getName(), ps);
- }
-
- return null;
- });
- }
-
- private void updateListOnUIThread(final List schemasList) {
- runOnUiThread(() -> {
- if (schemasList.size() == 0) {
- showEmptyState();
- return;
- }
- statefulLayout.showContent();
- adapter.clear();
- adapter.addAll(schemasList);
- adapter.notifyDataSetChanged();
- });
- }
-
- private void showErrorOnUIThread(final String title, final Exception e) {
- runOnUiThread(() -> statefulLayout.showError(R.drawable.ic_parse_24dp, title, e.getLocalizedMessage(), "Retry", view -> fetchSchemasAsync()));
- }
-
- private void showEmptyState() {
- statefulLayout.showEmpty(R.drawable.ic_parse_24dp, getString(R.string.empty_state_schemas_screen_short), getString(R.string.empty_state_schemas_screen_long));
- }
-
- private void showTable(String tableName) {
- Intent intent = new Intent(this, SingleClassParseActivity.class);
- intent.putExtra(Const.BUNDLE_KEY_CLASS_NAME, tableName);
- if (schemas.containsKey(tableName)) {
- int size = schemas.get(tableName).getFields().size();
- String[] fieldsArr = new String[size];
-
- Iterator it = schemas.get(tableName).getFields().keySet().iterator();
- for (int i=0; i()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_single_app)
+ val toolbar = findViewById(R.id.toolbar)
+ setSupportActionBar(toolbar)
+
+ var extra = intent.extras
+ if (extra == null) {
+ extra = savedInstanceState
+ }
+
+ val appName = if (extra != null && extra.containsKey(Const.BUNDLE_KEY_PARSE_APP_NAME)) {
+ extra.getString(Const.BUNDLE_KEY_PARSE_APP_NAME)
+ } else ""
+
+ title = appName
+
+ statefulLayout = findViewById(R.id.stateful_layout)
+ adapter = ParseClassesAdapter(this)
+ adapter.setListener(object: ParseClassesAdapter.OnClickListener {
+ override fun onSchemaCLicked(schema: ParseSchema) {
+ showTable(schema.name)
+ }
+ })
+ val listView = findViewById(R.id.list_view)
+ listView.adapter = adapter
+ fetchSchemasAsync()
+ }
+
+ private fun fetchSchemasAsync() {
+ statefulLayout.showLoading()
+ ParseSchema.getParseSchemasAsync().continueWith { task ->
+ if (task.isFaulted || task.isCancelled) {
+ showErrorOnUIThread(getString(R.string.schemas_screen_error_title), task.error)
+ Log.e("ParseDashboard","Error fetching from parse server.", task.error)
+ return@continueWith null
+ }
+
+ Log.i(Const.TAG, "Found schemas: ${task.result}")
+ val s = task.result
+ updateListOnUIThread(s)
+ s.forEach { ps ->
+ schemas[ps.name] = ps
+ }
+
+ return@continueWith null
+ }
+ }
+
+ private fun updateListOnUIThread(schemasList: List) {
+ runOnUiThread {
+ if (schemasList.isEmpty()) {
+ showEmptyState()
+ return@runOnUiThread
+ }
+ statefulLayout.showContent()
+ adapter.clear()
+ adapter.addAll(schemasList)
+ adapter.notifyDataSetChanged()
+ }
+ }
+
+ private fun showErrorOnUIThread(title: String, e: Exception) {
+ runOnUiThread {
+ statefulLayout.showError(
+ R.drawable.ic_parse_24dp,
+ title,
+ e.localizedMessage,
+ "Retry"
+ ) {
+ fetchSchemasAsync()
+ }
+ }
+ }
+
+ private fun showEmptyState() {
+ statefulLayout.showEmpty(
+ R.drawable.ic_parse_24dp,
+ getString(R.string.empty_state_schemas_screen_short),
+ getString(R.string.empty_state_schemas_screen_long)
+ )
+ }
+
+ private fun showTable(tableName: String) {
+ val intent = Intent(this, SingleClassParseActivity::class.java)
+ intent.putExtra(Const.BUNDLE_KEY_CLASS_NAME, tableName)
+ if (schemas.containsKey(tableName)) {
+ val fields = schemas[tableName]?.fields?.keys?.toTypedArray()
+ if (fields != null) {
+ intent.putExtra(Const.BUNDLE_KEY_CLASS_FIELDS_NAME, fields)
+ this.startActivityForResult(intent, 1)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/screens/SingleClassParseActivity.java b/app/src/main/java/com/galtashma/parsedashboard/screens/SingleClassParseActivity.java
deleted file mode 100644
index f505533..0000000
--- a/app/src/main/java/com/galtashma/parsedashboard/screens/SingleClassParseActivity.java
+++ /dev/null
@@ -1,210 +0,0 @@
-package com.galtashma.parsedashboard.screens;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ListView;
-import android.widget.RadioButton;
-import android.widget.Spinner;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
-
-import com.afollestad.materialdialogs.MaterialDialog;
-import com.galtashma.lazyparse.LazyList;
-import com.galtashma.lazyparse.ScrollInfiniteAdapter;
-import com.galtashma.lazyparse.ScrollInfiniteListener;
-import com.galtashma.parsedashboard.Const;
-import com.galtashma.parsedashboard.ListPreferenceStore;
-import com.galtashma.parsedashboard.SortPreferenceStore;
-import com.galtashma.parsedashboard.adapters.ParseObjectsAdapter;
-import com.galtashma.parsedashboard.R;
-import com.parse.ParseObject;
-import com.parse.ParseQuery;
-import com.vlonjatg.progressactivity.ProgressRelativeLayout;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class SingleClassParseActivity extends AppCompatActivity implements ScrollInfiniteAdapter.OnClickListener {
-
- private String className;
- ProgressRelativeLayout statefulLayout;
- private String[] fieldNames;
- private ListPreferenceStore visibleFieldsStore;
- private SortPreferenceStore sortPreferenceStore;
-
- private ParseObjectsAdapter adapter;
-
- private static final String PREF_KEY = "KEY_SingleClassParseActivity_";
- private static final String PREF_SORT = "SORT_SingleClassParseActivity";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_single_class);
- Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- Bundle extra = getIntent().getExtras();
- if (extra == null) {
- extra = savedInstanceState;
- }
-
- if (extra == null || !extra.containsKey(Const.BUNDLE_KEY_CLASS_NAME)) {
- finish();
- return;
- }
-
- className = extra.getString(Const.BUNDLE_KEY_CLASS_NAME);
- setTitle(className);
-
- if (extra.containsKey(Const.BUNDLE_KEY_CLASS_FIELDS_NAME)) {
- fieldNames = extra.getStringArray(Const.BUNDLE_KEY_CLASS_FIELDS_NAME);
-
- // Remove objectId field as it is special and is displayed anyway
- List l = new ArrayList<>(Arrays.asList(fieldNames));
- if (l.contains("objectId")) {
- l.remove("objectId");
- }
-
- fieldNames = l.toArray(new String[l.size()]);
- } else {
- fieldNames = new String[]{"createdAt", "updatedAt"};
- }
-
- visibleFieldsStore = new ListPreferenceStore(PREF_KEY + className);
- if (visibleFieldsStore.isEmpty()) {
- visibleFieldsStore.add("createdAt");
- visibleFieldsStore.add("updatedAt");
- }
-
- sortPreferenceStore = new SortPreferenceStore(PREF_SORT + className);
- statefulLayout = findViewById(R.id.stateful_layout);
-
- initList();
- }
-
- private void initList() {
- ListView listView = findViewById(R.id.list_view);
- statefulLayout.showLoading();
- ParseQuery query = new ParseQuery<>(className);
-
- if (!sortPreferenceStore.isEmpty()) {
- if (sortPreferenceStore.isAsc()) {
- query.orderByAscending(sortPreferenceStore.getKey());
- } else {
- query.orderByDescending(sortPreferenceStore.getKey());
- }
- }
-
- LazyList list = new LazyList<>(query);
- adapter = new ParseObjectsAdapter(this, list, visibleFieldsStore.getList());
- listView.setAdapter(adapter);
- listView.setOnScrollListener(new ScrollInfiniteListener(adapter));
- adapter.setOnClickListener(this);
-
- if (list.getLimit() == 0) {
- statefulLayout.showEmpty(R.drawable.ic_parse_24dp, getString(R.string.empty_state_objects_screen_short), getString(R.string.empty_state_objects_screen_long));
- return;
- }
-
- statefulLayout.showContent();
- }
-
- @Override
- public void onClick(ParseObject parseObject) {
- Intent i = new Intent(this, SingleObjectParseActivity.class);
- i.putExtra(Const.BUNDLE_KEY_CLASS_NAME, parseObject.getClassName());
- i.putExtra(Const.BUNDLE_KEY_OBJECT_ID, parseObject.getObjectId());
- this.startActivityForResult(i, 1);
- }
-
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.menu_class_view, menu);
- return true;
- }
-
- private void refresh() {
- initList();
- }
-
- public void onRefresh(MenuItem item) {
- refresh();
- }
-
- public void onSelectFavFields(MenuItem item) {
- List selectedIndices = new ArrayList<>();
-
- for (int i=0; i {
- visibleFieldsStore.reset();
- for (CharSequence key : text) {
- visibleFieldsStore.add(key.toString());
- }
- adapter.updatePreviewFields(visibleFieldsStore.getList());
- return true;
- })
- .positiveText(R.string.save)
- .show();
- }
-
- private int findKeyIndex(String key) {
- for (int i=0; i adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, fieldNames);
- fieldSelector.setAdapter(adapter);
-
- if (!sortPreferenceStore.isEmpty()) {
- int index = findKeyIndex(sortPreferenceStore.getKey());
- if (index != -1) {
- fieldSelector.setSelection(index);
- ascRadioButton.setChecked(sortPreferenceStore.isAsc());
- descRadioButton.setChecked(!sortPreferenceStore.isAsc());
- }
- }
-
- Button cancelButton = dialog.getCustomView().findViewById(R.id.sort_dialog_button_cancel);
- Button confirmButton = dialog.getCustomView().findViewById(R.id.sort_dialog_button_confirm);
- cancelButton.setOnClickListener(view -> dialog.dismiss());
-
- confirmButton.setOnClickListener(view -> {
- String key = (String) fieldSelector.getSelectedItem();
- boolean asc = ascRadioButton.isChecked();
- sortPreferenceStore.update(key, asc);
- dialog.dismiss();
- refresh();
- });
-
- dialog.show();
- }
-}
diff --git a/app/src/main/java/com/galtashma/parsedashboard/screens/SingleClassParseActivity.kt b/app/src/main/java/com/galtashma/parsedashboard/screens/SingleClassParseActivity.kt
new file mode 100644
index 0000000..3901e31
--- /dev/null
+++ b/app/src/main/java/com/galtashma/parsedashboard/screens/SingleClassParseActivity.kt
@@ -0,0 +1,211 @@
+package com.galtashma.parsedashboard.screens
+
+import android.content.Intent
+import android.os.Bundle
+import android.os.PersistableBundle
+import android.util.Log
+import android.view.Menu
+import android.view.MenuItem
+import android.widget.*
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.widget.Toolbar
+import com.afollestad.materialdialogs.MaterialDialog
+import com.galtashma.lazyparse.LazyList
+import com.galtashma.lazyparse.ScrollInfiniteAdapter
+import com.galtashma.lazyparse.ScrollInfiniteListener
+import com.galtashma.parsedashboard.Const
+import com.galtashma.parsedashboard.ListPreferenceStore
+import com.galtashma.parsedashboard.R
+import com.galtashma.parsedashboard.SortPreferenceStore
+import com.galtashma.parsedashboard.adapters.ParseObjectsAdapter
+import com.parse.ParseObject
+import com.parse.ParseQuery
+import com.vlonjatg.progressactivity.ProgressRelativeLayout
+
+/**
+ * Created by gal on 3/16/18, rewritten by Cyb3rKo on 05/12/22.
+ */
+
+private const val PREF_KEY = "KEY_SingleClassParseActivity_"
+private const val PREF_SORT = "SORT_SingleClassParseActivity"
+
+class SingleClassParseActivity :
+ AppCompatActivity(),
+ ScrollInfiniteAdapter.OnClickListener {
+
+ private var className = ""
+ private lateinit var statefulLayout: ProgressRelativeLayout
+ private lateinit var fieldNames: MutableList
+ private lateinit var visibleFieldsStore: ListPreferenceStore
+ private lateinit var sortPreferenceStore: SortPreferenceStore
+
+ private lateinit var adapter: ParseObjectsAdapter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_single_class)
+ val toolbar = findViewById(R.id.toolbar)
+ setSupportActionBar(toolbar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+
+ var extra = intent.extras
+ if (extra == null) {
+ extra = savedInstanceState
+ }
+
+ if (extra == null || !extra.containsKey(Const.BUNDLE_KEY_CLASS_NAME)) {
+ finish()
+ return
+ }
+
+ className = extra.getString(Const.BUNDLE_KEY_CLASS_NAME).toString()
+ title = className
+
+ if (extra.containsKey(Const.BUNDLE_KEY_CLASS_FIELDS_NAME)) {
+ fieldNames = extra.getStringArray(Const.BUNDLE_KEY_CLASS_FIELDS_NAME)!!.toMutableList()
+
+ // Remove objectId field as it is special and is displayed anyway
+ if (fieldNames.contains("objectId")) {
+ fieldNames.remove("objectId")
+ }
+ } else {
+ fieldNames = mutableListOf("createdAt", "updatedAt")
+ }
+
+ visibleFieldsStore = ListPreferenceStore(PREF_KEY + className)
+ if (visibleFieldsStore.isEmpty()) {
+ visibleFieldsStore.add("createdAt")
+ visibleFieldsStore.add("updatedAt")
+ }
+
+ sortPreferenceStore = SortPreferenceStore(PREF_SORT + className)
+ statefulLayout = findViewById(R.id.stateful_layout)
+
+ initList()
+ }
+
+ private fun initList() {
+ val listView = findViewById(R.id.list_view)
+ statefulLayout.showLoading()
+ val query = ParseQuery(className)
+
+ if (!sortPreferenceStore.isEmpty()) {
+ if (sortPreferenceStore.isAsc()) {
+ query.orderByAscending(sortPreferenceStore.getKey())
+ } else {
+ query.orderByDescending(sortPreferenceStore.getKey())
+ }
+ }
+
+ val list = LazyList(query)
+ adapter = ParseObjectsAdapter(this, list, visibleFieldsStore.list)
+ listView.adapter = adapter
+ listView.setOnScrollListener(ScrollInfiniteListener(adapter))
+ adapter.setOnClickListener(this)
+
+ if (list.limit == 0) {
+ statefulLayout.showEmpty(
+ R.drawable.ic_parse_24dp,
+ getString(R.string.empty_state_objects_screen_short),
+ getString(R.string.empty_state_objects_screen_long)
+ )
+ return
+ }
+
+ statefulLayout.showContent()
+ }
+
+ override fun onClick(parseObject: ParseObject?) {
+ val i = Intent(this, SingleObjectParseActivity::class.java)
+ i.putExtra(Const.BUNDLE_KEY_CLASS_NAME, parseObject?.className)
+ i.putExtra(Const.BUNDLE_KEY_OBJECT_ID, parseObject?.objectId)
+ startActivityForResult(i, 1)
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.menu_class_view, menu)
+ return true
+ }
+
+ private fun refresh() = initList()
+
+ @Suppress("UNUSED_PARAMETER")
+ fun onRefresh(item: MenuItem) = refresh()
+
+ @Suppress("UNUSED_PARAMETER")
+ fun onSelectFavFields(item: MenuItem) {
+ val selectedIndices = mutableListOf()
+
+ fieldNames.forEachIndexed { index, fieldName ->
+ if (visibleFieldsStore.exists(fieldName)) {
+ selectedIndices.add(index)
+ }
+ }
+
+ Log.d("ParseDashboard", "Selected indices: $selectedIndices")
+
+ MaterialDialog.Builder(this)
+ .title(R.string.action_select_fav_fields)
+ .items(fieldNames)
+ .itemsCallbackMultiChoice(selectedIndices.toTypedArray()) { _, _, text ->
+ visibleFieldsStore.reset()
+ text.forEach { key ->
+ visibleFieldsStore.add(key.toString())
+ }
+ adapter.updatePreviewFields(visibleFieldsStore.list)
+ true
+ }
+ .positiveText(R.string.save)
+ .show()
+ }
+
+ private fun findKeyIndex(key: String): Int {
+ fieldNames.forEachIndexed { index, k ->
+ if (k == key) return index
+ }
+ return -1
+ }
+
+ @Suppress("UNUSED_PARAMETER")
+ fun onSelectOrderFields(item: MenuItem) {
+ val dialog = MaterialDialog.Builder(this)
+ .title("Sort Fields")
+ .customView(R.layout.dialog_field_sort, false).build()
+
+ if (dialog.customView == null) return
+
+ val dialogView = dialog.customView!!
+ val fieldSelector = dialogView.findViewById(R.id.sort_dialog_selected_field)
+ val ascRadioButton = dialogView.findViewById(R.id.sort_dialog_order_asc)
+ val descRadioButton = dialogView.findViewById(R.id.sort_dialog_order_desc)
+ val adapter = ArrayAdapter(
+ this,
+ android.R.layout.simple_spinner_dropdown_item,
+ fieldNames
+ )
+ fieldSelector.adapter = adapter
+
+ if (!sortPreferenceStore.isEmpty()) {
+ val index = findKeyIndex(sortPreferenceStore.getKey())
+ if (index != -1) {
+ fieldSelector.setSelection(index)
+ ascRadioButton.isChecked = sortPreferenceStore.isAsc()
+ descRadioButton.isChecked = !sortPreferenceStore.isAsc()
+ }
+ }
+
+ val cancelButton = dialogView.findViewById