diff --git a/husky/app/build.gradle b/husky/app/build.gradle deleted file mode 100644 index eb6f662..0000000 --- a/husky/app/build.gradle +++ /dev/null @@ -1,206 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'kotlin-kapt' - -apply from: "../instance-build.gradle" - -def getGitSha = { - def stdout = new ByteArrayOutputStream() - exec { - commandLine 'git', 'rev-parse', '--short', 'HEAD' - standardOutput = stdout - } - return stdout.toString().trim() -} - -def buildnum = { - def today = new Date() - def epoch = new Date(119, 11, 8) // first Husky commit was 20191208 - return today - epoch -} - -android { - compileSdkVersion 29 - // ndkVersion "20.1.5948944" - defaultConfig { - applicationId APP_ID - minSdkVersion 21 - targetSdkVersion 29 - versionCode buildnum() - versionName "1.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - vectorDrawables.useSupportLibrary = true - - resValue "string", "app_name", APP_NAME - - buildConfigField("String", "APPLICATION_NAME", "\"$APP_NAME\"") - buildConfigField("String", "CUSTOM_LOGO_URL", "\"$CUSTOM_LOGO_URL\"") - buildConfigField("String", "CUSTOM_INSTANCE", "\"$CUSTOM_INSTANCE\"") - buildConfigField("String", "SUPPORT_ACCOUNT_URL", "\"$SUPPORT_ACCOUNT_URL\"") - - kapt { - arguments { - arg("room.schemaLocation", "$projectDir/schemas") - arg("room.incremental", "true") - } - } - } - buildTypes { - release { - minifyEnabled true - shrinkResources true - proguardFiles 'proguard-rules.pro' - } - debug {} - } - - flavorDimensions "husky", "color" - productFlavors { - husky { dimension "husky" } - - blue { dimension "color" } - green { - dimension "color" - resValue "string", "app_name", APP_NAME + " Test" - applicationIdSuffix ".test" - versionNameSuffix "-" + getGitSha() - } - } - - lintOptions { - //abortOnError false - disable 'MissingTranslation' - disable 'ExtraTranslation' - disable 'AppCompatCustomView' // I don't care about AppCompat bloat - disable 'UseRequireInsteadOfGet' - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - androidExtensions { - experimental = true - } - buildFeatures { - viewBinding true - } - testOptions { - unitTests { - returnDefaultValues = true - includeAndroidResources = true - } - } - sourceSets { - androidTest.assets.srcDirs += files("$projectDir/schemas".toString()) - } - - packagingOptions { - // Exclude unneeded files added by libraries - exclude 'LICENSE_OFL' - exclude 'LICENSE_UNICODE' - } - bundle { - language { - // bundle all languages in every apk so the dynamic language switching works - enableSplit = false - } - } -} - -project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { - kotlinOptions { - jvmTarget = "1.8" - } -} - -ext.lifecycleVersion = "2.2.0" -ext.roomVersion = '2.2.5' -ext.retrofitVersion = '2.9.0' -ext.okhttpVersion = '4.9.0' -ext.glideVersion = '4.11.0' -ext.daggerVersion = '2.30.1' -ext.materialdrawerVersion = '8.2.0' - -// if libraries are changed here, they should also be changed in LicenseActivity -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - - implementation "androidx.core:core-ktx:1.3.2" - implementation "androidx.appcompat:appcompat:1.2.0" - implementation "androidx.fragment:fragment-ktx:1.2.5" - implementation "androidx.browser:browser:1.3.0" - implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" - implementation "androidx.recyclerview:recyclerview:1.1.0" - implementation "androidx.exifinterface:exifinterface:1.3.2" - implementation "androidx.cardview:cardview:1.0.0" - implementation "androidx.preference:preference-ktx:1.1.1" - implementation "androidx.sharetarget:sharetarget:1.0.0" - implementation "androidx.emoji:emoji:1.1.0" - implementation "androidx.emoji:emoji-appcompat:1.1.0" - implementation "androidx.emoji:emoji-bundled:1.1.0" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion" - implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycleVersion" - implementation "androidx.constraintlayout:constraintlayout:2.0.4" - implementation "androidx.paging:paging-runtime-ktx:2.1.2" - implementation "androidx.viewpager2:viewpager2:1.0.0" - implementation "androidx.work:work-runtime:2.4.0" - implementation "androidx.room:room-runtime:$roomVersion" - implementation "androidx.room:room-rxjava2:$roomVersion" - kapt "androidx.room:room-compiler:$roomVersion" - - implementation "com.google.android.material:material:1.2.1" - implementation 'com.google.android:flexbox:2.0.1' - - implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" - implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion" - implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion" - - implementation "com.squareup.okhttp3:okhttp:$okhttpVersion" - implementation "com.squareup.okhttp3:logging-interceptor:$okhttpVersion" - implementation "com.squareup.okhttp3:okhttp-brotli:$okhttpVersion" - - implementation "org.conscrypt:conscrypt-android:2.5.1" - - implementation "com.github.bumptech.glide:glide:$glideVersion" - implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion" - kapt "com.github.bumptech.glide:compiler:$glideVersion" - - implementation "io.reactivex.rxjava2:rxjava:2.2.20" - implementation "io.reactivex.rxjava2:rxandroid:2.1.1" - implementation "io.reactivex.rxjava2:rxkotlin:2.4.0" - - implementation "com.uber.autodispose:autodispose-android-archcomponents:1.4.0" - implementation "com.uber.autodispose:autodispose:1.4.0" - - implementation "com.google.dagger:dagger:$daggerVersion" - kapt "com.google.dagger:dagger-compiler:$daggerVersion" - implementation "com.google.dagger:dagger-android:$daggerVersion" - implementation "com.google.dagger:dagger-android-support:$daggerVersion" - kapt "com.google.dagger:dagger-android-processor:$daggerVersion" - - implementation "com.github.connyduck:sparkbutton:4.1.0" - - implementation 'com.github.piasy:BigImageViewer:1.7.0' - implementation 'com.github.piasy:GlideImageLoader:1.7.0' - implementation 'com.github.piasy:GlideImageViewFactory:1.7.0' - - implementation "com.mikepenz:materialdrawer:$materialdrawerVersion" - implementation "com.mikepenz:materialdrawer-iconics:$materialdrawerVersion" - implementation 'com.mikepenz:google-material-typeface:3.0.1.4.original-kotlin@aar' - - implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" - - implementation "de.c1710:filemojicompat:1.0.17" - implementation 'com.github.Tunous:MarkdownEdit:1.0.0' - - testImplementation "androidx.test.ext:junit:1.1.2" - testImplementation "org.robolectric:robolectric:4.4" - testImplementation "org.mockito:mockito-inline:3.6.28" - testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" - - androidTestImplementation "androidx.test.espresso:espresso-core:3.3.0" - androidTestImplementation "androidx.room:room-testing:$roomVersion" - androidTestImplementation "androidx.test.ext:junit:1.1.2" -} diff --git a/husky/app/build.gradle.kts b/husky/app/build.gradle.kts new file mode 100644 index 0000000..9282d65 --- /dev/null +++ b/husky/app/build.gradle.kts @@ -0,0 +1,216 @@ +plugins { + id("com.android.application") + + kotlin("android") + id("kotlin-android-extensions") + kotlin("kapt") + + //id("kotlin-parcelize") + id("com.github.ben-manes.versions") +} + +android { + compileSdk = AndroidSDK.compileSdk + buildToolsVersion = AndroidSDK.buildTools + + defaultConfig { + applicationId = DefaultConfig.applicationID + + minSdk = DefaultConfig.minSdk + targetSdk = DefaultConfig.targetSdk + + versionCode = DefaultConfig.versionCodeRel + versionName = DefaultConfig.versionNameRel + + testInstrumentationRunner = DefaultConfig.instrumentationRunner + + vectorDrawables.useSupportLibrary = true + + kapt { + arguments { + arg("room.schemaLocation", "$projectDir/schemas") + arg("room.incremental", true) + } + } + + // TODO: remove, just for compiling + resValue("string", "app_name", "\"${CustomHuskyBuild.applicationName}\"") + buildConfigField("String", "APPLICATION_NAME", "\"${CustomHuskyBuild.applicationName}\"") + buildConfigField("String", "CUSTOM_LOGO_URL", "\"${CustomHuskyBuild.customLogo}\"") + buildConfigField("String", "CUSTOM_INSTANCE", "\"${CustomHuskyBuild.customInstance}\"") + buildConfigField("String", "SUPPORT_ACCOUNT_URL", "\"${CustomHuskyBuild.supportAccountUrl}\"") + } + + buildTypes { + getByName(BuildTypes.debug) { + isDebuggable = true + isMinifyEnabled = false + isShrinkResources = false + } + + getByName(BuildTypes.release) { + isDebuggable = false + isMinifyEnabled = false + isShrinkResources = false + + proguardFiles( + getDefaultProguardFile(ProguardFile.defaultFile), + ProguardFile.defaultRules + ) + } + + flavorDimensions.addAll( + listOf( + "husky", + "color" + ) + ) + productFlavors { + create("husky") { + dimension = "husky" + } + + create("blue") { + dimension = "color" + } + + create("green") { + dimension = "color" + applicationIdSuffix = ".test" + versionNameSuffix = "-beta" + } + } + + lint { + // isAbortOnError = true + disable("MissingTranslation") + disable("ExtraTranslation") + disable("AppCompatCustomView") + disable("UseRequireInsteadOfGet") + } + + compileOptions { + sourceCompatibility = DefaultConfig.javaVersion + targetCompatibility = DefaultConfig.javaVersion + } + + kotlinOptions { + jvmTarget = DefaultConfig.javaVersion.toString() + } + + buildFeatures { + viewBinding = true + } + + // TODO: remove this, only for compiling + androidExtensions { + isExperimental = true + } + + testOptions { + unitTests { + isReturnDefaultValues = true + isIncludeAndroidResources = true + } + } + + sourceSets { + getByName("androidTest").assets.srcDirs("$projectDir/schemas") + } + + packagingOptions { + resources.excludes.addAll( + listOf( + "LICENSE_OFL", + "LICENSE_UNICODE" + ) + ) + } + + bundle { + language { + enableSplit = true + } + } + } +} + +dependencies { + implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar")))) + + implementation(ApplicationLibs.AndroidX.appCompat) + implementation(ApplicationLibs.AndroidX.browser) + implementation(ApplicationLibs.AndroidX.cardView) + implementation(ApplicationLibs.AndroidX.constraintLayout) + implementation(ApplicationLibs.AndroidX.coreKtx) + implementation(ApplicationLibs.AndroidX.emoji) + implementation(ApplicationLibs.AndroidX.emojiAppCompat) + implementation(ApplicationLibs.AndroidX.emojiBundled) + implementation(ApplicationLibs.AndroidX.exifInterface) + implementation(ApplicationLibs.AndroidX.fragmentKtx) + implementation(ApplicationLibs.AndroidX.pagingRuntimeKtx) + implementation(ApplicationLibs.AndroidX.preferenceKtx) + implementation(ApplicationLibs.AndroidX.recyclerView) + kapt(ApplicationLibs.AndroidX.roomCompiler) + implementation(ApplicationLibs.AndroidX.roomRuntime) + implementation(ApplicationLibs.AndroidX.roomRxJava) + implementation(ApplicationLibs.AndroidX.shareTarget) + implementation(ApplicationLibs.AndroidX.swipeRefreshLayout) + implementation(ApplicationLibs.AndroidX.viewpager2) + implementation(ApplicationLibs.AndroidX.workRuntime) + implementation(ApplicationLibs.AndroidX.Lifecycle.liveDataKtx) + implementation(ApplicationLibs.AndroidX.Lifecycle.reactiveStreamsKtx) + implementation(ApplicationLibs.AndroidX.Lifecycle.viewmodelKtx) + + implementation(ApplicationLibs.Dagger.dagger) + implementation(ApplicationLibs.Dagger.daggerAndroid) + kapt(ApplicationLibs.Dagger.daggerCompiler) + kapt(ApplicationLibs.Dagger.daggerProcessor) + implementation(ApplicationLibs.Dagger.daggerSupport) + + implementation(ApplicationLibs.Glide.glide) + implementation(ApplicationLibs.Glide.glideOkhttp) + kapt(ApplicationLibs.Glide.glideCompiler) + + implementation(ApplicationLibs.Google.flexBox) + implementation(ApplicationLibs.Google.materialDesign) + + implementation(ApplicationLibs.RxJava.rxAndroid) + implementation(ApplicationLibs.RxJava.rxJava) + implementation(ApplicationLibs.RxJava.rxKotlin) + + implementation(ApplicationLibs.Square.retrofit) + implementation(ApplicationLibs.Square.retrofitAdapterRxJ2) + implementation(ApplicationLibs.Square.retrofitConvGson) + implementation(ApplicationLibs.Square.logginInterceptor) + implementation(ApplicationLibs.Square.okhttp) + implementation(ApplicationLibs.Square.okhttpBrotli) + + implementation(ApplicationLibs.Kotlin.stdlibJdk) + + implementation(ApplicationLibs.androidImageCropper) + implementation(ApplicationLibs.autodispose) + implementation(ApplicationLibs.autodisposeAndroidArchComp) + implementation(ApplicationLibs.bigImageViewer) + implementation(ApplicationLibs.conscryptAndroid) + implementation(ApplicationLibs.filemojiCompat) + implementation(ApplicationLibs.glideImage) + implementation(ApplicationLibs.glideImageViewFactory) + implementation(ApplicationLibs.markdownEdit) + implementation(ApplicationLibs.materialDrawer) + implementation(ApplicationLibs.materialDrawerIconics) + implementation(ApplicationLibs.materialDrawerTypeface) + implementation(ApplicationLibs.filemojiCompat) + implementation(ApplicationLibs.sparkButton) + implementation(ApplicationLibs.timber) + + testImplementation(TestLibs.extJunit) + testImplementation(TestLibs.junit) + testImplementation(TestLibs.mockitoInline) + testImplementation(TestLibs.mockitoKotlin) + testImplementation(TestLibs.roboelectric) + + androidTestImplementation(TestLibs.espresso) + androidTestImplementation(TestLibs.junit) + androidTestImplementation(TestLibs.roomTesting) +} diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/di/AppInjector.kt b/husky/app/src/main/java/com/keylesspalace/tusky/di/AppInjector.kt index bd06bfc..cd59201 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/di/AppInjector.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/di/AppInjector.kt @@ -41,22 +41,22 @@ object AppInjector { handleActivity(activity) } - override fun onActivityPaused(activity: Activity?) { + override fun onActivityPaused(activity: Activity) { } - override fun onActivityResumed(activity: Activity?) { + override fun onActivityResumed(activity: Activity) { } - override fun onActivityStarted(activity: Activity?) { + override fun onActivityStarted(activity: Activity) { } - override fun onActivityDestroyed(activity: Activity?) { + override fun onActivityDestroyed(activity: Activity) { } - override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) { + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { } - override fun onActivityStopped(activity: Activity?) { + override fun onActivityStopped(activity: Activity) { } }) @@ -77,4 +77,4 @@ object AppInjector { }, true) } } -} \ No newline at end of file +} diff --git a/husky/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt b/husky/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt index 2f59a58..8ac6676 100644 --- a/husky/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt +++ b/husky/app/src/main/java/com/keylesspalace/tusky/receiver/SendStatusBroadcastReceiver.kt @@ -18,7 +18,6 @@ package com.keylesspalace.tusky.receiver import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.os.Message import android.util.Log import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat @@ -27,12 +26,11 @@ import androidx.core.content.ContextCompat import com.keylesspalace.tusky.R import com.keylesspalace.tusky.components.compose.ComposeActivity import com.keylesspalace.tusky.components.compose.ComposeActivity.ComposeOptions +import com.keylesspalace.tusky.components.notifications.NotificationHelper import com.keylesspalace.tusky.db.AccountManager import com.keylesspalace.tusky.entity.Status import com.keylesspalace.tusky.service.SendTootService import com.keylesspalace.tusky.service.TootToSend -import com.keylesspalace.tusky.components.notifications.NotificationHelper -import com.keylesspalace.tusky.service.MessageToSend import com.keylesspalace.tusky.util.randomAlphanumericString import dagger.android.AndroidInjection import javax.inject.Inject @@ -53,108 +51,106 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() { val senderFullName = intent.getStringExtra(NotificationHelper.KEY_SENDER_ACCOUNT_FULL_NAME) val citedStatusId = intent.getStringExtra(NotificationHelper.KEY_CITED_STATUS_ID) val visibility = intent.getSerializableExtra(NotificationHelper.KEY_VISIBILITY) as Status.Visibility - val spoiler = intent.getStringExtra(NotificationHelper.KEY_SPOILER) - val mentions = intent.getStringArrayExtra(NotificationHelper.KEY_MENTIONS) + val spoiler = intent.getStringExtra(NotificationHelper.KEY_SPOILER) ?: "" + val mentions = intent.getStringArrayExtra(NotificationHelper.KEY_MENTIONS) ?: emptyArray() val citedText = intent.getStringExtra(NotificationHelper.KEY_CITED_TEXT) val localAuthorId = intent.getStringExtra(NotificationHelper.KEY_CITED_AUTHOR_LOCAL) - val chatId = intent.getStringExtra(NotificationHelper.KEY_CHAT_ID) val account = accountManager.getAccountById(senderId) val notificationManager = NotificationManagerCompat.from(context) - if (account == null) { - Log.w(TAG, "Account \"$senderId\" not found in database. Aborting quick reply!") + if (intent.action == NotificationHelper.REPLY_ACTION) { - val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier) + val message = getReplyMessage(intent) + + if (account == null) { + Log.w(TAG, "Account \"$senderId\" not found in database. Aborting quick reply!") + + val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier) + .setSmallIcon(R.drawable.ic_notify) + .setColor(ContextCompat.getColor(context, R.color.tusky_blue)) + .setGroup(senderFullName) + .setDefaults(0) // So it doesn't ring twice, notify only in Target callback + + builder.setContentTitle(context.getString(R.string.error_generic)) + builder.setContentText(context.getString(R.string.error_sender_account_gone)) + + builder.setSubText(senderFullName) + builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + builder.setCategory(NotificationCompat.CATEGORY_SOCIAL) + builder.setOnlyAlertOnce(true) + + notificationManager.notify(notificationId, builder.build()) + } else { + val text = mentions.joinToString(" ", postfix = " ") { "@$it" } + message.toString() + + val sendIntent = SendTootService.sendTootIntent( + context, + TootToSend( + text = text, + warningText = spoiler, + visibility = visibility.serverString(), + sensitive = false, + mediaIds = emptyList(), + mediaUris = emptyList(), + mediaDescriptions = emptyList(), + scheduledAt = null, + inReplyToId = citedStatusId, + poll = null, + replyingStatusContent = null, + replyingStatusAuthorUsername = null, + accountId = account.id, + draftId = -1, + idempotencyKey = randomAlphanumericString(16), + retries = 0, + formattingSyntax = "", + preview = false, + savedTootUid = -1, + ) + ) + + context.startService(sendIntent) + + val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier) .setSmallIcon(R.drawable.ic_notify) .setColor(ContextCompat.getColor(context, (R.color.tusky_blue))) .setGroup(senderFullName) .setDefaults(0) // So it doesn't ring twice, notify only in Target callback - builder.setContentTitle(context.getString(R.string.error_generic)) - builder.setContentText(context.getString(R.string.error_sender_account_gone)) + builder.setContentTitle(context.getString(R.string.status_sent)) + builder.setContentText(context.getString(R.string.status_sent_long)) - builder.setSubText(senderFullName) - builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - builder.setCategory(NotificationCompat.CATEGORY_SOCIAL) - builder.setOnlyAlertOnce(true) + builder.setSubText(senderFullName) + builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + builder.setCategory(NotificationCompat.CATEGORY_SOCIAL) + builder.setOnlyAlertOnce(true) - notificationManager.notify(notificationId, builder.build()) - return - } + notificationManager.notify(notificationId, builder.build()) + } + } else if (intent.action == NotificationHelper.COMPOSE_ACTION) { - if (intent.action == NotificationHelper.COMPOSE_ACTION) { context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) notificationManager.cancel(notificationId) accountManager.setActiveAccount(senderId) - val composeIntent = ComposeActivity.startIntent(context, ComposeOptions( + val composeIntent = ComposeActivity.startIntent( + context, + ComposeOptions( inReplyToId = citedStatusId, replyVisibility = visibility, contentWarning = spoiler, mentionedUsernames = mentions.toSet(), replyingStatusAuthor = localAuthorId, replyingStatusContent = citedText - )) + ) + ) composeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(composeIntent) - } else { - val message = getReplyMessage(intent) - - val sendIntent = if(intent.action == NotificationHelper.REPLY_ACTION) { - val text = mentions.joinToString(" ", postfix = " ") { "@$it" } + message.toString() - - SendTootService.sendTootIntent( - context, - TootToSend( - text = text, - warningText = spoiler, - visibility = visibility.serverString(), - sensitive = false, - mediaIds = emptyList(), - mediaUris = emptyList(), - mediaDescriptions = emptyList(), - scheduledAt = null, - inReplyToId = citedStatusId, - poll = null, - replyingStatusContent = null, - replyingStatusAuthorUsername = null, - formattingSyntax = "", - preview = false, - accountId = account.id, - savedTootUid = -1, - draftId = -1, - idempotencyKey = randomAlphanumericString(16), - retries = 0 - ) - ) - } else { - SendTootService.sendMessageIntent(context, - MessageToSend(message.toString(), null, null, account.id, chatId!!, 0)) - } - - context.startService(sendIntent) - - val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier) - .setSmallIcon(R.drawable.ic_notify) - .setColor(ContextCompat.getColor(context, (R.color.tusky_blue))) - .setGroup(senderFullName) - .setDefaults(0) // So it doesn't ring twice, notify only in Target callback - - builder.setContentTitle(context.getString(R.string.status_sent)) - builder.setContentText(context.getString(R.string.status_sent_long)) - - builder.setSubText(senderFullName) - builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - builder.setCategory(NotificationCompat.CATEGORY_SOCIAL) - builder.setOnlyAlertOnce(true) - - notificationManager.notify(notificationId, builder.build()) } } @@ -163,5 +159,4 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() { return remoteInput.getCharSequence(NotificationHelper.KEY_REPLY, "") } - } diff --git a/husky/build.gradle b/husky/build.gradle deleted file mode 100644 index af233cd..0000000 --- a/husky/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -buildscript { - ext.kotlin_version = '1.4.21' - repositories { - google() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.1.1' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - maven { - url "http://dl.bintray.com/piasy/maven" - } - maven { - url "https://jitpack.io" - } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/husky/build.gradle.kts b/husky/build.gradle.kts new file mode 100644 index 0000000..d560e92 --- /dev/null +++ b/husky/build.gradle.kts @@ -0,0 +1,44 @@ +import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask + +buildscript { + addRepos(repositories) + + dependencies { + // Base + classpath(GradlePlugins.android) + classpath(GradlePlugins.kotlin) + + // Plugins + classpath(GradlePlugins.gradleVersions) + } +} + +allprojects { + addRepos(repositories) + + tasks.withType { + options.encoding = DefaultConfig.encoding + options.compilerArgs.addAll( + listOf( + "-Xlint:all", + "-Xlint:unchecked", + "-Xlint:-deprecation" + ) + ) + } + + tasks.withType { + gradleReleaseChannel = "current" + + rejectVersionIf { + !isNonStable(candidate.version) + } + } +} + +tasks.register(BuildTasks.taskTypeClean) { + delete(rootProject.buildDir) + delete(project.buildDir) + delete(buildDir) + delete("${projectDir}/buildSrc/build") +} diff --git a/husky/buildSrc/build.gradle.kts b/husky/buildSrc/build.gradle.kts new file mode 100644 index 0000000..b6413e3 --- /dev/null +++ b/husky/buildSrc/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() +} diff --git a/husky/buildSrc/src/main/kotlin/AppLibs.kt b/husky/buildSrc/src/main/kotlin/AppLibs.kt new file mode 100644 index 0000000..9e66fd8 --- /dev/null +++ b/husky/buildSrc/src/main/kotlin/AppLibs.kt @@ -0,0 +1,118 @@ +object ApplicationLibs { + + private object Versions { + const val appcompat = "1.2.0" + const val constraintlayout = "2.1.0" + const val coreKtx = "1.3.2" + const val dagger = "2.30.1" + const val glide = "4.11.0" + const val lifecycle = "2.2.0" + const val materialDesign = "1.4.0" + const val materialDrawer = "8.2.0" + const val okhttpVersion = "4.9.0" + const val retrofit = "2.9.0" + const val room = "2.2.5" + const val simplestack = "2.6.2" + const val simplestackExt = "2.2.2" + const val timber = "4.7.1" + } + + object AndroidX { + const val appCompat = "androidx.appcompat:appcompat:${Versions.appcompat}" + const val browser = "androidx.browser:browser:1.3.0" + const val cardView = "androidx.cardview:cardview:1.0.0" + const val constraintLayout = + "androidx.constraintlayout:constraintlayout:${Versions.constraintlayout}" + const val coreKtx = "androidx.core:core-ktx:${Versions.coreKtx}" + const val exifInterface = "androidx.exifinterface:exifinterface:1.3.2" + const val emoji = "androidx.emoji:emoji:1.1.0" + const val emojiAppCompat = "androidx.emoji:emoji-appcompat:1.1.0" + const val emojiBundled = "androidx.emoji:emoji-bundled:1.1.0" + const val fragmentKtx = "androidx.fragment:fragment-ktx:1.2.5" + const val pagingRuntimeKtx = "androidx.paging:paging-runtime-ktx:2.1.2" + const val preferenceKtx = "androidx.preference:preference-ktx:1.1.1" + const val recyclerView = "androidx.recyclerview:recyclerview:1.1.0" + const val roomCompiler = "androidx.room:room-compiler:${Versions.room}" + const val roomRuntime = "androidx.room:room-runtime:${Versions.room}" + const val roomRxJava = "androidx.room:room-rxjava2:${Versions.room}" + const val shareTarget = "androidx.sharetarget:sharetarget:1.0.0" + const val swipeRefreshLayout = "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" + const val viewpager2 = "androidx.viewpager2:viewpager2:1.0.0" + const val workRuntime = "androidx.work:work-runtime:2.4.0" + + object Lifecycle { + const val liveDataKtx = + "androidx.lifecycle:lifecycle-livedata-ktx:${Versions.lifecycle}" + const val reactiveStreamsKtx = + "androidx.lifecycle:lifecycle-reactivestreams-ktx:${Versions.lifecycle}" + const val viewmodelKtx = + "androidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.lifecycle}" + } + } + + object Dagger { + const val dagger = "com.google.dagger:dagger:${Versions.dagger}" + const val daggerAndroid = "com.google.dagger:dagger-android:${Versions.dagger}" + const val daggerCompiler = "com.google.dagger:dagger-compiler:${Versions.dagger}" + const val daggerProcessor = "com.google.dagger:dagger-android-processor:${Versions.dagger}" + const val daggerSupport = "com.google.dagger:dagger-android-support:${Versions.dagger}" + } + + object Glide { + const val glide = "com.github.bumptech.glide:glide:${Versions.glide}" + const val glideCompiler = "com.github.bumptech.glide:compiler:${Versions.glide}" + const val glideOkhttp = "com.github.bumptech.glide:okhttp3-integration:${Versions.glide}" + } + + object Google { + const val flexBox = "com.google.android:flexbox:2.0.1" + const val materialDesign = "com.google.android.material:material:${Versions.materialDesign}" + } + + object Kotlin { + const val reflect = "org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}" + const val stdlib = "org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}" + const val stdlibJdk = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}" + } + + object RxJava { + const val rxAndroid = "io.reactivex.rxjava2:rxandroid:2.1.1" + const val rxJava = "io.reactivex.rxjava2:rxjava:2.2.20" + const val rxKotlin = "io.reactivex.rxjava2:rxkotlin:2.4.0" + } + + object SimpleStack { + const val lib = "com.github.Zhuinden:simple-stack:${Versions.simplestack}" + const val ext = "com.github.Zhuinden:simple-stack-extensions:${Versions.simplestackExt}" + } + + object Square { + const val retrofit = "com.squareup.retrofit2:retrofit:${Versions.retrofit}" + const val retrofitAdapterRxJ2 = + "com.squareup.retrofit2:adapter-rxjava2:${Versions.retrofit}" + const val retrofitConvGson = "com.squareup.retrofit2:converter-gson:${Versions.retrofit}" + + const val logginInterceptor = + "com.squareup.okhttp3:logging-interceptor:${Versions.okhttpVersion}" + const val okhttp = "com.squareup.okhttp3:okhttp:${Versions.okhttpVersion}" + const val okhttpBrotli = "com.squareup.okhttp3:okhttp-brotli:${Versions.okhttpVersion}" + } + + const val androidImageCropper = "com.theartofdev.edmodo:android-image-cropper:2.8.0" + const val autodispose = "com.uber.autodispose:autodispose:1.4.0" + const val autodisposeAndroidArchComp = + "com.uber.autodispose:autodispose-android-archcomponents:1.4.0" + const val bigImageViewer = "com.github.piasy:BigImageViewer:1.7.0" + const val conscryptAndroid = "org.conscrypt:conscrypt-android:2.5.1" + const val filemojiCompat = "de.c1710:filemojicompat:1.0.17" + const val glideImage = "com.github.piasy:GlideImageLoader:1.8.0" + const val glideImageViewFactory = "com.github.piasy:GlideImageViewFactory:1.8.0" + const val markdownEdit = "com.github.Tunous:MarkdownEdit:1.0.0" + const val materialDrawer = "com.mikepenz:materialdrawer:${Versions.materialDrawer}" + const val materialDrawerIconics = + "com.mikepenz:materialdrawer-iconics:${Versions.materialDrawer}" + const val materialDrawerTypeface = + "com.mikepenz:google-material-typeface:3.0.1.4.original-kotlin@aar" + const val sparkButton = "com.github.connyduck:sparkbutton:4.1.0" + const val timber = "com.jakewharton.timber:timber:${Versions.timber}" +} diff --git a/husky/buildSrc/src/main/kotlin/Dependencies.kt b/husky/buildSrc/src/main/kotlin/Dependencies.kt new file mode 100644 index 0000000..4bc52a3 --- /dev/null +++ b/husky/buildSrc/src/main/kotlin/Dependencies.kt @@ -0,0 +1,72 @@ +import java.util.Locale +import org.gradle.api.JavaVersion +import org.gradle.api.artifacts.dsl.RepositoryHandler +import org.gradle.kotlin.dsl.maven + +const val kotlinVersion = "1.4.21" + +object AndroidSDK { + const val compileSdk = 30 + const val buildTools = "30.0.3" +} + +object CustomHuskyBuild { + const val applicationName = "Husky" + const val customLogo = "" + const val customInstance = "" + const val supportAccountUrl = "https://huskyapp.dev/users/husky" +} + +object DefaultConfig { + const val applicationID = "su.xash.husky" + const val minSdk = 23 + const val targetSdk = 30 + const val versionCodeRel = 168 + const val versionNameRel = "1.0.1" + + val javaVersion = JavaVersion.VERSION_1_8 + + const val instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + const val encoding = "UTF-8" +} + +object BuildTypes { + const val debug = "debug" + const val release = "release" +} + +object ProguardFile { + const val defaultFile = "proguard-android-optimize.txt" + const val defaultRules = "proguard-rules.pro" +} + +object BuildTasks { + const val taskTypeClean = "clean" +} + +object GradlePlugins { + object Versions { + const val gradle = "7.0.1" + const val gradleVersions = "0.38.0" + } + + const val android = "com.android.tools.build:gradle:${Versions.gradle}" + const val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}" + const val gradleVersions = + "com.github.ben-manes:gradle-versions-plugin:${Versions.gradleVersions}" +} + +// Function to add repositories to the project. +fun addRepos(handler: RepositoryHandler) { + handler.google() + handler.maven(url = "https://jitpack.io") + handler.gradlePluginPortal() +} + +// Function to check stable versions +fun isNonStable(version: String): Boolean { + val stableKeyword = listOf("alpha", "beta", "final", "ga", "m", "release", "rc") + .any { version.toLowerCase(Locale.ROOT).contains(it) } + return stableKeyword.not() +} diff --git a/husky/buildSrc/src/main/kotlin/TestLibs.kt b/husky/buildSrc/src/main/kotlin/TestLibs.kt new file mode 100644 index 0000000..b3d076b --- /dev/null +++ b/husky/buildSrc/src/main/kotlin/TestLibs.kt @@ -0,0 +1,20 @@ +object TestLibs { + + private object Versions { + const val espresso = "3.4.0" + const val extJunit = "1.1.3" + const val junit = "4.13.2" + const val mockitoInline = "3.6.28" + const val mockitoKotlin = "2.2.0" + const val roboelectric = "4.4" + const val roomTesting = "2.2.5" + } + + const val extJunit = "androidx.test.ext:junit:${Versions.extJunit}" + const val espresso = "androidx.test.espresso:espresso-core:${Versions.espresso}" + const val junit = "junit:junit:${Versions.junit}" + const val mockitoInline = "org.mockito:mockito-inline:${Versions.mockitoInline}" + const val mockitoKotlin = "com.nhaarman.mockitokotlin2:mockito-kotlin:${Versions.mockitoKotlin}" + const val roboelectric = "org.robolectric:robolectric:${Versions.roboelectric}" + const val roomTesting = "androidx.room:room-testing:${Versions.roomTesting}" +} diff --git a/husky/gradle.properties b/husky/gradle.properties index 73d75e8..f2d407c 100644 --- a/husky/gradle.properties +++ b/husky/gradle.properties @@ -1,14 +1,19 @@ # Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. +# Put 4GiB of memory for Gradle org.gradle.jvmargs = -Xmx4096m -# use parallel execution +# Parallel execution org.gradle.parallel = true -android.enableR8.fullMode = true +# Use AndroidX libraries android.useAndroidX = true +# Disable incremental annotations kapt.incremental.apt = false +# Change console to verbose +org.gradle.console = verbose +# Enable log (info) +org.gradle.logging.level = info +# Enable warning mode +org.gradle.warning.mode = all +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier = true +# Kotlin code style for this project: "official" or "obsolete" +kotlin.code.style = official diff --git a/husky/gradle/wrapper/gradle-wrapper.properties b/husky/gradle/wrapper/gradle-wrapper.properties index 33682bb..772d354 100644 --- a/husky/gradle/wrapper/gradle-wrapper.properties +++ b/husky/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/husky/instance-build.gradle b/husky/instance-build.gradle deleted file mode 100644 index 8465a3b..0000000 --- a/husky/instance-build.gradle +++ /dev/null @@ -1,19 +0,0 @@ -/** -Edit this file to create a Tusky build that is customized for your Fediverse instance. -Note: Publishing a custom build on Google Play may violate the Google Play developer policy (Repetetive Content) - */ - -// The app name -ext.APP_NAME = "Husky" - -// The application id. Must be unique, e.g. based on your domain -ext.APP_ID = "su.xash.husky" - -// url of a custom app logo. Recommended size at least 600x600. Keep empty to use the Tusky elephant friend. -ext.CUSTOM_LOGO_URL = "" - -// e.g. mastodon.social. Keep empty to not suggest any instance on the signup screen -ext.CUSTOM_INSTANCE = "" - -// link to your support account. Will be linked on the about page when not empty. -ext.SUPPORT_ACCOUNT_URL = "https://huskyapp.dev/users/husky" diff --git a/husky/settings.gradle b/husky/settings.gradle.kts similarity index 63% rename from husky/settings.gradle rename to husky/settings.gradle.kts index d66f4ee..84b6943 100644 --- a/husky/settings.gradle +++ b/husky/settings.gradle.kts @@ -1,3 +1,3 @@ rootProject.name = "husky" -include ":app" +include(":app")