1 /* <lambda>null2 * Copyright (C) 2019 The Android Open Source Project 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package com.example.android.bubbles.data 17 18 import android.content.Context 19 import androidx.annotation.MainThread 20 import androidx.lifecycle.LiveData 21 import androidx.lifecycle.MutableLiveData 22 import java.util.concurrent.Executor 23 import java.util.concurrent.Executors 24 25 interface ChatRepository { 26 fun getContacts(): LiveData<List<Contact>> 27 fun findContact(id: Long): LiveData<Contact?> 28 fun findMessages(id: Long): LiveData<List<Message>> 29 fun sendMessage(id: Long, text: String) 30 fun activateChat(id: Long) 31 fun deactivateChat(id: Long) 32 fun showAsBubble(id: Long) 33 fun canBubble(): Boolean 34 } 35 36 class DefaultChatRepository internal constructor( 37 private val notificationHelper: NotificationHelper, 38 private val executor: Executor 39 ) : ChatRepository { 40 41 companion object { 42 private var instance: DefaultChatRepository? = null 43 getInstancenull44 fun getInstance(context: Context): DefaultChatRepository { 45 return instance ?: synchronized(this) { 46 instance ?: DefaultChatRepository( 47 NotificationHelper(context), 48 Executors.newFixedThreadPool(4) 49 ).also { 50 instance = it 51 } 52 } 53 } 54 } 55 56 private var currentChat: Long = 0L 57 contactnull58 private val chats = Contact.CONTACTS.map { contact -> 59 contact.id to Chat(contact) 60 }.toMap() 61 62 init { 63 notificationHelper.setUpNotificationChannels() 64 } 65 66 @MainThread getContactsnull67 override fun getContacts(): LiveData<List<Contact>> { 68 return MutableLiveData<List<Contact>>().apply { 69 postValue(Contact.CONTACTS) 70 } 71 } 72 73 @MainThread findContactnull74 override fun findContact(id: Long): LiveData<Contact?> { 75 return MutableLiveData<Contact>().apply { 76 postValue(Contact.CONTACTS.find { it.id == id }) 77 } 78 } 79 80 @MainThread findMessagesnull81 override fun findMessages(id: Long): LiveData<List<Message>> { 82 val chat = chats.getValue(id) 83 return object : LiveData<List<Message>>() { 84 85 private val listener = { messages: List<Message> -> 86 postValue(messages) 87 } 88 89 override fun onActive() { 90 value = chat.messages 91 chat.addListener(listener) 92 } 93 94 override fun onInactive() { 95 chat.removeListener(listener) 96 } 97 } 98 } 99 100 @MainThread sendMessagenull101 override fun sendMessage(id: Long, text: String) { 102 val chat = chats.getValue(id) 103 chat.addMessage(Message.Builder().apply { 104 sender = 0L // User 105 this.text = text 106 timestamp = System.currentTimeMillis() 107 }) 108 executor.execute { 109 // The animal is typing... 110 Thread.sleep(5000L) 111 // Receive a reply. 112 chat.addMessage(chat.contact.reply(text)) 113 // Show notification if the chat is not on the foreground. 114 if (chat.contact.id != currentChat) { 115 notificationHelper.showNotification(chat, false) 116 } 117 } 118 } 119 activateChatnull120 override fun activateChat(id: Long) { 121 currentChat = id 122 notificationHelper.dismissNotification(id) 123 } 124 deactivateChatnull125 override fun deactivateChat(id: Long) { 126 if (currentChat == id) { 127 currentChat = 0 128 } 129 } 130 showAsBubblenull131 override fun showAsBubble(id: Long) { 132 val chat = chats.getValue(id) 133 executor.execute { 134 notificationHelper.showNotification(chat, true) 135 } 136 } 137 canBubblenull138 override fun canBubble(): Boolean { 139 return notificationHelper.canBubble() 140 } 141 } 142