diff --git a/.gitignore b/.gitignore
index d7d6aa00..ec851b00 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,22 +1,10 @@
-start/.gradle/5.1.1/gc.properties
-start/.gradle/5.1.1/executionHistory/executionHistory.bin
-start/.gradle/5.1.1/executionHistory/executionHistory.lock
-start/.gradle/5.1.1/fileChanges/last-build.bin
-start/.gradle/5.1.1/fileHashes/fileHashes.bin
-start/.gradle/5.1.1/fileHashes/fileHashes.lock
-start/.gradle/5.4.1/gc.properties
-start/.gradle/5.4.1/executionHistory/executionHistory.bin
-start/.gradle/5.4.1/executionHistory/executionHistory.lock
-start/.gradle/5.4.1/fileChanges/last-build.bin
-start/.gradle/5.4.1/fileContent/fileContent.lock
-start/.gradle/5.4.1/fileHashes/fileHashes.bin
-start/.gradle/5.4.1/fileHashes/fileHashes.lock
-start/.gradle/5.4.1/fileHashes/resourceHashesCache.bin
-start/.gradle/5.4.1/javaCompile/classAnalysis.bin
-start/.gradle/5.4.1/javaCompile/jarAnalysis.bin
-start/.gradle/5.4.1/javaCompile/javaCompile.lock
-start/.gradle/5.4.1/javaCompile/taskHistory.bin
-start/.gradle/buildOutputCleanup/buildOutputCleanup.lock
-start/.gradle/buildOutputCleanup/cache.properties
-start/.gradle/buildOutputCleanup/outputFiles.bin
-start/.gradle/vcs-1/gc.properties
+*.iml
+.gradle
+/local.properties
+/.idea
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties/
diff --git a/app/build.gradle b/app/build.gradle
index 5ca4e427..508dfc59 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -17,11 +17,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
+apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 30
defaultConfig {
- applicationId "com.example.android.eggtimernotifications"
+ applicationId "dev.filipebezerra.android.eggtimernotifications"
minSdkVersion 19
targetSdkVersion 30
versionCode 1
@@ -34,30 +35,46 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
-
- // Enables data binding.
buildFeatures {
dataBinding true
}
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_1_8
+ }
}
dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
+ // Kotlin support
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'androidx.core:core-ktx:1.3.1'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
- implementation 'androidx.legacy:legacy-support-v4:1.0.0'
- implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
- implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0-rc01'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test:runner:1.2.0'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ // AndroidX
+ implementation "androidx.appcompat:appcompat:1.2.0"
+ implementation "androidx.core:core-ktx:1.3.2"
+ implementation "androidx.fragment:fragment-ktx:$fragment_version"
+ implementation "androidx.constraintlayout:constraintlayout:2.0.4"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
+ implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
+ implementation "androidx.work:work-runtime-ktx:$work_version"
+
+ // Firebase
+ implementation platform("com.google.firebase:firebase-bom:26.2.0")
+ implementation "com.google.firebase:firebase-messaging-ktx:21.0.1"
+
+ // Testing
+ testImplementation "junit:junit:4.13.1"
+ androidTestImplementation "androidx.test:runner:1.3.0"
+ androidTestImplementation "androidx.test.espresso:espresso-core:3.3.0"
+ // optional - Test helpers for LiveData
+ testImplementation "androidx.arch.core:core-testing:$arch_version"
+ // Testing Fragments in Isolation
+ debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
+ // Test helpers
+ androidTestImplementation "androidx.work:work-testing:$work_version"
- //for fcm
- implementation 'com.google.firebase:firebase-core:17.0.0'
- implementation 'com.google.firebase:firebase-iid:19.0.1'
- implementation 'com.google.firebase:firebase-messaging:19.0.1'
- implementation 'android.arch.work:work-runtime:1.0.1'
+ // Third-party
+ implementation 'com.jakewharton.timber:timber:4.7.1'
}
diff --git a/app/google-services.json b/app/google-services.json
new file mode 100644
index 00000000..039152cd
--- /dev/null
+++ b/app/google-services.json
@@ -0,0 +1,47 @@
+{
+ "project_info": {
+ "project_number": "662070897175",
+ "project_id": "egg-timer-59de8",
+ "storage_bucket": "egg-timer-59de8.appspot.com"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:662070897175:android:3becb7029d5f23f260ca52",
+ "android_client_info": {
+ "package_name": "dev.filipebezerra.android.eggtimernotifications"
+ }
+ },
+ "oauth_client": [
+ {
+ "client_id": "662070897175-vnfjeoi2oguro0dbvt48ktvbfru7kt34.apps.googleusercontent.com",
+ "client_type": 1,
+ "android_info": {
+ "package_name": "dev.filipebezerra.android.eggtimernotifications",
+ "certificate_hash": "8c2424ba513d384fd4ec9f1dfa6099b0b36e677d"
+ }
+ },
+ {
+ "client_id": "662070897175-pd3g3r728ecgd20o2m3dil14br2k9kha.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ],
+ "api_key": [
+ {
+ "current_key": "AIzaSyBB6hjA-ebIWIonwu0quEzYLaZG3v_4CM8"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": [
+ {
+ "client_id": "662070897175-pd3g3r728ecgd20o2m3dil14br2k9kha.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 04993f0f..efa2bd40 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,50 +1,75 @@
-
-
+ package="dev.filipebezerra.android.eggtimernotifications"
+ >
+
+
-
-
+ android:theme="@style/AppTheme"
+ >
+
-
+
-
+
+
-
+ android:name="dev.filipebezerra.android.eggtimernotifications.receiver.AlarmReceiver"
+ android:enabled="true"
+ android:exported="false"
+ />
-
+ android:name="dev.filipebezerra.android.eggtimernotifications.receiver.SnoozeReceiver"
+ android:enabled="true"
+ android:exported="false"
+ />
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android/eggtimernotifications/ui/EggTimerFragment.kt b/app/src/main/java/com/example/android/eggtimernotifications/ui/EggTimerFragment.kt
deleted file mode 100644
index 0802dc0f..00000000
--- a/app/src/main/java/com/example/android/eggtimernotifications/ui/EggTimerFragment.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2019 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.eggtimernotifications.ui
-
-import android.app.NotificationChannel
-import android.app.NotificationManager
-import android.graphics.Color
-import android.os.Build
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.Toast
-import androidx.databinding.DataBindingUtil
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
-import com.example.android.eggtimernotifications.R
-import com.example.android.eggtimernotifications.databinding.FragmentEggTimerBinding
-import com.google.firebase.messaging.FirebaseMessaging
-
-class EggTimerFragment : Fragment() {
-
- private val TOPIC = "breakfast"
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
-
- val binding: FragmentEggTimerBinding = DataBindingUtil.inflate(
- inflater, R.layout.fragment_egg_timer, container, false
- )
-
- val viewModel = ViewModelProvider(this).get(EggTimerViewModel::class.java)
-
- binding.eggTimerViewModel = viewModel
- binding.lifecycleOwner = this.viewLifecycleOwner
-
- // TODO: Step 1.7 call create channel
-
- return binding.root
- }
-
- private fun createChannel(channelId: String, channelName: String) {
- // TODO: Step 1.6 START create a channel
-
- // TODO: Step 1.6 END create a channel
-
- }
-
- companion object {
- fun newInstance() = EggTimerFragment()
- }
-}
-
diff --git a/app/src/main/java/com/example/android/eggtimernotifications/util/NotificationUtils.kt b/app/src/main/java/com/example/android/eggtimernotifications/util/NotificationUtils.kt
deleted file mode 100644
index 2f9e2a2e..00000000
--- a/app/src/main/java/com/example/android/eggtimernotifications/util/NotificationUtils.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.eggtimernotifications.util
-
-import android.app.NotificationManager
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.graphics.BitmapFactory
-import androidx.core.app.NotificationCompat
-import com.example.android.eggtimernotifications.MainActivity
-import com.example.android.eggtimernotifications.R
-import com.example.android.eggtimernotifications.receiver.SnoozeReceiver
-
-// Notification ID.
-private val NOTIFICATION_ID = 0
-private val REQUEST_CODE = 0
-private val FLAGS = 0
-
-// TODO: Step 1.1 extension function to send messages (GIVEN)
-/**
- * Builds and delivers the notification.
- *
- * @param context, activity context.
- */
-fun NotificationManager.sendNotification(messageBody: String, applicationContext: Context) {
- // Create the content intent for the notification, which launches
- // this activity
- // TODO: Step 1.11 create intent
-
- // TODO: Step 1.12 create PendingIntent
-
- // TODO: Step 2.0 add style
-
- // TODO: Step 2.2 add snooze action
-
- // TODO: Step 1.2 get an instance of NotificationCompat.Builder
- // Build the notification
-
- // TODO: Step 1.8 use the new 'breakfast' notification channel
-
- // TODO: Step 1.3 set title, text and icon to builder
-
- // TODO: Step 1.13 set content intent
-
- // TODO: Step 2.1 add style to builder
-
- // TODO: Step 2.3 add snooze action
-
- // TODO: Step 2.5 set priority
-
- // TODO: Step 1.4 call notify
-
-}
-
-// TODO: Step 1.14 Cancel all notifications
diff --git a/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/EggTimerApplication.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/EggTimerApplication.kt
new file mode 100644
index 00000000..e4a4ff2b
--- /dev/null
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/EggTimerApplication.kt
@@ -0,0 +1,11 @@
+package dev.filipebezerra.android.eggtimernotifications
+
+import android.app.Application
+import timber.log.Timber
+
+class EggTimerApplication : Application() {
+ override fun onCreate() {
+ super.onCreate()
+ BuildConfig.DEBUG.takeIf { it }?.run { Timber.plant(Timber.DebugTree()) }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android/eggtimernotifications/MainActivity.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/MainActivity.kt
similarity index 84%
rename from app/src/main/java/com/example/android/eggtimernotifications/MainActivity.kt
rename to app/src/main/java/dev/filipebezerra/android/eggtimernotifications/MainActivity.kt
index 10621e1d..5dbd07ad 100644
--- a/app/src/main/java/com/example/android/eggtimernotifications/MainActivity.kt
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/MainActivity.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package com.example.android.eggtimernotifications
+package dev.filipebezerra.android.eggtimernotifications
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
-import com.example.android.eggtimernotifications.ui.EggTimerFragment
+import dev.filipebezerra.android.eggtimernotifications.R
+import dev.filipebezerra.android.eggtimernotifications.timer.EggTimerFragment
class MainActivity : AppCompatActivity() {
diff --git a/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/important/ImportantActivity.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/important/ImportantActivity.kt
new file mode 100644
index 00000000..226a884e
--- /dev/null
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/important/ImportantActivity.kt
@@ -0,0 +1,15 @@
+package dev.filipebezerra.android.eggtimernotifications.important
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.DataBindingUtil.setContentView
+import dev.filipebezerra.android.eggtimernotifications.R
+import dev.filipebezerra.android.eggtimernotifications.databinding.ImportantActivityBinding
+
+class ImportantActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(this, R.layout.important_activity)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android/eggtimernotifications/receiver/AlarmReceiver.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/receiver/AlarmReceiver.kt
similarity index 62%
rename from app/src/main/java/com/example/android/eggtimernotifications/receiver/AlarmReceiver.kt
rename to app/src/main/java/dev/filipebezerra/android/eggtimernotifications/receiver/AlarmReceiver.kt
index 7313457c..61caed86 100644
--- a/app/src/main/java/com/example/android/eggtimernotifications/receiver/AlarmReceiver.kt
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/receiver/AlarmReceiver.kt
@@ -14,25 +14,21 @@
* limitations under the License.
*/
-package com.example.android.eggtimernotifications.receiver
+package dev.filipebezerra.android.eggtimernotifications.receiver
-import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
-import android.widget.Toast
-import androidx.core.content.ContextCompat
-import com.example.android.eggtimernotifications.R
-import com.example.android.eggtimernotifications.util.sendNotification
+import dev.filipebezerra.android.eggtimernotifications.R
+import dev.filipebezerra.android.eggtimernotifications.util.getNotificationManager
+import dev.filipebezerra.android.eggtimernotifications.util.sendNotification
class AlarmReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
- // TODO: Step 1.10 [Optional] remove toast
- Toast.makeText(context, context.getText(R.string.eggs_ready), Toast.LENGTH_SHORT).show()
-
- // TODO: Step 1.9 add call to sendNotification
-
+ context.getNotificationManager().sendNotification(
+ context.getString(R.string.eggs_ready),
+ context
+ )
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/android/eggtimernotifications/receiver/SnoozeReceiver.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/receiver/SnoozeReceiver.kt
similarity index 83%
rename from app/src/main/java/com/example/android/eggtimernotifications/receiver/SnoozeReceiver.kt
rename to app/src/main/java/dev/filipebezerra/android/eggtimernotifications/receiver/SnoozeReceiver.kt
index ceea1381..d46883f4 100644
--- a/app/src/main/java/com/example/android/eggtimernotifications/receiver/SnoozeReceiver.kt
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/receiver/SnoozeReceiver.kt
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package com.example.android.eggtimernotifications.receiver
+package dev.filipebezerra.android.eggtimernotifications.receiver
import android.app.AlarmManager
-import android.app.NotificationManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
@@ -25,8 +24,10 @@ import android.content.Intent
import android.os.SystemClock
import android.text.format.DateUtils
import androidx.core.app.AlarmManagerCompat
-import androidx.core.content.ContextCompat
+import dev.filipebezerra.android.eggtimernotifications.util.cancelNotifications
+import dev.filipebezerra.android.eggtimernotifications.util.getNotificationManager
+// TODO: Improve it - Remove this DRY code
class SnoozeReceiver: BroadcastReceiver() {
private val REQUEST_CODE = 0
@@ -47,6 +48,8 @@ class SnoozeReceiver: BroadcastReceiver() {
triggerTime,
notifyPendingIntent
)
+
+ context.getNotificationManager().cancelNotifications()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/service/EggTimerFirebaseMessagingService.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/service/EggTimerFirebaseMessagingService.kt
new file mode 100644
index 00000000..a4892adc
--- /dev/null
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/service/EggTimerFirebaseMessagingService.kt
@@ -0,0 +1,26 @@
+package dev.filipebezerra.android.eggtimernotifications.service
+
+import com.google.firebase.messaging.FirebaseMessagingService
+import com.google.firebase.messaging.RemoteMessage
+import dev.filipebezerra.android.eggtimernotifications.util.getNotificationManager
+import dev.filipebezerra.android.eggtimernotifications.util.sendNotification
+import timber.log.Timber
+
+class EggTimerFirebaseMessagingService : FirebaseMessagingService() {
+ override fun onNewToken(newToken: String) {
+ Timber.i("Refreshed Firebase Token: $newToken")
+ }
+
+ override fun onMessageReceived(remoteMessage: RemoteMessage) {
+ with(remoteMessage) {
+ from?.run { Timber.d("Message received from $this") }
+ data.takeIf { it.isNotEmpty() }?.run {
+ Timber.d("Data received within the message $data")
+ }
+ notification?.body?.run { applicationContext.getNotificationManager().sendNotification(
+ this,
+ applicationContext
+ ) }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/timer/EggTimerFragment.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/timer/EggTimerFragment.kt
new file mode 100644
index 00000000..46c18d1e
--- /dev/null
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/timer/EggTimerFragment.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dev.filipebezerra.android.eggtimernotifications.timer
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import com.google.firebase.messaging.FirebaseMessaging
+import dev.filipebezerra.android.eggtimernotifications.R
+import dev.filipebezerra.android.eggtimernotifications.databinding.FragmentEggTimerBinding
+import dev.filipebezerra.android.eggtimernotifications.util.createChannel
+import dev.filipebezerra.android.eggtimernotifications.util.getNotificationManager
+import dev.filipebezerra.android.eggtimernotifications.util.subscribeToTopicBreakfast
+
+class EggTimerFragment : Fragment() {
+
+ private val viewModel: EggTimerViewModel by viewModels()
+
+ private val TOPIC = "breakfast"
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View = FragmentEggTimerBinding.inflate(inflater, container, false)
+ .apply {
+ eggTimerViewModel = viewModel
+ lifecycleOwner = viewLifecycleOwner
+ }
+ .root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ context?.run {
+ createEggTimerNotificationChannel()
+ createBreakfastNotificationChannel()
+ subscribeToTopicBreakfast()
+ }
+ }
+
+ private fun Context.createEggTimerNotificationChannel() =
+ getNotificationManager().createChannel(
+ getString(R.string.egg_notification_channel_id),
+ getString(R.string.egg_notification_channel_name),
+ getString(R.string.egg_notification_channel_description)
+ )
+
+ private fun Context.createBreakfastNotificationChannel() =
+ getNotificationManager().createChannel(
+ getString(R.string.breakfast_notification_channel_id),
+ getString(R.string.breakfast_notification_channel_name),
+ getString(R.string.breakfast_notification_channel_description)
+ )
+
+ private fun Context.subscribeToTopicBreakfast() =
+ FirebaseMessaging.getInstance().subscribeToTopicBreakfast(this)
+
+ companion object {
+ fun newInstance() = EggTimerFragment()
+ }
+}
+
diff --git a/app/src/main/java/com/example/android/eggtimernotifications/ui/EggTimerViewModel.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/timer/EggTimerViewModel.kt
similarity index 85%
rename from app/src/main/java/com/example/android/eggtimernotifications/ui/EggTimerViewModel.kt
rename to app/src/main/java/dev/filipebezerra/android/eggtimernotifications/timer/EggTimerViewModel.kt
index 934306f1..0e0b0486 100644
--- a/app/src/main/java/com/example/android/eggtimernotifications/ui/EggTimerViewModel.kt
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/timer/EggTimerViewModel.kt
@@ -14,20 +14,27 @@
* limitations under the License.
*/
-package com.example.android.eggtimernotifications.ui
+package dev.filipebezerra.android.eggtimernotifications.timer
-import android.app.*
+import android.app.AlarmManager
+import android.app.Application
+import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.CountDownTimer
import android.os.SystemClock
import androidx.core.app.AlarmManagerCompat
-import androidx.core.content.ContextCompat
-import androidx.lifecycle.*
-import com.example.android.eggtimernotifications.receiver.AlarmReceiver
-import com.example.android.eggtimernotifications.R
-import com.example.android.eggtimernotifications.util.sendNotification
-import kotlinx.coroutines.*
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import dev.filipebezerra.android.eggtimernotifications.R
+import dev.filipebezerra.android.eggtimernotifications.receiver.AlarmReceiver
+import dev.filipebezerra.android.eggtimernotifications.util.cancelNotifications
+import dev.filipebezerra.android.eggtimernotifications.util.getNotificationManager
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
class EggTimerViewModel(private val app: Application) : AndroidViewModel(app) {
@@ -57,7 +64,6 @@ class EggTimerViewModel(private val app: Application) : AndroidViewModel(app) {
val isAlarmOn: LiveData
get() = _alarmOn
-
private lateinit var timer: CountDownTimer
init {
@@ -68,6 +74,7 @@ class EggTimerViewModel(private val app: Application) : AndroidViewModel(app) {
PendingIntent.FLAG_NO_CREATE
) != null
+ // TODO: Improve it - Remove this DRY code
notifyPendingIntent = PendingIntent.getBroadcast(
getApplication(),
REQUEST_CODE,
@@ -118,9 +125,8 @@ class EggTimerViewModel(private val app: Application) : AndroidViewModel(app) {
}
val triggerTime = SystemClock.elapsedRealtime() + selectedInterval
- // TODO: Step 1.5 get an instance of NotificationManager and call sendNotification
-
- // TODO: Step 1.15 call cancel notification
+ // TODO: Improve it - Remove this DRY code
+ app.applicationContext.getNotificationManager().cancelNotifications()
AlarmManagerCompat.setExactAndAllowWhileIdle(
alarmManager,
diff --git a/app/src/main/java/com/example/android/eggtimernotifications/util/BindingUtils.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/BindingAdapters.kt
similarity index 94%
rename from app/src/main/java/com/example/android/eggtimernotifications/util/BindingUtils.kt
rename to app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/BindingAdapters.kt
index 28f2bafa..5ffca6d9 100644
--- a/app/src/main/java/com/example/android/eggtimernotifications/util/BindingUtils.kt
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/BindingAdapters.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.example.android.eggtimernotifications.util
+package dev.filipebezerra.android.eggtimernotifications.util
import android.text.format.DateUtils
import android.widget.TextView
diff --git a/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/ContextCompatExt.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/ContextCompatExt.kt
new file mode 100644
index 00000000..e2f90d6f
--- /dev/null
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/ContextCompatExt.kt
@@ -0,0 +1,10 @@
+package dev.filipebezerra.android.eggtimernotifications.util
+
+import android.app.NotificationManager
+import android.content.Context
+import androidx.core.content.ContextCompat.getSystemService
+
+fun Context.getNotificationManager(): NotificationManager = getSystemService(
+ this,
+ NotificationManager::class.java
+) as NotificationManager
\ No newline at end of file
diff --git a/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/FirebaseMessagingExt.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/FirebaseMessagingExt.kt
new file mode 100644
index 00000000..a7472c2a
--- /dev/null
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/FirebaseMessagingExt.kt
@@ -0,0 +1,19 @@
+package dev.filipebezerra.android.eggtimernotifications.util
+
+import android.content.Context
+import android.widget.Toast
+import com.google.firebase.messaging.FirebaseMessaging
+import dev.filipebezerra.android.eggtimernotifications.R
+
+private const val BREAKFAST_TOPIC = "breakfast"
+
+fun FirebaseMessaging.subscribeToTopicBreakfast(context: Context) {
+ subscribeToTopic(BREAKFAST_TOPIC)
+ .addOnCompleteListener {
+ val userFeedback = if (it.isSuccessful)
+ R.string.message_subscribed
+ else
+ R.string.message_subscribe_failed
+ Toast.makeText(context.applicationContext, userFeedback, Toast.LENGTH_SHORT).show();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/NotificationExt.kt b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/NotificationExt.kt
new file mode 100644
index 00000000..90e1773c
--- /dev/null
+++ b/app/src/main/java/dev/filipebezerra/android/eggtimernotifications/util/NotificationExt.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dev.filipebezerra.android.eggtimernotifications.util
+
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.os.Build
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import androidx.core.content.ContextCompat
+import dev.filipebezerra.android.eggtimernotifications.MainActivity
+import dev.filipebezerra.android.eggtimernotifications.R
+import dev.filipebezerra.android.eggtimernotifications.important.ImportantActivity
+import dev.filipebezerra.android.eggtimernotifications.receiver.SnoozeReceiver
+
+private val NOTIFICATION_ID = 0
+private val REQUEST_CODE = 0
+
+/**
+ * Builds and delivers the notification.
+ *
+ * @param context activity context.
+ */
+fun NotificationManager.sendNotification(
+ messageBody: String,
+ context: Context,
+) {
+ val contentIntent = Intent(context, MainActivity::class.java)
+ .apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK }
+ val contentPendingIntent = PendingIntent.getActivity(
+ context,
+ REQUEST_CODE,
+ contentIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ )
+
+ val snoozeIntent = Intent(context, SnoozeReceiver::class.java)
+ val snoozePendingIntent = PendingIntent.getBroadcast(
+ context,
+ REQUEST_CODE,
+ snoozeIntent,
+ PendingIntent.FLAG_ONE_SHOT
+ )
+
+ val eggImage = BitmapFactory.decodeResource(
+ context.resources,
+ R.drawable.cooked_egg
+ )
+
+ val style = NotificationCompat.BigPictureStyle()
+ .bigPicture(eggImage)
+ .bigLargeIcon(null)
+
+ val fullScreenIntent = Intent(context, ImportantActivity::class.java)
+ .apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK }
+ val fullScreenPedingIntent = PendingIntent.getActivity(
+ context,
+ REQUEST_CODE,
+ fullScreenIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ )
+
+ NotificationCompat.Builder(
+ context,
+ context.getString(R.string.egg_notification_channel_id)
+ )
+ .setSmallIcon(R.drawable.egg_icon)
+ .setContentTitle(context.getString(R.string.notification_title))
+ .setContentText(messageBody)
+ .setContentIntent(contentPendingIntent)
+ // auto dissmiss notification from status bar
+ .setAutoCancel(true)
+ // style notifications with Big Style containing a big image
+ .setStyle(style)
+ // use this to show a small icon when collapsing the notification
+ .setLargeIcon(eggImage)
+ // snooze action to reeschedule the notification
+ .addAction(
+ R.drawable.egg_icon,
+ context.getString(R.string.snooze),
+ snoozePendingIntent
+ )
+ // priority defines the level of user interruption
+ // High priority makes a sound and appears as a heads up notification
+ // Default priority makes a sound
+ // Low priority makes no sound
+ // Min priority makes no sound and does not appear in the status bar
+ .setPriority(NotificationManagerCompat.IMPORTANCE_HIGH)
+ // This information about your notification category is used by the system to make decisions about displaying your notification when the device is in Do Not Disturb mode.
+ // https://developer.android.com/training/notify-user/build-notification#system-category
+ .setCategory(NotificationCompat.CATEGORY_REMINDER)
+ // https://developer.android.com/training/notify-user/build-notification#urgent-message
+ .setFullScreenIntent(fullScreenPedingIntent, true)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setVibrate(longArrayOf(100, 200, 100, 200))
+ .run {
+ notify(NOTIFICATION_ID, this.build())
+ }
+}
+
+fun NotificationManager.createChannel(
+ channelId: String,
+ channelName: String,
+ channelDescription: String,
+) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ NotificationChannel(
+ channelId,
+ channelName,
+ NotificationManager.IMPORTANCE_HIGH
+ ).apply {
+ enableLights(true)
+ lightColor = Color.RED
+ enableVibration(true)
+ description = channelDescription
+ setShowBadge(false)
+ }.run {
+ createNotificationChannel(this)
+ }
+ }
+}
+
+fun NotificationManager.cancelNotifications() = cancelAll()
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index a91ed6c4..88987da9 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -21,4 +21,4 @@
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".MainActivity"/>
+ tools:context="dev.filipebezerra.android.eggtimernotifications.MainActivity"/>
diff --git a/app/src/main/res/layout/fragment_egg_timer.xml b/app/src/main/res/layout/fragment_egg_timer.xml
index b5eab981..c892f740 100644
--- a/app/src/main/res/layout/fragment_egg_timer.xml
+++ b/app/src/main/res/layout/fragment_egg_timer.xml
@@ -23,13 +23,13 @@
+ type="dev.filipebezerra.android.eggtimernotifications.timer.EggTimerViewModel" />
+ tools:context="dev.filipebezerra.android.eggtimernotifications.timer.EggTimerFragment">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..0aff7969
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,4 @@
+
+
+ 32dp
+
\ 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 79164f9e..01d424b4 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,5 +1,4 @@
-
-
egg_channel
Egg
+ Time for breakfast
+
+
fcm_default_channel
Breakfast
+
It is time! Bon appetit!
- Egg timer is running...
+ Egg timer is running…
Breakfast reminder
Snooze
+ Important!!!
diff --git a/build.gradle b/build.gradle
index edab77f3..64d9d446 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,17 +16,16 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.72'
+ ext.kotlin_version = '1.4.21'
repositories {
google()
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.0.1'
+ classpath 'com.android.tools.build:gradle:4.1.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
+ classpath 'com.google.gms:google-services:4.3.4'
}
}
@@ -34,10 +33,16 @@ allprojects {
repositories {
google()
jcenter()
-
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
+
+ext {
+ lifecycle_version = "2.2.0"
+ work_version = "2.4.0"
+ arch_version = "2.1.0"
+ fragment_version = "1.2.5"
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 47a3857d..e346567c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Aug 28 16:34:52 PDT 2019
+#Sat Dec 26 13:10:10 BRT 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
diff --git a/settings.gradle b/settings.gradle
index e14c9a6d..c66fc0ad 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -16,3 +16,4 @@
*/
include ':app'
+rootProject.name = "Egg Timer"
\ No newline at end of file