diff --git a/.gitignore b/.gitignore index 2b75303..503d55c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ /build /captures .externalNativeBuild +lib/build/generated +lib/build diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 34dc27c..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index 79ee123..a55e7a1 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,5 @@ - \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..ef688f2 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/dictionaries/.xml b/.idea/dictionaries/.xml deleted file mode 100644 index 68cf6a6..0000000 --- a/.idea/dictionaries/.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - bindable - snackbar - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 97626ba..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 5d6f65c..d7d05b2 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,18 +1,25 @@ + diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..dc07417 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..fdf8d99 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 10467e7..561e5d5 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,16 @@ - - + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 2588e5f..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/Crash/.gitignore b/Crash/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/Crash/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/Crash/build.gradle b/Crash/build.gradle new file mode 100644 index 0000000..362cc5f --- /dev/null +++ b/Crash/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + + + +android { + compileSdkVersion 31 + + defaultConfig { + minSdkVersion 19 + targetSdkVersion 31 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.6.0' + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.4.0' + implementation 'com.github.Omega-R.OmegaIntentBuilder:core:1.3.4' + implementation "com.squareup.retrofit2:retrofit:2.9.0" + + testImplementation 'junit:junit:4.+' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' +} \ No newline at end of file diff --git a/Crash/consumer-rules.pro b/Crash/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/Crash/proguard-rules.pro b/Crash/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/Crash/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/Crash/src/androidTest/java/com/omega_r/base/crash/ExampleInstrumentedTest.kt b/Crash/src/androidTest/java/com/omega_r/base/crash/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..1b150ea --- /dev/null +++ b/Crash/src/androidTest/java/com/omega_r/base/crash/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.omega_r.base.crash + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * 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.omega_r.base.crash.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/Crash/src/main/AndroidManifest.xml b/Crash/src/main/AndroidManifest.xml new file mode 100644 index 0000000..71b59ec --- /dev/null +++ b/Crash/src/main/AndroidManifest.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Crash/src/main/java/com/omega_r/base/crash/CrashInitProvider.kt b/Crash/src/main/java/com/omega_r/base/crash/CrashInitProvider.kt new file mode 100644 index 0000000..4fe06b3 --- /dev/null +++ b/Crash/src/main/java/com/omega_r/base/crash/CrashInitProvider.kt @@ -0,0 +1,32 @@ +package com.omega_r.base.crash + +import android.app.Application +import android.content.ContentProvider +import android.content.ContentValues +import android.database.Cursor +import android.net.Uri +import com.omega_r.base.crash.CrashSender.Companion + +class CrashInitProvider: ContentProvider() { + + override fun onCreate(): Boolean { + (context?.applicationContext as? Application)?.also(Companion::setup) + return false + } + + override fun query( + uri: Uri, + projection: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor? = null + + override fun getType(uri: Uri): String? = null + + override fun insert(uri: Uri, values: ContentValues?): Uri? = null + + override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int = 0 + + override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int = 0 +} \ No newline at end of file diff --git a/Crash/src/main/java/com/omega_r/base/crash/CrashReport.kt b/Crash/src/main/java/com/omega_r/base/crash/CrashReport.kt new file mode 100644 index 0000000..df272f8 --- /dev/null +++ b/Crash/src/main/java/com/omega_r/base/crash/CrashReport.kt @@ -0,0 +1,10 @@ +package com.omega_r.base.crash + +import android.graphics.Bitmap + + +class CrashReport( + val info: Map>, + val stacktrace: String, + val screenshot: Bitmap? +) \ No newline at end of file diff --git a/Crash/src/main/java/com/omega_r/base/crash/CrashSender.kt b/Crash/src/main/java/com/omega_r/base/crash/CrashSender.kt new file mode 100644 index 0000000..a2759d2 --- /dev/null +++ b/Crash/src/main/java/com/omega_r/base/crash/CrashSender.kt @@ -0,0 +1,188 @@ +package com.omega_r.base.crash + +import android.annotation.SuppressLint +import android.app.Activity +import android.app.Application +import android.content.Context +import android.content.pm.PackageManager +import android.graphics.Bitmap +import android.graphics.Canvas +import android.os.Build +import android.os.Bundle +import android.view.View +import androidx.core.content.pm.PackageInfoCompat +import java.io.PrintWriter +import java.io.StringWriter +import java.lang.Exception +import java.lang.ref.WeakReference +import java.util.concurrent.CopyOnWriteArrayList +import java.util.concurrent.CopyOnWriteArraySet + + +class CrashSender(context: Context) : Thread.UncaughtExceptionHandler, + Application.ActivityLifecycleCallbacks { + + companion object { + + val senderWays = CopyOnWriteArraySet().apply { + add(EmailSenderCrashWay()) + } + + val reporters = CopyOnWriteArraySet() + + @SuppressLint("StaticFieldLeak") + private var singleCrashSender: CrashSender? = null + + fun setup(application: Application) { + singleCrashSender?.let { + application.unregisterActivityLifecycleCallbacks(it) + OmegaUncaughtExceptionHandler.remove(it) + } + val handler = CrashSender(application) + OmegaUncaughtExceptionHandler.add(handler) + application.registerActivityLifecycleCallbacks(handler) + singleCrashSender = handler + } + + + } + + private val context = context.applicationContext + private var activityWeakRef: WeakReference? = null + + override fun uncaughtException(thread: Thread, error: Throwable) { + try { + val currentActivity = activityWeakRef?.get() + val screenshotBitmap = currentActivity?.createScreenshotBitmap() + val crashReport = createCrashReport(currentActivity, error, screenshotBitmap) + + senderWays.forEach { + try { + it.send(context, currentActivity, error, crashReport) + } catch (e: Exception) { + e.printStackTrace() + } + } + + screenshotBitmap?.recycle() + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun createCrashReport(currentActivity: Activity?, error: Throwable, screenshotBitmap: Bitmap?): CrashReport { + val info = mutableMapOf>().apply { + putGroupMap("OS", getOsInfo()) + putGroupMap("Application", getApplicationInfo()) + putGroupMap("Activity", getActivityInfo(currentActivity)) + } + + reporters.forEach { + it.report(info) + } + + return CrashReport(info, getStackTrace(error) ?: "", screenshotBitmap) + } + + private fun MutableMap>.putGroupMap(groupName: String, map: Map?) { + if (map?.isNotEmpty() == true) { + put(groupName, map) + } + } + + private fun getActivityInfo(currentActivity: Activity?): Map? { + if (currentActivity != null) { + val title = currentActivity.title + + return mutableMapOf().also { map -> + currentActivity::class.simpleName?.let { map["ClassName"] = it } + title?.let { map["title"] = title.toString() } + } + } + return null + } + + private fun getOsInfo(): Map? { + return mapOf("Version" to "Android ${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})") + } + + + private fun getApplicationInfo(): Map? { + try { + with(context.packageManager.getPackageInfo(context.packageName, 0)) { + return mapOf( + "Package" to packageName, + "Version Name" to versionName, + "Version Code" to PackageInfoCompat.getLongVersionCode(this).toString() + ) + } + } catch (e: PackageManager.NameNotFoundException) { + return null // Ignored, this shouldn't happen + } + } + + private fun getStackTrace(error: Throwable): String? { + val stack: Array = error.stackTrace + if (stack.isNotEmpty()) { + val stringWriter = StringWriter() + val printWriter = PrintWriter(stringWriter) + error.printStackTrace(printWriter) + return stringWriter.toString() + } + return null + } + + private fun Activity.createScreenshotBitmap(): Bitmap? { + val window = window ?: return null + val view = window.decorView + return getBitmapFromView(view) + } + + private fun getBitmapFromView(view: View): Bitmap? { + val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + view.draw(canvas) + return bitmap + } + + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + // nothing + } + + override fun onActivityStarted(activity: Activity) { + // nothing + } + + override fun onActivityResumed(activity: Activity) { + activityWeakRef = WeakReference(activity) + } + + override fun onActivityPaused(activity: Activity) { + activityWeakRef = null + } + + override fun onActivityStopped(activity: Activity) { + // nothing + } + + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { + // nothing + } + + override fun onActivityDestroyed(activity: Activity) { + // nothing + } + + interface SenderCrashWay { + + fun send(context: Context, currentActivity: Activity?, error: Throwable, crashReport: CrashReport) + + } + + interface CrashReporter { + + fun report(map: MutableMap>) + + } + +} \ No newline at end of file diff --git a/Crash/src/main/java/com/omega_r/base/crash/EmailSenderCrashWay.kt b/Crash/src/main/java/com/omega_r/base/crash/EmailSenderCrashWay.kt new file mode 100644 index 0000000..b59b96e --- /dev/null +++ b/Crash/src/main/java/com/omega_r/base/crash/EmailSenderCrashWay.kt @@ -0,0 +1,54 @@ +package com.omega_r.base.crash + +import android.app.Activity +import android.content.Context +import com.omega_r.libs.omegaintentbuilder.OmegaIntentBuilder +import java.io.PrintWriter +import java.io.StringWriter + +class EmailSenderCrashWay(private val emailTo: String? = null) : CrashSender.SenderCrashWay { + + override fun send(context: Context, currentActivity: Activity?, error: Throwable, crashReport: CrashReport) { + OmegaIntentBuilder.share() + .subject("~ CRASH REPORT ~") + .text(createBodyText(crashReport)) + .apply { + crashReport.screenshot?.let { bitmap(crashReport.screenshot) } + emailTo?.let { emailTo(emailTo) } + } + .startActivity(context) + } + + private fun createBodyText(crashReport: CrashReport): String { + val stringWriter = StringWriter() + with(PrintWriter(stringWriter)) { + printGroupMap(crashReport.info) + printGroupSingleValue("Stack Trace", crashReport.stacktrace) + } + return stringWriter.toString() + } + + + private fun PrintWriter.printGroupMap(map: Map>) { + map.forEach { + println("[${it.key}]: ") + printMap(it.value) + println() + } + } + + private fun PrintWriter.printGroupSingleValue(groupName: String, value: String) { + if (value.isNotEmpty()) { + println("[$groupName]: ") + println(value) + println() + } + } + + private fun PrintWriter.printMap(map: Map) { + map.forEach { + println(" - ${it.key}: ${it.value}") + } + } + +} \ No newline at end of file diff --git a/Crash/src/main/java/com/omega_r/base/crash/OmegaUncaughtExceptionHandler.kt b/Crash/src/main/java/com/omega_r/base/crash/OmegaUncaughtExceptionHandler.kt new file mode 100644 index 0000000..42e9a39 --- /dev/null +++ b/Crash/src/main/java/com/omega_r/base/crash/OmegaUncaughtExceptionHandler.kt @@ -0,0 +1,35 @@ +package com.omega_r.base.crash + +import java.lang.Thread.UncaughtExceptionHandler +import java.util.concurrent.CopyOnWriteArraySet + +object OmegaUncaughtExceptionHandler : UncaughtExceptionHandler { + + private var defaultHandler: UncaughtExceptionHandler? = null + + private val uncaughtExceptionHandlers = CopyOnWriteArraySet() + + init { + defaultHandler = Thread.getDefaultUncaughtExceptionHandler() + Thread.setDefaultUncaughtExceptionHandler(this) + } + + override fun uncaughtException(thread: Thread, error: Throwable) { + try { + uncaughtExceptionHandlers.forEach { + it.uncaughtException(thread, error) + } + } finally { + defaultHandler?.uncaughtException(thread, error) + } + } + + fun add(handler: UncaughtExceptionHandler) { + uncaughtExceptionHandlers.add(handler) + } + + fun remove(handler: UncaughtExceptionHandler) { + uncaughtExceptionHandlers.remove(handler) + } + +} \ No newline at end of file diff --git a/Crash/src/main/java/com/omega_r/base/crash/RocketChatSenderCrashWay.kt b/Crash/src/main/java/com/omega_r/base/crash/RocketChatSenderCrashWay.kt new file mode 100644 index 0000000..86d4979 --- /dev/null +++ b/Crash/src/main/java/com/omega_r/base/crash/RocketChatSenderCrashWay.kt @@ -0,0 +1,92 @@ +package com.omega_r.base.crash + +import android.app.Activity +import android.content.Context +import android.util.Log +import okhttp3.* +import org.json.JSONObject +import java.io.IOException + + +class RocketChatSenderCrashWay(private val webHookUrl: String) : CrashSender.SenderCrashWay { + + companion object { + private val MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8") + } + + private val client = OkHttpClient() + + override fun send(context: Context, currentActivity: Activity?, error: Throwable, crashReport: CrashReport) { + val content = """ + { + "text": ${JSONObject.quote("```\n" + crashReport.stacktrace + "\n```")}, + ${getJsonAttachments(crashReport.info)} + + } + """.trimIndent() + val body = RequestBody.create( + MEDIA_TYPE_JSON, + content + ) + + val request: Request = Request.Builder() + .post(body) + .url(webHookUrl) + .build() + + + client.newCall(request).enqueue(object : Callback { + + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + override fun onResponse(call: Call, response: Response) { + // nothing + } + + }) + + Thread.sleep(1) + + } + + private fun getJsonFields(map: Map): String { + val entries = map.entries + return StringBuilder().apply { + append("\"fields\":[") + entries.forEachIndexed { index, entry -> + if (index > 0) { + append(",") + } + append("{") + append("\"title\": ${JSONObject.quote(entry.key)}, ") + append("\"value\": ${JSONObject.quote(entry.value)}") + append("}") + + + } + append("]") + }.toString() + } + + private fun getJsonAttachments(map: Map>): String { + val entries = map.entries + return StringBuilder().apply { + append("\"attachments\":[") + entries.forEachIndexed { index, entry -> + if (index > 0) { + append(",") + } + append("{") + append("\"title\": ${JSONObject.quote(entry.key)}, ") + append(getJsonFields(entry.value)) + append("}") + + } + append("]") + }.toString() + + } + +} \ No newline at end of file diff --git a/Crash/src/test/java/com/omega_r/base/crash/ExampleUnitTest.kt b/Crash/src/test/java/com/omega_r/base/crash/ExampleUnitTest.kt new file mode 100644 index 0000000..ad8dd7a --- /dev/null +++ b/Crash/src/test/java/com/omega_r/base/crash/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.omega_r.base.crash + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/README.md b/README.md index abc2b92..6dac785 100644 --- a/README.md +++ b/README.md @@ -1 +1,18 @@ -# OmegaBase \ No newline at end of file +[![](https://jitpack.io/v/Omega-R/OmegaBase.svg)](https://jitpack.io/#Omega-R/OmegaBase) +[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://opensource.org/licenses/MIT) +# OmegaBase + + +Add it in your root build.gradle at the end of repositories: + + allprojects { + repositories { + ... + maven { url 'https://jitpack.io' } + } + } +Step 2. Add the dependency + + dependencies { + implementation 'com.github.Omega-R:OmegaBase:1.3.1' + } diff --git a/lib/.gitignore b/annotations/.gitignore similarity index 100% rename from lib/.gitignore rename to annotations/.gitignore diff --git a/annotations/build.gradle b/annotations/build.gradle new file mode 100644 index 0000000..178a53a --- /dev/null +++ b/annotations/build.gradle @@ -0,0 +1,38 @@ +apply plugin: 'kotlin' +apply plugin: 'maven-publish' + + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +publishing { + publications { + release(MavenPublication) { + groupId = 'com.github.Omega-R.OmegaBase' + artifactId = 'annotations' + version project.hasProperty('version') ? project.version : gradle.gitHash() + + afterEvaluate { + from components.java + } + } + } + repositories { + maven { + url gradle.nexusUrl + credentials { + username gradle.nexusUsername + password gradle.nexusPassword + } + } + } + + dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "org.jetbrains.kotlin:kotlin-reflect" + //noinspection DifferentStdlibGradleVersion + } + +} diff --git a/annotations/src/main/java/com/omega_r/base/annotations/AppOmegaRepository.kt b/annotations/src/main/java/com/omega_r/base/annotations/AppOmegaRepository.kt new file mode 100644 index 0000000..7b992f8 --- /dev/null +++ b/annotations/src/main/java/com/omega_r/base/annotations/AppOmegaRepository.kt @@ -0,0 +1,5 @@ +package com.omega_r.base.annotations + +@Retention(AnnotationRetention.SOURCE) +@Target(allowedTargets = [AnnotationTarget.CLASS]) +annotation class AppOmegaRepository \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 39c8e6e..1d34a20 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,14 +1,16 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' +apply plugin: 'com.google.devtools.ksp' +apply plugin: 'kotlin-parcelize' android { - compileSdkVersion 28 + compileSdk 33 defaultConfig { applicationId "com.omega_r.omegabase.simple" - minSdkVersion 14 - targetSdkVersion 28 + multiDexEnabled true + minSdkVersion 21 + targetSdkVersion 31 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -19,22 +21,52 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + + packagingOptions { + pickFirst 'META-INF/kotlinx-io.kotlin_module' + pickFirst 'META-INF/atomicfu.kotlin_module' + pickFirst 'META-INF/kotlinx-coroutines-io.kotlin_module' + pickFirst 'META-INF/library_release.kotlin_module' + pickFirst 'META-INF/core_release.kotlin_module' + } + + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + +} + +kotlin { + sourceSets { + main.kotlin.srcDirs += 'build/generated/ksp/debug/kotlin' + } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.0.0-beta01' - implementation 'androidx.core:core-ktx:1.1.0-alpha05' - implementation 'androidx.constraintlayout:constraintlayout:1.1.2' - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.0-alpha4' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4' - implementation project(':lib') - implementation 'com.github.Omega-R:OmegaRecyclerView:1.9.4' - implementation 'com.github.Omega-R.OmegaMoxy:moxy:1.5.7' - implementation 'com.github.Omega-R.OmegaMoxy:moxy-androidx:1.5.7' - kapt 'com.github.Omega-R.OmegaMoxy:moxy-compiler:1.5.7' - implementation 'com.github.Omega-R.OmegaTypes:omegatypes:0.0.7' + implementation 'androidx.appcompat:appcompat:1.4.0' + implementation 'androidx.core:core-ktx:1.7.0' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${kotlinCorutines_version}" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${kotlinCorutines_version}" + implementation 'androidx.constraintlayout:constraintlayout:2.2.0-alpha04' + implementation 'androidx.recyclerview:recyclerview:1.2.1' + implementation "com.github.Omega-R.OmegaRecyclerView:omegarecyclerview:${omegaRecyclerView}" + + implementation project(':core') + + ksp "com.github.Omega-R.OmegaMoxy:moxy-compiler:${omegaMoxy_version}" + kapt project(':processor') + + implementation 'com.github.bumptech.glide:glide:4.9.0' + + testImplementation 'junit:junit:4.13-beta-3' + androidTestImplementation 'androidx.test:runner:1.3.0-alpha02' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha02' + implementation 'com.google.android.material:material:1.5.0-beta01' + + ksp project(":mvp-processor") } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e29d537..fa3639f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,14 +2,22 @@ + + + - + + + + diff --git a/app/src/main/java/com/omega_r/base/simple/InspectionRepository.kt b/app/src/main/java/com/omega_r/base/simple/InspectionRepository.kt new file mode 100644 index 0000000..cc161a4 --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/InspectionRepository.kt @@ -0,0 +1,35 @@ +package com.omega_r.base.simple + +import com.omega_r.base.annotations.AppOmegaRepository +import com.omega_r.base.data.OmegaRepository.Strategy +import kotlinx.coroutines.channels.ReceiveChannel + +@AppOmegaRepository +interface InspectionRepository : ParentRepository { + + val isAuth: Boolean? + get() = true + var age: Int + + val inspectionUpdateChannel: ReceiveChannel> + + suspend fun getInspectionsChannel(strategy: Strategy, index: Int): ReceiveChannel + + suspend fun getInspections(strategy: Strategy, index: Int): String + + suspend fun getInspections(pair: Pair, second: Boolean) + + suspend fun pair(): Pair? + + suspend fun returnInt(): Int? + + suspend fun returnBoolean(): Boolean { + return true + } + + fun clearCache() + + // TODO future code generation +// suspend fun lambda(func: (String) -> Boolean): Int + +} \ No newline at end of file diff --git a/app/src/main/java/com/omega_r/base/simple/MainActivity.kt b/app/src/main/java/com/omega_r/base/simple/MainActivity.kt index 5b0df98..e4787f7 100644 --- a/app/src/main/java/com/omega_r/base/simple/MainActivity.kt +++ b/app/src/main/java/com/omega_r/base/simple/MainActivity.kt @@ -1,29 +1,121 @@ package com.omega_r.base.simple -import com.omega_r.base.adapters.OmegaAutoAdapter -import com.omega_r.base.annotations.OmegaContentView +import android.content.pm.PackageManager +import android.os.Bundle +import android.util.Log +import android.view.MenuItem +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import com.omega_r.adapters.OmegaListAdapter import com.omega_r.base.components.OmegaActivity -import com.omega_r.libs.omegarecyclerview.OmegaRecyclerView +import com.omega_r.bind.adapters.OmegaAutoAdapter +import com.omega_r.bind.delegates.IdHolder +import com.omega_r.bind.model.binders.bindImage import com.omega_r.libs.omegatypes.Text +import com.omega_r.libs.omegatypes.image.Image +import com.omega_r.libs.omegatypes.image.from -@OmegaContentView(R.layout.activity_main) -class MainActivity : OmegaActivity(), OmegaAutoAdapter.Callback { +class MainActivity : OmegaActivity(R.layout.activity_main), MainView { - private val adapter = OmegaAutoAdapter.create(R.layout.item_test) { - bind(R.id.textview_test, Item::text) + override val presenter: MainPresenter by providePresenter() + + private val adapter = OmegaAutoAdapter.create(R.layout.item_test_3, ::onClickItem) { + bindImage(R.id.imageview) }.apply { - callback = this@MainActivity + watcher = OmegaListAdapter.ImagePreloadWatcher(this) + list = listOf( + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?156"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?256"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?35"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?45"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?56"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?64"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?79"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?85"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?91"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?102"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?113"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?124"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?135"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?146"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?1578"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?169"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?174"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?185"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?1956"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?201"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?212"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?2212"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?231"), + Image.from("https://i.pinimg.com/originals/d6/68/ab/d668abc72809303852c27275e6a56775.gif?242") + ) + } + + private val recyclerView: RecyclerView by bind(R.id.recyclerview, adapter) { + recyclerView.setHasFixedSize(true) } - private val recyclerView: OmegaRecyclerView by bind(R.id.recyclerview) { - this@MainActivity.adapter.list = listOf(Item(), Item()) - adapter = this@MainActivity.adapter + private val maps: Map by bind(Field.values()) { + //showToast(Text.from(it.id.toString())) } - override fun onClickItem(item: Item, position: Int) { - showToast(Text.from("Click $position")) + override var list: String = "" + + override var enabled: Boolean + get() = false + set(value) { + println("YES") + } + + private val menuItem: MenuItem? by bindMenuItem(R.id.action_test) + + private var imageMenuItem: Image by bindIconMenuItem(R.id.action_test) + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) +// title = this[EXTRA_TITLE] + setClickListener(R.id.button) { + showToast(Text.from("Test")) + } + setMenu(R.menu.menu_main, R.id.action_test to { showToast(Text.from("Test")) }) + imageMenuItem = Image.from(R.drawable.ic_error_omega) + val applicationInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA) + val metaData = applicationInfo.metaData + val email = metaData?.getString("CRASH_SENDER_EMAIL") + Log.v("Test123", email.toString()) + } + + private fun onClickItem(item: Image) { + showToast(Text.from("Click $item")) + throw NullPointerException() +// ActivityLauncher.launch(this, null, createLauncher("1"), createLauncher("2")) + +// createLauncher("1").launch(this, createLauncher("2")) + } + + data class Item( + val text: String = "123", + val list: List = listOf( + SubItem(), + SubItem(), + SubItem(), + SubItem(), + SubItem(), + SubItem(), + SubItem(), + SubItem(), + SubItem(), + SubItem() + ) + ) + + data class SubItem(val text: String = "123") + + enum class Field(override val id: Int) : IdHolder { + ITEM1(R.id.recyclerview), + ITEM2(R.id.recyclerview), } - data class Item (val text: String = "123") } diff --git a/app/src/main/java/com/omega_r/base/simple/MainPresenter.kt b/app/src/main/java/com/omega_r/base/simple/MainPresenter.kt new file mode 100644 index 0000000..83e130d --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/MainPresenter.kt @@ -0,0 +1,65 @@ +package com.omega_r.base.simple + +import android.os.SystemClock +import com.omega_r.base.mvp.presenters.OmegaPresenter +import com.omega_r.base.simple.dialog_fragment.DialogScreenFactory +import com.omega_r.libs.omegatypes.Text +import java.io.Serializable + +/** + * Created by Anton Knyazev on 06.05.19. + */ +typealias TestEntity2 = TestEntity +class MainPresenter(testEntity: TestEntity?, t2: TestEntity2?): OmegaPresenter() { + + companion object { + var lastTime = SystemClock.elapsedRealtime() + } + + init { + + val time = (SystemClock.elapsedRealtime() - lastTime) + lastTime = SystemClock.elapsedRealtime() + + if (testEntity == null) { + MainScreenFactory.createLauncher(TestEntity(), TestEntity()).launch() + } else { + println("TestAnt: $time") + viewState.showToast(Text.from(time.toString())) + + } + viewState.enabled = false +// launch { +// try { +// Retrofit.Builder() +// .baseUrl("https://git.omega-r.club") +// .build() +// .create(Api::class.java) +// .test("aga", RequestBody.create(MediaType.get("text/html"), "Run")) +// } catch (e: Exception) { +// throw ErrorHandler().handleThrowable(e) +// } +// } + + DialogScreenFactory.createLauncher().launch() +// viewState.showMe +// log { +// "Message" +// }ssage(Text.from("test"), Action(Text.from("Test")) { +// viewState.showToast(Text.from("test")) +// }) +// +// viewState.showQuery( +// Text.from("message"), +// Text.from("title"), +// positiveAction = Action("Yes"), +// negativeAction = Action("No") +// ) + } + + override fun onLaunchResult(requestCode: Int, success: Boolean, data: Serializable?): Boolean { + viewState.showToast(Text.from("onLaunchResult = $requestCode")) + return super.onLaunchResult(requestCode, success, data) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/omega_r/base/simple/MainView.kt b/app/src/main/java/com/omega_r/base/simple/MainView.kt new file mode 100644 index 0000000..84a18f8 --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/MainView.kt @@ -0,0 +1,11 @@ +package com.omega_r.base.simple + +import com.omega_r.base.mvp.views.OmegaView + +interface MainView: OmegaView { + + var list: String + + var enabled: Boolean +} + diff --git a/app/src/main/java/com/omega_r/base/simple/ParentRepository.kt b/app/src/main/java/com/omega_r/base/simple/ParentRepository.kt new file mode 100644 index 0000000..e59fb55 --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/ParentRepository.kt @@ -0,0 +1,7 @@ +package com.omega_r.base.simple + +interface ParentRepository { + + suspend fun parentMethod(): String + +} \ No newline at end of file diff --git a/app/src/main/java/com/omega_r/base/simple/SampleApp.kt b/app/src/main/java/com/omega_r/base/simple/SampleApp.kt new file mode 100644 index 0000000..86c318e --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/SampleApp.kt @@ -0,0 +1,11 @@ +package com.omega_r.base.simple + +import android.app.Application + +class SampleApp : Application() { + + override fun onCreate() { + super.onCreate() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/omega_r/base/simple/Settings.kt b/app/src/main/java/com/omega_r/base/simple/Settings.kt new file mode 100644 index 0000000..7e81885 --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/Settings.kt @@ -0,0 +1,17 @@ +package com.omega_r.base.simple + +import com.omega_r.base.settings.BaseSettings +import com.omega_r.base.settings.SettingStorage +import com.squareup.moshi.Moshi +import com.squareup.moshi.adapter + +class Settings(setting: SettingStorage, moshi: Moshi): BaseSettings(setting) { + + var firstLaunch by provideBoolean(key = "jklh", defaultValue = false, label = "possim") + + @OptIn(ExperimentalStdlibApi::class) + var session: Session? by provideAnyJson(key = "", defaultValue = null, label = "sdf", moshi.adapter()) + + class Session(val token: String, val refreshToken: String) + +} \ No newline at end of file diff --git a/app/src/main/java/com/omega_r/base/simple/TestEntity.kt b/app/src/main/java/com/omega_r/base/simple/TestEntity.kt new file mode 100644 index 0000000..7de29bd --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/TestEntity.kt @@ -0,0 +1,11 @@ +package com.omega_r.base.simple + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize +import java.io.Serializable + +@Parcelize +class TestEntity : Parcelable, Serializable { + + +} \ No newline at end of file diff --git a/app/src/main/java/com/omega_r/base/simple/TestFragment.kt b/app/src/main/java/com/omega_r/base/simple/TestFragment.kt new file mode 100644 index 0000000..3b76967 --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/TestFragment.kt @@ -0,0 +1,6 @@ +package com.omega_r.base.simple + +import com.omegar.mvp.MvpAppCompatFragment + +class TestFragment(contentLayoutId: Int) : MvpAppCompatFragment(contentLayoutId) { +} \ No newline at end of file diff --git a/app/src/main/java/com/omega_r/base/simple/dialog_fragment/DialogDialogFragment.kt b/app/src/main/java/com/omega_r/base/simple/dialog_fragment/DialogDialogFragment.kt new file mode 100644 index 0000000..784a0b2 --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/dialog_fragment/DialogDialogFragment.kt @@ -0,0 +1,26 @@ +package com.omega_r.base.simple.dialog_fragment + +import android.os.Bundle +import com.omega_r.base.annotations.OmegaContentView +import com.omega_r.base.components.OmegaDialogFragment +import com.omega_r.base.simple.R +import com.omega_r.libs.omegatypes.Text +import com.omegar.libs.omegalaunchers.createDialogFragmentLauncher + +/** + * Created by Anton Knyazev on 10.03.2020. + */ +@OmegaContentView(R.layout.activity_main) +class DialogDialogFragment : OmegaDialogFragment(), DialogView { + + + override val presenter: DialogPresenter by providePresenter() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setClickListener(R.id.button) { + showToast(Text.from("Test from dialog")) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/omega_r/base/simple/dialog_fragment/DialogPresenter.kt b/app/src/main/java/com/omega_r/base/simple/dialog_fragment/DialogPresenter.kt new file mode 100644 index 0000000..0b3cd00 --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/dialog_fragment/DialogPresenter.kt @@ -0,0 +1,10 @@ +package com.omega_r.base.simple.dialog_fragment + +import com.omega_r.base.mvp.presenters.OmegaPresenter + +/** + * Created by Anton Knyazev on 10.03.2020. + */ +class DialogPresenter : OmegaPresenter() { + +} \ No newline at end of file diff --git a/app/src/main/java/com/omega_r/base/simple/dialog_fragment/DialogView.kt b/app/src/main/java/com/omega_r/base/simple/dialog_fragment/DialogView.kt new file mode 100644 index 0000000..da2a40b --- /dev/null +++ b/app/src/main/java/com/omega_r/base/simple/dialog_fragment/DialogView.kt @@ -0,0 +1,8 @@ +package com.omega_r.base.simple.dialog_fragment + +import com.omega_r.base.mvp.views.OmegaView + +/** + * Created by Anton Knyazev on 10.03.2020. + */ +interface DialogView: OmegaView \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 93fcf82..0e5e488 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,14 +1,26 @@ - +