Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation and improve formatting #4

Merged
merged 14 commits into from
Dec 8, 2023
2 changes: 1 addition & 1 deletion app/src/main/java/xyz/wingio/dimett/Dimett.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Dimett : Application() {
override fun onCreate() {
super.onCreate()

// Add gif support (https://coil-kt.github.io/coil/gifs/)
val imageLoader = ImageLoader.Builder(this)
.components {
if (Build.VERSION.SDK_INT >= 28) {
Expand All @@ -46,7 +47,6 @@ class Dimett : Application() {
loggerModule
)
}

}

}
22 changes: 22 additions & 0 deletions app/src/main/java/xyz/wingio/dimett/ast/Renderer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ import xyz.wingio.syntakts.compose.rememberAsyncRendered
import xyz.wingio.syntakts.markdown.addBasicMarkdownRules
import xyz.wingio.syntakts.syntakts

/**
* Renders a formatted version of [text]
*
* @param text Text to parse and format
* @param emojiMap Used to insert custom emoji into the text
* @param mentionMap All the users mentioned in the post
* @param actionHandler Callback that is passed the actions name
*/
@Composable
fun Syntakts<DefaultRenderContext>.render(
text: String,
Expand All @@ -21,6 +29,11 @@ fun Syntakts<DefaultRenderContext>.render(
context = rememberRenderContext(emojiMap, mentionMap, actionHandler)
)

/**
* Creates a remembered version of [DefaultRenderContext]
*
* @see DefaultRenderContext
*/
@Composable
fun rememberRenderContext(
emojiMap: Map<String, String>,
Expand All @@ -35,6 +48,9 @@ fun rememberRenderContext(
}
}

/**
* Contains all the rules for rendering post content
*/
val DefaultSyntakts = syntakts {
addHashtagRule()
addMentionRule()
Expand All @@ -43,13 +59,19 @@ val DefaultSyntakts = syntakts {
addUnicodeEmojiRule()
}

/**
* Contains the rules for rendering styled string resources
*/
val StringSyntakts = syntakts {
addUrlRule()
addClickableRule()
addBasicMarkdownRules()
addUnicodeEmojiRule()
}

/**
* Only contains rules necessary for emotes and Twemoji
*/
val EmojiSyntakts = syntakts {
addEmojiRule()
addUnicodeEmojiRule()
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/java/xyz/wingio/dimett/ast/Rules.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ import xyz.wingio.syntakts.compose.style.toSyntaktsColor
import xyz.wingio.syntakts.style.Style

const val urlRegex =
"https?:\\/\\/([\\w+?]+\\.[\\w+]+)([a-zA-Z0-9\\~\\!\\@\\#\\\$\\%\\^\\&\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?"
"https?:\\/\\/([\\w+?]+\\.[\\w+]+)([a-zA-Z0-9\\~\\!\\@\\#\\\$\\%\\^\\&\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?" // https://example.com

const val hyperlinkRegex =
"\\[(.+?)\\]\\(($urlRegex)\\)"
"\\[(.+?)\\]\\(($urlRegex)\\)" // [link](https://example.com)

const val clickableRegex =
"\\[(.+?)\\]\\{(.+?)\\}"
"\\[(.+?)\\]\\{(.+?)\\}" // [some text]{onSomeAction}

const val emojiRegex =
":(.+?):"
":(.+?):" // :shortcode:

const val mentionRegex =
"@(\\S+?)\\b(@(\\S+)\\b)?"
"@(\\S+?)\\b(@(\\S+)\\b)?" // @user or @[email protected]

const val hashtagRegex =
"#(.+?)\\b"
"#(.+?)\\b" // #sometext

fun Syntakts.Builder<DefaultRenderContext>.addUrlRule() {
rule(urlRegex) { result, context ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.UriHandler

data class DefaultRenderContext(
val emojiMap: Map<String, String>,
val mentionMap: Map<String, String>,
val emojiMap: Map<String, String>, // shortcode: url
val mentionMap: Map<String, String>, // username to id
val linkColor: Color,
val uriHandler: UriHandler,
val clickActionHandler: (String) -> Unit
val clickActionHandler: (String) -> Unit // Is passed the action name (Ex. onUserClick)
)
2 changes: 1 addition & 1 deletion app/src/main/java/xyz/wingio/dimett/di/HttpModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ val httpModule = module {
defaultRequest {
header(
HttpHeaders.UserAgent,
"Dimett/${BuildConfig.APPLICATION_ID} v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})${if (BuildConfig.DEBUG) " - Debug" else ""}"
"Dimett/${BuildConfig.APPLICATION_ID} v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" // Dimett/xyz.wingio.dimett v1.0.0 (1)
)
}
install(Logging) {
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/xyz/wingio/dimett/domain/db/AccountsDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import androidx.room.Query
import androidx.room.Update
import xyz.wingio.dimett.domain.db.entities.Account

/**
* Used to manage saved [Account]s
*/
@Dao
interface AccountsDao {

Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/xyz/wingio/dimett/domain/db/AppDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import androidx.room.TypeConverters
import xyz.wingio.dimett.domain.db.entities.Account
import xyz.wingio.dimett.domain.db.entities.Instance

/**
* Manages complex persistent data (Such as accounts and instances)
*/
@Database(
entities = [Account::class, Instance::class],
version = 1
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/xyz/wingio/dimett/domain/db/Converters.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import kotlinx.serialization.json.Json
import xyz.wingio.dimett.rest.dto.CustomEmoji
import xyz.wingio.dimett.rest.dto.user.Field

/**
* Contains methods to convert any non-primitive data types
*/
@ProvidedTypeConverter
class Converters(
private val json: Json
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/xyz/wingio/dimett/domain/db/InstancesDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import xyz.wingio.dimett.domain.db.entities.Account
import xyz.wingio.dimett.domain.db.entities.Instance

/**
* Used to manage saved [Instance]s
*/
@Dao
interface InstancesDao {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import androidx.room.PrimaryKey
import xyz.wingio.dimett.rest.dto.CustomEmoji
import xyz.wingio.dimett.rest.dto.user.Field

/**
* Represents an account that can be logged into
*
* @see xyz.wingio.dimett.rest.dto.user.CredentialUser
*/
@Entity(
foreignKeys = [ForeignKey(
entity = Instance::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

/**
* Represents a Mastodon compatible instance with an existing OAuth application
*/
@Entity
data class Instance(
@PrimaryKey val url: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,55 @@ import xyz.wingio.dimett.domain.db.entities.Account
import xyz.wingio.dimett.rest.dto.user.CredentialUser
import xyz.wingio.dimett.utils.mainThread

/**
* Manage all stored accounts (adding, switching, deleting)
*
* @param preferenceManager Used for obtaining the logged in id
*/
class AccountManager(
db: AppDatabase,
private val preferenceManager: PreferenceManager
) {

// All db accesses need to be done on another thread
private val managerScope = CoroutineScope(Dispatchers.IO)
private val dao = db.accountsDao()

/**
* Whether or not all accounts have been loaded yet
*/
var isInitialized by mutableStateOf(false)
private set

/**
* Cached version of the accounts table for fast synchronous account fetching
*/
var accounts: MutableList<Account> = mutableStateListOf()
private set

/**
* Currently logged on account, null when not logged in to any account
*/
val current: Account?
get() = get(preferenceManager.currentAccount)

init {
managerScope.launch {
val accs = dao.listAccounts()
mainThread {
accounts += accs
isInitialized = true
val accs = dao.listAccounts() // Fetch all accounts from the database
mainThread { // Compose state needs to be altered on the main thread
accounts += accs // Cache them all in memory
isInitialized = true // Mark us as ready
}
}
}

/**
* Adds an account using a [CredentialUser]
*
* @param user User to add as an account
* @param token The token for the [user]
* @param instance Instance the [user] is on
*/
fun addAccount(user: CredentialUser, token: String, instance: String) {
managerScope.launch {
val acct = with(user) {
Expand Down Expand Up @@ -77,6 +99,9 @@ class AccountManager(
}
}

/**
* Updates an account
*/
fun updateAccount(account: Account) {
managerScope.launch {
if (account.id.isNotBlank()) {
Expand All @@ -85,12 +110,18 @@ class AccountManager(
}
}

/**
* Switches to another account
*/
fun switchAccount(id: String) {
val otherAccount = accounts.find { it.id == id } ?: return

preferenceManager.currentAccount = otherAccount.id
}

/**
* Retrieves an account by its id or null if one doesn't exist
*/
operator fun get(id: String): Account? {
return accounts.find { it.id == id }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,29 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import xyz.wingio.dimett.domain.db.AppDatabase
import xyz.wingio.dimett.domain.db.entities.Instance
import xyz.wingio.dimett.utils.mainThread

class InstanceManager(database: AppDatabase, val accountManager: AccountManager) {
private val dao = database.instancesDao()
/**
* Managed saved instances and associated OAuth apps
*/
class InstanceManager(
database: AppDatabase,
val accountManager: AccountManager
) {

// All db accesses need to be done on another thread
private val managerScope = CoroutineScope(Dispatchers.IO)
private val dao = database.instancesDao()

/**
* Cached version of the instances table for fast synchronous instance fetching
*/
var instances: MutableList<Instance> = mutableListOf()
private set

/**
* Gets the instance for the currently logged on account
*/
val current: Instance?
get() {
val account = accountManager.current ?: return null
Expand All @@ -22,10 +37,21 @@ class InstanceManager(database: AppDatabase, val accountManager: AccountManager)

init {
managerScope.launch {
instances = dao.listInstances().toMutableList()
val _instances = dao.listInstances() // Fetch all accounts from the database
mainThread { // Compose state needs to be altered on the main thread
instances += _instances // Cache them all in memory
}
}
}

/**
* Stores an [Instance]
*
* @param url Base url for the instance
* @param clientId Client id for the associated OAuth app
* @param clientSecret Client secret for the associated OAuth app
* @param features Supported features that this instance has (Ex. reactions)
*/
fun addInstance(
url: String,
clientId: String,
Expand All @@ -40,10 +66,16 @@ class InstanceManager(database: AppDatabase, val accountManager: AccountManager)
return i
}

/**
* Checks if the instance with the given [url] already has an OAuth app we could use
*/
fun exists(url: String): Boolean {
return instances.find { it.url == url } != null
}

/**
* Obtains the instance with the given [url]
*/
operator fun get(url: String) = instances.find { it.url == url }

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ package xyz.wingio.dimett.domain.manager
import android.content.Context
import xyz.wingio.dimett.domain.manager.base.BasePreferenceManager

/**
* Manage general app preferences
*/
class PreferenceManager(context: Context) :
BasePreferenceManager(context.getSharedPreferences("prefs", Context.MODE_PRIVATE)) {

/**
* Id for the currently logged in account
*/
var currentAccount by stringPreference("current_account")

}
Loading
Loading