diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 99bc18c..6b00b7c 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -64,32 +64,35 @@ dependencies {
implementation("com.google.android.play:app-update-ktx:2.0.1")
- implementation(platform("com.google.firebase:firebase-bom:32.4.1"))
+ implementation(platform("com.google.firebase:firebase-bom:32.5.0"))
+ implementation("com.google.firebase:firebase-config")
implementation("com.google.firebase:firebase-analytics")
implementation("com.google.firebase:firebase-crashlytics")
- implementation("com.google.firebase:firebase-analytics")
+ implementation("com.google.firebase:firebase-inappmessaging-display")
+ implementation("com.google.firebase:firebase-config-ktx")
+ implementation("com.google.firebase:firebase-messaging-ktx")
implementation("com.google.android.gms:play-services-tagmanager:18.0.4")
+ implementation("com.google.android.gms:play-services-measurement-api:21.4.0")
implementation("com.github.ianatha.termux:termux-shared:feat-non-proc-terms-SNAPSHOT")
implementation("com.github.ianatha.termux:terminal-view:feat-non-proc-terms-SNAPSHOT")
- implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation(platform("io.github.Rosemoe.sora-editor:bom:0.22.1"))
implementation("io.github.Rosemoe.sora-editor:editor")
implementation("io.github.Rosemoe.sora-editor:language-java")
implementation("io.github.Rosemoe.sora-editor:language-textmate")
implementation("androidx.appcompat:appcompat:1.6.1")
- implementation("com.google.android.material:material:1.9.0")
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
implementation("androidx.activity:activity-compose:1.8.0")
+
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
- implementation("com.google.android.gms:play-services-measurement-api:21.4.0")
+ implementation("com.google.android.material:material:1.10.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3db0d70..d13043b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,14 +2,20 @@
-
-
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -61,5 +75,4 @@
-
\ No newline at end of file
diff --git a/app/src/main/java/io/atha/bababasic/ActivityAbout.kt b/app/src/main/java/io/atha/bababasic/ActivityAbout.kt
index 1d777b1..ee0effe 100644
--- a/app/src/main/java/io/atha/bababasic/ActivityAbout.kt
+++ b/app/src/main/java/io/atha/bababasic/ActivityAbout.kt
@@ -7,7 +7,7 @@ import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import io.atha.bababasic.databinding.ActivityAboutBinding
-class ActivityAbout : AppCompatActivity() {
+class ActivityAbout : BabaActivity() {
private lateinit var binding: ActivityAboutBinding
override fun onCreate(savedInstanceState: Bundle?) {
@@ -27,5 +27,7 @@ class ActivityAbout : AppCompatActivity() {
intent.data = Uri.parse("https://github.com/ianatha/bababasic")
startActivity(intent)
}
+
+ initFirebase()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/io/atha/bababasic/ActivityMain.kt b/app/src/main/java/io/atha/bababasic/ActivityMain.kt
index 692dafc..0d8fa9a 100644
--- a/app/src/main/java/io/atha/bababasic/ActivityMain.kt
+++ b/app/src/main/java/io/atha/bababasic/ActivityMain.kt
@@ -8,7 +8,6 @@ import android.content.res.Configuration
import android.graphics.Typeface
import android.net.Uri
import android.os.Bundle
-import android.provider.Settings
import android.text.Editable
import android.text.TextWatcher
import android.view.KeyEvent
@@ -17,13 +16,6 @@ import android.view.MenuItem
import android.view.View
import android.widget.PopupMenu
import android.widget.Toast
-import androidx.appcompat.app.AppCompatActivity
-import com.google.android.play.core.appupdate.AppUpdateManagerFactory
-import com.google.android.play.core.install.model.AppUpdateType
-import com.google.android.play.core.install.model.UpdateAvailability
-import com.google.firebase.analytics.FirebaseAnalytics
-import com.google.firebase.analytics.ktx.analytics
-import com.google.firebase.ktx.Firebase
import io.atha.bababasic.databinding.ActivityMainBinding
import io.atha.bababasic.editor.switchThemeIfRequired
import io.atha.libbababasic.Interpreter.checkSyntax
@@ -51,9 +43,6 @@ import io.github.rosemoe.sora.widget.component.EditorAutoCompletion
import io.github.rosemoe.sora.widget.component.Magnifier
import io.github.rosemoe.sora.widget.getComponent
import io.github.rosemoe.sora.widget.subscribeEvent
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import org.eclipse.tm4e.core.registry.IThemeSource
import java.io.BufferedReader
import java.io.IOException
@@ -62,49 +51,17 @@ import java.io.OutputStream
import java.util.regex.PatternSyntaxException
import java.util.stream.Collectors
-
-class ActivityMain : AppCompatActivity() {
- lateinit var firebaseAnalytics: FirebaseAnalytics
+class ActivityMain : BabaActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- firebaseAnalytics = Firebase.analytics
- CrashHandler.INSTANCE.init(this)
+
binding = ActivityMainBinding.inflate(layoutInflater)
prepareView()
setContentView(binding.root)
- val testLabSetting = Settings.System.getString(contentResolver, "firebase.test.lab")
- if ("true" == testLabSetting) {
- val bundle = Bundle().apply {
- putString("traffic_type", "testlab")
- }
- Firebase.analytics.setDefaultEventParameters(bundle)
- }
-
- checkForUpdates()
- }
-
- private fun checkForUpdates() {
- val context = this
- CoroutineScope(Dispatchers.Main).launch {
- val appUpdateManager = AppUpdateManagerFactory.create(context)
- val appUpdateInfoTask = appUpdateManager.appUpdateInfo
-
- appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
- if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
- && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
- ) {
- appUpdateManager.startUpdateFlowForResult(
- appUpdateInfo,
- AppUpdateType.IMMEDIATE,
- context,
- 1011
- )
- }
- }
- }
+ initFirebase()
}
private var searchOptions = SearchOptions(false, false)
diff --git a/app/src/main/java/io/atha/bababasic/ActivityRun.kt b/app/src/main/java/io/atha/bababasic/ActivityRun.kt
index 3b69c0d..3a2c723 100644
--- a/app/src/main/java/io/atha/bababasic/ActivityRun.kt
+++ b/app/src/main/java/io/atha/bababasic/ActivityRun.kt
@@ -18,7 +18,7 @@ data class RunDatum(
val src: String,
) : Serializable
-class ActivityRun : AppCompatActivity() {
+class ActivityRun : BabaActivity() {
private lateinit var viewClient: TermuxTerminalViewClient
private lateinit var mPreferences: AppSharedPreferences
lateinit var binding: ActivityRunBinding
@@ -144,6 +144,7 @@ class ActivityRun : AppCompatActivity() {
session.initializeEmulator(1, 1)
setContentView(binding.root)
viewClient.onCreate()
+ initFirebase()
}
fun getTerminalView(): TerminalView = binding.terminal
diff --git a/app/src/main/java/io/atha/bababasic/BabaActivity.kt b/app/src/main/java/io/atha/bababasic/BabaActivity.kt
new file mode 100644
index 0000000..ccdc9ec
--- /dev/null
+++ b/app/src/main/java/io/atha/bababasic/BabaActivity.kt
@@ -0,0 +1,145 @@
+package io.atha.bababasic
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.os.Bundle
+import android.provider.Settings
+import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
+import android.util.Log
+import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.gms.tasks.OnCompleteListener
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.android.play.core.appupdate.AppUpdateManagerFactory
+import com.google.android.play.core.install.model.AppUpdateType
+import com.google.android.play.core.install.model.UpdateAvailability
+import com.google.firebase.analytics.FirebaseAnalytics
+import com.google.firebase.analytics.ktx.analytics
+import com.google.firebase.inappmessaging.ktx.inAppMessaging
+import com.google.firebase.ktx.Firebase
+import com.google.firebase.messaging.FirebaseMessaging
+import com.google.firebase.remoteconfig.FirebaseRemoteConfig
+import com.google.firebase.remoteconfig.ktx.remoteConfig
+import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+abstract class BabaActivity : AppCompatActivity() {
+ lateinit var firebaseAnalytics: FirebaseAnalytics
+
+ protected fun initFirebase() {
+ firebaseAnalytics = Firebase.analytics
+ CrashHandler.INSTANCE.init(this)
+ val remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig
+ val configSettings = remoteConfigSettings {
+ minimumFetchIntervalInSeconds = 3600
+ }
+ remoteConfig.setConfigSettingsAsync(configSettings)
+ remoteConfig.setDefaultsAsync(mapOf(
+ "feature_docs" to "0"
+ ))
+
+ Firebase.inAppMessaging.addClickListener { inAppMessage, action ->
+ Log.i("inapp", "clicked ${inAppMessage} ${action}")
+ }
+
+ val testLabSetting = Settings.System.getString(contentResolver, "firebase.test.lab")
+ if ("true" == testLabSetting) {
+ val bundle = Bundle().apply {
+ putString("traffic_type", "testlab")
+ }
+ Firebase.analytics.setDefaultEventParameters(bundle)
+ }
+
+ FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
+ if (!task.isSuccessful) {
+ Log.w("fcm", "Fetching FCM registration token failed", task.exception)
+ return@OnCompleteListener
+ }
+
+ // Get new FCM registration token
+ val token = task.result
+
+ // Log and toast
+ Log.d("fcm", token)
+ })
+
+ if (Build.VERSION.SDK_INT >= 33) {
+// notificationPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS)
+ } else {
+ hasNotificationPermissionGranted = true
+ }
+ }
+
+ private fun showSettingDialog() {
+ MaterialAlertDialogBuilder(this, com.google.android.material.R.style.MaterialAlertDialog_Material3)
+ .setTitle("Notification Permission")
+ .setMessage("Notification permission is required, Please allow notification permission from setting")
+ .setPositiveButton("Ok") { _, _ ->
+ val intent = Intent(ACTION_APPLICATION_DETAILS_SETTINGS)
+ intent.data = Uri.parse("package:$packageName")
+ startActivity(intent)
+ }
+ .setNegativeButton("Cancel", null)
+ .show()
+ }
+
+ private fun showNotificationPermissionRationale() {
+ MaterialAlertDialogBuilder(this, com.google.android.material.R.style.MaterialAlertDialog_Material3)
+ .setTitle("Alert")
+ .setMessage("Notification permission is required, to show notification")
+ .setPositiveButton("Ok") { _, _ ->
+ if (Build.VERSION.SDK_INT >= 33) {
+ notificationPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS)
+ }
+ }
+ .setNegativeButton("Cancel", null)
+ .show()
+ }
+
+ var hasNotificationPermissionGranted = false
+
+ private val notificationPermissionLauncher =
+ this.registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
+ hasNotificationPermissionGranted = isGranted
+ if (!isGranted) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (Build.VERSION.SDK_INT >= 33) {
+ if (shouldShowRequestPermissionRationale(android.Manifest.permission.POST_NOTIFICATIONS)) {
+ showNotificationPermissionRationale()
+ } else {
+ showSettingDialog()
+ }
+ }
+ }
+ } else {
+ Toast.makeText(applicationContext, "notification permission granted", Toast.LENGTH_SHORT)
+ .show()
+ }
+ }
+
+
+ private fun checkForUpdates() {
+ val context = this
+ CoroutineScope(Dispatchers.Main).launch {
+ val appUpdateManager = AppUpdateManagerFactory.create(context)
+ val appUpdateInfoTask = appUpdateManager.appUpdateInfo
+
+ appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
+ if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
+ && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
+ ) {
+ appUpdateManager.startUpdateFlowForResult(
+ appUpdateInfo,
+ AppUpdateType.IMMEDIATE,
+ context,
+ 1011
+ )
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/atha/bababasic/MyFirebaseMessagingService.kt b/app/src/main/java/io/atha/bababasic/MyFirebaseMessagingService.kt
new file mode 100644
index 0000000..2adbadc
--- /dev/null
+++ b/app/src/main/java/io/atha/bababasic/MyFirebaseMessagingService.kt
@@ -0,0 +1,69 @@
+package io.atha.bababasic
+
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.media.RingtoneManager
+import android.os.Build
+import android.util.Log
+import androidx.core.app.NotificationCompat
+import com.google.firebase.messaging.FirebaseMessagingService
+import com.google.firebase.messaging.RemoteMessage
+
+class MyFirebaseMessagingService : FirebaseMessagingService() {
+ override fun onMessageReceived(remoteMessage: RemoteMessage) {
+ remoteMessage.notification?.let {
+ it.body?.let { body -> sendNotification(body) }
+ }
+ }
+
+ override fun onNewToken(token: String) {
+ sendRegistrationToServer(token)
+ }
+
+ private fun sendRegistrationToServer(token: String?) {
+ Log.d(TAG, "FCM registrationToken = $token")
+ }
+
+ private fun sendNotification(messageBody: String) {
+ val requestCode = 0
+ val intent = Intent(this, ActivityMain::class.java)
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ val pendingIntent = PendingIntent.getActivity(
+ this,
+ requestCode,
+ intent,
+ PendingIntent.FLAG_IMMUTABLE,
+ )
+
+ val channelId = getString(R.string.default_notification_channel_id)
+ val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
+ val notificationBuilder = NotificationCompat.Builder(this, channelId)
+ .setSmallIcon(R.drawable.ic_launcher_foreground)
+ .setContentTitle(getString(R.string.fcm_message))
+ .setContentText(messageBody)
+ .setAutoCancel(true)
+ .setSound(defaultSoundUri)
+ .setContentIntent(pendingIntent)
+
+ val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val channel = NotificationChannel(
+ channelId,
+ "Channel human readable title",
+ NotificationManager.IMPORTANCE_DEFAULT,
+ )
+ notificationManager.createNotificationChannel(channel)
+ }
+
+ val notificationId = 29330
+ notificationManager.notify(notificationId, notificationBuilder.build())
+ }
+
+ companion object {
+ private const val TAG = "MyFirebaseMsgService"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6e976d8..188f5a8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,4 +1,8 @@
+ fcm_default_channel
+ Weather
+ FCM Message
+
Last
Next
Replace