AccountManager.kt 6.71 KB
Newer Older
Konrad Pozniak's avatar
Konrad Pozniak committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* Copyright 2018 Conny Duck
 *
 * This file is a part of Tusky.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with Tusky; if not,
 * see <http://www.gnu.org/licenses>. */

package com.keylesspalace.tusky.db

import android.util.Log
import com.keylesspalace.tusky.entity.Account
Konrad Pozniak's avatar
Konrad Pozniak committed
20
import com.keylesspalace.tusky.entity.Status
Konrad Pozniak's avatar
Konrad Pozniak committed
21 22 23 24 25 26

/**
 * This class caches the account database and handles all account related operations
 * @author ConnyDuck
 */

27 28
private const val TAG = "AccountManager"

Ivan Kupalov's avatar
Ivan Kupalov committed
29
class AccountManager(db: AppDatabase) {
Konrad Pozniak's avatar
Konrad Pozniak committed
30

Ivan Kupalov's avatar
Ivan Kupalov committed
31 32
    @Volatile
    var activeAccount: AccountEntity? = null
Konrad Pozniak's avatar
Konrad Pozniak committed
33 34

    private var accounts: MutableList<AccountEntity> = mutableListOf()
Ivan Kupalov's avatar
Ivan Kupalov committed
35
    private val accountDao: AccountDao = db.accountDao()
Konrad Pozniak's avatar
Konrad Pozniak committed
36 37

    init {
38 39 40

        // TODO: should system-wide Librem One accounts be loaded here?

Konrad Pozniak's avatar
Konrad Pozniak committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54
        accounts = accountDao.loadAll().toMutableList()

        activeAccount = accounts.find { acc ->
            acc.isActive
        }
    }

    /**
     * Adds a new empty account and makes it the active account.
     * More account information has to be added later with [updateActiveAccount]
     * or the account wont be saved to the database.
     * @param accessToken the access token for the new account
     * @param domain the domain of the accounts Mastodon instance
     */
55
    fun addAccount(accessToken: String, domain: String, username: String = ""): Long {
Konrad Pozniak's avatar
Konrad Pozniak committed
56

Ivan Kupalov's avatar
Ivan Kupalov committed
57
        activeAccount?.let {
Konrad Pozniak's avatar
Konrad Pozniak committed
58
            it.isActive = false
Ivan Kupalov's avatar
Ivan Kupalov committed
59
            Log.d(TAG, "addAccount: saving account with id " + it.id)
Konrad Pozniak's avatar
Konrad Pozniak committed
60 61 62 63

            accountDao.insertOrReplace(it)
        }

64 65
        val maxAccountId = accounts.maxBy { it.id }?.id ?: 0
        val newAccountId = maxAccountId + 1
66
        activeAccount = AccountEntity(id = newAccountId, username = username, domain = domain.toLowerCase(), accessToken = accessToken, isActive = true)
67 68 69 70
        activeAccount?.let {
            accountDao.insertOrReplace(it)
            accounts.add(it)
        }
Konrad Pozniak's avatar
Konrad Pozniak committed
71

72
        return newAccountId
Konrad Pozniak's avatar
Konrad Pozniak committed
73 74 75 76 77 78 79 80
    }

    /**
     * Saves an already known account to the database.
     * New accounts must be created with [addAccount]
     * @param account the account to save
     */
    fun saveAccount(account: AccountEntity) {
Ivan Kupalov's avatar
Ivan Kupalov committed
81 82
        if (account.id != 0L) {
            Log.d(TAG, "saveAccount: saving account with id " + account.id)
Konrad Pozniak's avatar
Konrad Pozniak committed
83 84 85 86 87 88 89 90 91
            accountDao.insertOrReplace(account)
        }

    }

    /**
     * Logs the current account out by deleting all data of the account.
     * @return the new active account, or null if no other account was found
     */
Ivan Kupalov's avatar
Ivan Kupalov committed
92
    fun logActiveAccountOut(): AccountEntity? {
Konrad Pozniak's avatar
Konrad Pozniak committed
93

94 95
        // TODO: also log out of the system-wide Librem One social account here

Ivan Kupalov's avatar
Ivan Kupalov committed
96
        if (activeAccount == null) {
Konrad Pozniak's avatar
Konrad Pozniak committed
97 98 99 100 101
            return null
        } else {
            accounts.remove(activeAccount!!)
            accountDao.delete(activeAccount!!)

Ivan Kupalov's avatar
Ivan Kupalov committed
102
            if (accounts.size > 0) {
Konrad Pozniak's avatar
Konrad Pozniak committed
103 104
                accounts[0].isActive = true
                activeAccount = accounts[0]
Ivan Kupalov's avatar
Ivan Kupalov committed
105
                Log.d(TAG, "logActiveAccountOut: saving account with id " + accounts[0].id)
Konrad Pozniak's avatar
Konrad Pozniak committed
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
                accountDao.insertOrReplace(accounts[0])
            } else {
                activeAccount = null
            }
            return activeAccount

        }

    }

