diff --git a/app/build.gradle b/app/build.gradle index 00a6b60..075282a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -61,6 +61,7 @@ dependencies { testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + implementation "androidx.datastore:datastore-preferences:1.0.0" // Hilt implementation "com.google.dagger:hilt-android:2.47" @@ -131,5 +132,5 @@ dependencies { implementation(platform("com.google.firebase:firebase-bom:32.7.1")) implementation("com.google.firebase:firebase-crashlytics") implementation("com.google.firebase:firebase-analytics") - + implementation("com.google.firebase:firebase-messaging-ktx") } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3cb5cfd..9b52dfa 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,9 +1,10 @@ - + + + + + + + + + - + + \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/MyApplication.kt b/app/src/main/java/com/isolaatti/MyApplication.kt index dac6db3..6ec689a 100644 --- a/app/src/main/java/com/isolaatti/MyApplication.kt +++ b/app/src/main/java/com/isolaatti/MyApplication.kt @@ -1,10 +1,16 @@ package com.isolaatti import android.app.Application +import android.content.Context import android.net.ConnectivityManager +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.preferencesDataStore import com.isolaatti.connectivity.ConnectivityCallbackImpl import dagger.hilt.android.HiltAndroidApp +val Context.dataStore: DataStore by preferencesDataStore(name = "settings") + @HiltAndroidApp class MyApplication : Application() { diff --git a/app/src/main/java/com/isolaatti/home/HomeActivity.kt b/app/src/main/java/com/isolaatti/home/HomeActivity.kt index 749bdcd..dd593be 100644 --- a/app/src/main/java/com/isolaatti/home/HomeActivity.kt +++ b/app/src/main/java/com/isolaatti/home/HomeActivity.kt @@ -1,14 +1,21 @@ package com.isolaatti.home +import android.Manifest +import android.content.SharedPreferences +import android.content.pm.PackageManager +import android.os.Build import android.os.Bundle import android.view.Menu +import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels -import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.Observer +import androidx.core.content.ContextCompat +import androidx.datastore.preferences.core.edit import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.setupWithNavController +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.isolaatti.R import com.isolaatti.common.IsolaattiBaseActivity +import com.isolaatti.dataStore import com.isolaatti.databinding.ActivityHomeBinding import com.isolaatti.home.presentation.FeedViewModel @@ -16,6 +23,18 @@ class HomeActivity : IsolaattiBaseActivity() { private lateinit var viewBinding: ActivityHomeBinding private val feedViewModel: FeedViewModel by viewModels() + private val requestPermissionLauncher = registerForActivityResult( + ActivityResultContracts.RequestPermission(), + ) { isGranted: Boolean -> + if (!isGranted) { + MaterialAlertDialogBuilder(this) + .setTitle(R.string.push_notifications_dialog_title) + .setMessage(R.string.push_notifications_dialog_rejected_message) + .show() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewBinding = ActivityHomeBinding.inflate(layoutInflater) @@ -24,6 +43,8 @@ class HomeActivity : IsolaattiBaseActivity() { viewBinding.bottomNavigation?.setupWithNavController(navHostFragment.navController) viewBinding.navigationRail?.setupWithNavController(navHostFragment.navController) + askNotificationPermission() + if(savedInstanceState == null) { feedViewModel.getFeed(false) } @@ -34,7 +55,28 @@ class HomeActivity : IsolaattiBaseActivity() { return super.onCreateOptionsMenu(menu) } - override fun onDestroy() { - super.onDestroy() + private fun askNotificationPermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == + PackageManager.PERMISSION_GRANTED + ) { + + } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) { + MaterialAlertDialogBuilder(this) + .setTitle(R.string.push_notifications_dialog_title) + .setMessage(R.string.push_notifications_dialog_message) + .setPositiveButton(R.string.accept) { _, _ -> + requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) + } + .setNegativeButton(R.string.no, null) + .show() + } else { + // Directly ask for the permission + requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) + } + } else { + + } } + } \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/notifications/data/NotificationsApi.kt b/app/src/main/java/com/isolaatti/home/notifications/data/NotificationsApi.kt new file mode 100644 index 0000000..7c9c1b0 --- /dev/null +++ b/app/src/main/java/com/isolaatti/home/notifications/data/NotificationsApi.kt @@ -0,0 +1,10 @@ +package com.isolaatti.home.notifications.data + +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Query + +interface NotificationsApi { + @GET("/api/Notifications/list") + fun getNotifications(@Query("after") after: Long?): Call +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/notifications/data/NotificationsDto.kt b/app/src/main/java/com/isolaatti/home/notifications/data/NotificationsDto.kt new file mode 100644 index 0000000..62aa82e --- /dev/null +++ b/app/src/main/java/com/isolaatti/home/notifications/data/NotificationsDto.kt @@ -0,0 +1,22 @@ +package com.isolaatti.home.notifications.data + +import java.time.ZonedDateTime + +data class NotificationsDto( + val result: List +) + +data class NotificationDto( + val id: Long, + val date: ZonedDateTime, + val userId: Int, + val read: Boolean, + val payload: NotificationPayload +) + +data class NotificationPayload( + val type: String, + val authorId: Int, + val authorName: String?, + val intentData: String? +) diff --git a/app/src/main/java/com/isolaatti/push_notifications/FcmService.kt b/app/src/main/java/com/isolaatti/push_notifications/FcmService.kt new file mode 100644 index 0000000..5702a40 --- /dev/null +++ b/app/src/main/java/com/isolaatti/push_notifications/FcmService.kt @@ -0,0 +1,25 @@ +package com.isolaatti.push_notifications + +import android.Manifest +import android.util.Log +import androidx.core.content.ContextCompat +import com.google.firebase.messaging.FirebaseMessagingService +import dagger.hilt.EntryPoint +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject + +@AndroidEntryPoint +class FcmService : FirebaseMessagingService() { + companion object { + const val LOG_TAG = "FcmService" + } + + @Inject + lateinit var pushNotificationsApi: PushNotificationsApi + + override fun onNewToken(token: String) { + + pushNotificationsApi.registerDevice(token) + Log.d(LOG_TAG, token) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/push_notifications/Module.kt b/app/src/main/java/com/isolaatti/push_notifications/Module.kt new file mode 100644 index 0000000..253a001 --- /dev/null +++ b/app/src/main/java/com/isolaatti/push_notifications/Module.kt @@ -0,0 +1,16 @@ +package com.isolaatti.push_notifications + +import com.isolaatti.connectivity.RetrofitClient +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +class Module { + @Provides + fun providePushNotificationsApi(retrofitClient: RetrofitClient): PushNotificationsApi { + return retrofitClient.client.create(PushNotificationsApi::class.java) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/push_notifications/PushNotificationsApi.kt b/app/src/main/java/com/isolaatti/push_notifications/PushNotificationsApi.kt new file mode 100644 index 0000000..26e2430 --- /dev/null +++ b/app/src/main/java/com/isolaatti/push_notifications/PushNotificationsApi.kt @@ -0,0 +1,14 @@ +package com.isolaatti.push_notifications + +import retrofit2.Call +import retrofit2.http.Multipart +import retrofit2.http.PUT +import retrofit2.http.Part + +interface PushNotificationsApi { + + @PUT("/api/push_notifications/register_device") + @Multipart + fun registerDevice(@Part("token") token: String): Call + +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_push_notifications.xml b/app/src/main/res/layout/dialog_push_notifications.xml new file mode 100644 index 0000000..77d9ef6 --- /dev/null +++ b/app/src/main/res/layout/dialog_push_notifications.xml @@ -0,0 +1,6 @@ + + + + \ 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 d5d7b73..f1a75a8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -186,4 +186,7 @@ Select audio Do you really want to remove this audio? Discussions with this audio linked will still be pointing to it. Remove audio? + Push notifications + Receive notifications to stay informed about your profile activity + You won\'t receive notifications. You can change this on your device settings. \ No newline at end of file