    /**
     * updates the current account with new information from the mastodon api
     * and saves it in the database
     * @param account the [Account] object returned from the api
     */
    fun updateActiveAccount(account: Account) {
Ivan Kupalov's avatar
Ivan Kupalov committed
122
        activeAccount?.let {
Konrad Pozniak's avatar
Konrad Pozniak committed
123 124
            it.accountId = account.id
            it.username = account.username
125
            it.displayName = account.name
Konrad Pozniak's avatar
Konrad Pozniak committed
126
            it.profilePictureUrl = account.avatar
Konrad Pozniak's avatar
Konrad Pozniak committed
127 128
            it.defaultPostPrivacy = account.source?.privacy ?: Status.Visibility.PUBLIC
            it.defaultMediaSensitivity = account.source?.sensitive ?: false
129
            it.emojis = account.emojis ?: emptyList()
Konrad Pozniak's avatar
Konrad Pozniak committed
130

Ivan Kupalov's avatar
Ivan Kupalov committed
131
            Log.d(TAG, "updateActiveAccount: saving account with id " + it.id)
Konrad Pozniak's avatar
Konrad Pozniak committed
132 133 134 135
            it.id = accountDao.insertOrReplace(it)

            val accountIndex = accounts.indexOf(it)

Ivan Kupalov's avatar
Ivan Kupalov committed
136
            if (accountIndex != -1) {
Konrad Pozniak's avatar
Konrad Pozniak committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
                //in case the user was already logged in with this account, remove the old information
                accounts.removeAt(accountIndex)
                accounts.add(accountIndex, it)
            } else {
                accounts.add(it)
            }

        }
    }

    /**
     * changes the active account
     * @param accountId the database id of the new active account
     */
    fun setActiveAccount(accountId: Long) {

Ivan Kupalov's avatar
Ivan Kupalov committed
153 154
        activeAccount?.let {
            Log.d(TAG, "setActiveAccount: saving account with id " + it.id)
Konrad Pozniak's avatar
Konrad Pozniak committed
155
            it.isActive = false
156
            saveAccount(it)
Konrad Pozniak's avatar
Konrad Pozniak committed
157 158 159 160 161 162
        }

        activeAccount = accounts.find { acc ->
            acc.id == accountId
        }

Ivan Kupalov's avatar
Ivan Kupalov committed
163
        activeAccount?.let {
Konrad Pozniak's avatar
Konrad Pozniak committed
164 165 166 167 168 169 170 171 172
            it.isActive = true
            accountDao.insertOrReplace(it)
        }
    }

    /**
     * @return an immutable list of all accounts in the database with the active account first
     */
    fun getAllAccountsOrderedByActive(): List<AccountEntity> {
173 174
        val accountsCopy = accounts.toMutableList()
        accountsCopy.sortWith(Comparator { l, r ->
Konrad Pozniak's avatar
Konrad Pozniak committed
175 176 177 178 179 180 181
            when {
                l.isActive && !r.isActive -> -1
                r.isActive && !l.isActive -> 1
                else -> 0
            }
        })

182
        return accountsCopy
Konrad Pozniak's avatar
Konrad Pozniak committed
183 184 185 186 187
    }

    /**
     * @return true if at least one account has notifications enabled
     */
188
    fun areNotificationsEnabled(): Boolean {
Konrad Pozniak's avatar
Konrad Pozniak committed
189 190 191 192 193 194 195 196 197 198 199 200 201 202
        return accounts.any { it.notificationsEnabled }
    }

    /**
     * Finds an account by its database id
     * @param accountId the id of the account
     * @return the requested account or null if it was not found
     */
    fun getAccountById(accountId: Long): AccountEntity? {
        return accounts.find { acc ->
            acc.id == accountId
        }
    }

203 204 205 206 207 208 209 210 211 212 213 214
    /**
     * Finds an account by its username and domain
     * @param username the username of the account
     * @param domain the domain of the account
     * @return the requested account or null if it was not found
     */
    fun getAccountByUsername(username: String, domain: String): AccountEntity? {
        return accounts.find { acc ->
            acc.username == username && acc.domain == domain
        }
    }

Konrad Pozniak's avatar
Konrad Pozniak committed
215
}