Unverified Commit dee75e6a authored by Filipe Brito's avatar Filipe Brito Committed by GitHub

Merge branch 'develop' into fix-2059

parents 41229615 d34e779d
...@@ -43,8 +43,8 @@ cd Rocket.Chat.Android/app ...@@ -43,8 +43,8 @@ cd Rocket.Chat.Android/app
## Bug report & Feature request ## Bug report & Feature request
Are you having a technical issue trying to compile the app, or setting up Push Notifications? Please use our Community Support channel for that: https://forums.rocket.chat/c/community-support. The issues are only suppose to be used for bugs, improvements and features in the native Android application. Are you having a technical issue trying to compile the app, or setting up Push Notifications? Please use our Community Support channel for that: https://forums.rocket.chat/c/community-support. The issues are only supposed to be used for bugs, improvements, and features in the native Android application.
## Coding Style ## Coding Style
Please follow the official [Kotlin coding convections](https://kotlinlang.org/docs/reference/coding-conventions.html) when contributing. Please follow the official [Kotlin coding conventions](https://kotlinlang.org/docs/reference/coding-conventions.html) when contributing.
...@@ -2,7 +2,9 @@ def taskRequests = getGradle().getStartParameter().getTaskRequests().toString() ...@@ -2,7 +2,9 @@ def taskRequests = getGradle().getStartParameter().getTaskRequests().toString()
def isPlay = !(taskRequests.contains("Foss") || taskRequests.contains("foss")) def isPlay = !(taskRequests.contains("Foss") || taskRequests.contains("foss"))
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
if (isPlay) { apply plugin: 'io.fabric' } if (isPlay) {
apply plugin: 'io.fabric'
}
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
...@@ -16,13 +18,12 @@ android { ...@@ -16,13 +18,12 @@ android {
applicationId "chat.rocket.android" applicationId "chat.rocket.android"
minSdkVersion versions.minSdk minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk targetSdkVersion versions.targetSdk
versionCode 2057 versionCode 2065
versionName "3.2.0" versionName "3.4.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
def gitSha = 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim() def gitSha = 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim()
def buildTime = new GregorianCalendar().format("MM-dd-yyyy' 'h:mm:ss a z")
buildConfigField "String", "GIT_SHA", "\"${gitSha}\"" buildConfigField "String", "GIT_SHA", "\"${gitSha}\""
javaCompileOptions { javaCompileOptions {
...@@ -30,6 +31,17 @@ android { ...@@ -30,6 +31,17 @@ android {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
} }
} }
// For Jitsi
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// For Jitsi
ndk {
abiFilters "armeabi-v7a", "x86"
}
} }
signingConfigs { signingConfigs {
...@@ -73,7 +85,7 @@ android { ...@@ -73,7 +85,7 @@ android {
dimension "type" dimension "type"
} }
// only foss // only FOSS
foss { foss {
dimension "type" dimension "type"
} }
...@@ -83,6 +95,10 @@ android { ...@@ -83,6 +95,10 @@ android {
exclude 'META-INF/core.kotlin_module' exclude 'META-INF/core.kotlin_module'
exclude 'META-INF/main.kotlin_module' exclude 'META-INF/main.kotlin_module'
} }
lintOptions {
lintConfig file("src/main/res/xml/lint.xml")
}
} }
dependencies { dependencies {
...@@ -96,7 +112,7 @@ dependencies { ...@@ -96,7 +112,7 @@ dependencies {
implementation project(':suggestions') implementation project(':suggestions')
implementation libraries.kotlin implementation libraries.kotlin
implementation libraries.coroutines implementation libraries.coroutinesCore
implementation libraries.coroutinesAndroid implementation libraries.coroutinesAndroid
implementation libraries.appCompat implementation libraries.appCompat
...@@ -123,6 +139,8 @@ dependencies { ...@@ -123,6 +139,8 @@ dependencies {
implementation libraries.viewmodelKtx implementation libraries.viewmodelKtx
implementation libraries.workmanager implementation libraries.workmanager
implementation libraries.livedataKtx
implementation libraries.rxKotlin implementation libraries.rxKotlin
implementation libraries.rxAndroid implementation libraries.rxAndroid
...@@ -133,25 +151,25 @@ dependencies { ...@@ -133,25 +151,25 @@ dependencies {
implementation libraries.timber implementation libraries.timber
implementation libraries.threeTenABP implementation libraries.threeTenABP
kapt libraries.kotshiCompiler
implementation libraries.kotshiApi
implementation libraries.fresco implementation libraries.fresco
api libraries.frescoOkHttp api libraries.frescoOkHttp
implementation libraries.frescoAnimatedGif implementation libraries.frescoAnimatedGif
implementation libraries.frescoWebP implementation libraries.frescoWebP
implementation libraries.frescoAnimatedWebP implementation libraries.frescoAnimatedWebP
implementation libraries.glide
implementation libraries.glideTransformations
kapt libraries.kotshiCompiler
implementation libraries.kotshiApi
implementation libraries.frescoImageViewer implementation libraries.frescoImageViewer
implementation libraries.markwon implementation libraries.markwon
implementation libraries.aVLoadingIndicatorView implementation libraries.aVLoadingIndicatorView
implementation libraries.livedataKtx implementation libraries.glide
implementation libraries.glideTransformations
implementation(libraries.jitsi) { transitive = true }
implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation 'com.google.code.findbugs:jsr305:3.0.2'
...@@ -159,8 +177,8 @@ dependencies { ...@@ -159,8 +177,8 @@ dependencies {
playImplementation libraries.fcm playImplementation libraries.fcm
playImplementation libraries.firebaseAnalytics playImplementation libraries.firebaseAnalytics
playImplementation libraries.playServicesAuth playImplementation libraries.playServicesAuth
playImplementation('com.crashlytics.sdk.android:crashlytics:2.9.5@aar') { transitive = true } playImplementation('com.crashlytics.sdk.android:crashlytics:2.9.8@aar') { transitive = true }
playImplementation('com.crashlytics.sdk.android:answers:1.4.3@aar') { transitive = true } playImplementation('com.crashlytics.sdk.android:answers:1.4.6@aar') { transitive = true }
testImplementation libraries.junit testImplementation libraries.junit
testImplementation libraries.truth testImplementation libraries.truth
...@@ -168,12 +186,6 @@ dependencies { ...@@ -168,12 +186,6 @@ dependencies {
androidTestImplementation libraries.espressoIntents androidTestImplementation libraries.espressoIntents
} }
kotlin {
experimental {
coroutines "enable"
}
}
androidExtensions { androidExtensions {
experimental = true experimental = true
} }
...@@ -181,8 +193,8 @@ androidExtensions { ...@@ -181,8 +193,8 @@ androidExtensions {
// FIXME - build and install the sdk into the app/libs directory // FIXME - build and install the sdk into the app/libs directory
// We were having some issues with the kapt generated files from the sdk when importing as a module // We were having some issues with the kapt generated files from the sdk when importing as a module
def sdk_location=project.properties['sdk_location'] ?: "" def sdk_location = project.properties['sdk_location'] ?: ""
task compileSdk(type:Exec) { task compileSdk(type: Exec) {
if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) { if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) {
commandLine 'cmd', '/c', 'build-sdk.sh', sdk_location commandLine 'cmd', '/c', 'build-sdk.sh', sdk_location
} else { } else {
......
This diff is collapsed.
{ {
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 11, "version": 13,
"identityHash": "fb9f1c815809b0217d326452aeb34e92", "identityHash": "3bef73b44ae4edf2a74b48fd68f2c599",
"entities": [ "entities": [
{ {
"tableName": "users", "tableName": "users",
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
}, },
{ {
"tableName": "chatrooms", "tableName": "chatrooms",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `topic` TEXT, `announcement` TEXT, `description` TEXT, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, `muted` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `parentId` TEXT, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `topic` TEXT, `announcement` TEXT, `description` TEXT, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, `muted` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
...@@ -73,6 +73,12 @@ ...@@ -73,6 +73,12 @@
"affinity": "TEXT", "affinity": "TEXT",
"notNull": true "notNull": true
}, },
{
"fieldPath": "parentId",
"columnName": "parentId",
"affinity": "TEXT",
"notNull": false
},
{ {
"fieldPath": "type", "fieldPath": "type",
"columnName": "type", "columnName": "type",
...@@ -1013,7 +1019,7 @@ ...@@ -1013,7 +1019,7 @@
}, },
{ {
"tableName": "reactions", "tableName": "reactions",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `messageId` TEXT NOT NULL, `count` INTEGER NOT NULL, `usernames` TEXT NOT NULL, PRIMARY KEY(`reaction`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `messageId` TEXT NOT NULL, `count` INTEGER NOT NULL, `usernames` TEXT NOT NULL, `names` TEXT NOT NULL, PRIMARY KEY(`reaction`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [ "fields": [
{ {
"fieldPath": "reaction", "fieldPath": "reaction",
...@@ -1038,6 +1044,12 @@ ...@@ -1038,6 +1044,12 @@
"columnName": "usernames", "columnName": "usernames",
"affinity": "TEXT", "affinity": "TEXT",
"notNull": true "notNull": true
},
{
"fieldPath": "names",
"columnName": "names",
"affinity": "TEXT",
"notNull": true
} }
], ],
"primaryKey": { "primaryKey": {
...@@ -1099,7 +1111,7 @@ ...@@ -1099,7 +1111,7 @@
], ],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"fb9f1c815809b0217d326452aeb34e92\")" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"3bef73b44ae4edf2a74b48fd68f2c599\")"
] ]
} }
} }
\ No newline at end of file
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "06359a8c2943365dd094bc5dff210203",
"entities": [
{
"tableName": "users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "utcOffset",
"columnName": "utcOffset",
"affinity": "REAL",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_users_username",
"unique": false,
"columnNames": [
"username"
],
"createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
}
],
"foreignKeys": []
},
{
"tableName": "chatrooms",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "fullname",
"columnName": "fullname",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "ownerId",
"columnName": "ownerId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "readonly",
"columnName": "readonly",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "favorite",
"columnName": "favorite",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "open",
"columnName": "open",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alert",
"columnName": "alert",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userMentions",
"columnName": "userMentions",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "groupMentions",
"columnName": "groupMentions",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "updatedAt",
"columnName": "updatedAt",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastSeen",
"columnName": "lastSeen",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastMessageText",
"columnName": "lastMessageText",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastMessageUserId",
"columnName": "lastMessageUserId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastMessageTimestamp",
"columnName": "lastMessageTimestamp",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_chatrooms_userId",
"unique": false,
"columnNames": [
"userId"
],
"createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
},
{
"name": "index_chatrooms_ownerId",
"unique": false,
"columnNames": [
"ownerId"
],
"createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
},
{
"name": "index_chatrooms_subscriptionId",
"unique": true,
"columnNames": [
"subscriptionId"
],
"createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
},
{
"name": "index_chatrooms_updatedAt",
"unique": false,
"columnNames": [
"updatedAt"
],
"createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"ownerId"
],
"referencedColumns": [
"id"
]
},
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"userId"
],
"referencedColumns": [
"id"
]
},
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"lastMessageUserId"
],
"referencedColumns": [
"id"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"06359a8c2943365dd094bc5dff210203\")"
]
}
}
\ No newline at end of file
{
"formatVersion": 1,
"database": {
"version": 4,
"identityHash": "e389d26bfb975f00c75dc6fc5d06d012",
"entities": [
{
"tableName": "users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "utcOffset",
"columnName": "utcOffset",
"affinity": "REAL",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_users_username",
"unique": false,
"columnNames": [
"username"
],
"createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
}
],
"foreignKeys": []
},
{
"tableName": "chatrooms",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "fullname",
"columnName": "fullname",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "ownerId",
"columnName": "ownerId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "readonly",
"columnName": "readonly",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "favorite",
"columnName": "favorite",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "open",
"columnName": "open",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alert",
"columnName": "alert",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userMentions",
"columnName": "userMentions",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "groupMentions",
"columnName": "groupMentions",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "updatedAt",
"columnName": "updatedAt",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastSeen",
"columnName": "lastSeen",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastMessageText",
"columnName": "lastMessageText",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastMessageUserId",
"columnName": "lastMessageUserId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastMessageTimestamp",
"columnName": "lastMessageTimestamp",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "broadcast",
"columnName": "broadcast",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_chatrooms_userId",
"unique": false,
"columnNames": [
"userId"
],
"createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
},
{
"name": "index_chatrooms_ownerId",
"unique": false,
"columnNames": [
"ownerId"
],
"createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
},
{
"name": "index_chatrooms_subscriptionId",
"unique": true,
"columnNames": [
"subscriptionId"
],
"createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
},
{
"name": "index_chatrooms_updatedAt",
"unique": false,
"columnNames": [
"updatedAt"
],
"createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"ownerId"
],
"referencedColumns": [
"id"
]
},
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"userId"
],
"referencedColumns": [
"id"
]
},
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"lastMessageUserId"
],
"referencedColumns": [
"id"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"e389d26bfb975f00c75dc6fc5d06d012\")"
]
}
}
\ No newline at end of file
{
"formatVersion": 1,
"database": {
"version": 5,
"identityHash": "47a0c30e2696ae09bc86df16cc37279d",
"entities": [
{
"tableName": "users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "status",
"columnName": "status",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "utcOffset",
"columnName": "utcOffset",
"affinity": "REAL",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_users_username",
"unique": false,
"columnNames": [
"username"
],
"createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
}
],
"foreignKeys": []
},
{
"tableName": "chatrooms",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "fullname",
"columnName": "fullname",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "userId",
"columnName": "userId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "ownerId",
"columnName": "ownerId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "readonly",
"columnName": "readonly",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isDefault",
"columnName": "isDefault",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "favorite",
"columnName": "favorite",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "open",
"columnName": "open",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alert",
"columnName": "alert",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userMentions",
"columnName": "userMentions",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "groupMentions",
"columnName": "groupMentions",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "updatedAt",
"columnName": "updatedAt",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastSeen",
"columnName": "lastSeen",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastMessageText",
"columnName": "lastMessageText",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastMessageUserId",
"columnName": "lastMessageUserId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastMessageTimestamp",
"columnName": "lastMessageTimestamp",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "broadcast",
"columnName": "broadcast",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_chatrooms_userId",
"unique": false,
"columnNames": [
"userId"
],
"createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
},
{
"name": "index_chatrooms_ownerId",
"unique": false,
"columnNames": [
"ownerId"
],
"createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
},
{
"name": "index_chatrooms_subscriptionId",
"unique": true,
"columnNames": [
"subscriptionId"
],
"createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
},
{
"name": "index_chatrooms_updatedAt",
"unique": false,
"columnNames": [
"updatedAt"
],
"createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
},
{
"name": "index_chatrooms_lastMessageUserId",
"unique": false,
"columnNames": [
"lastMessageUserId"
],
"createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)"
}
],
"foreignKeys": [
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"ownerId"
],
"referencedColumns": [
"id"
]
},
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"userId"
],
"referencedColumns": [
"id"
]
},
{
"table": "users",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"lastMessageUserId"
],
"referencedColumns": [
"id"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"47a0c30e2696ae09bc86df16cc37279d\")"
]
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application <application
android:name=".app.RocketChatApplication" android:name=".app.RocketChatApplication"
...@@ -73,6 +75,11 @@ ...@@ -73,6 +75,11 @@
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" /> android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
<activity
android:name=".videoconference.ui.VideoConferenceActivity"
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
<activity <activity
android:name=".chatroom.ui.ChatRoomActivity" android:name=".chatroom.ui.ChatRoomActivity"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
...@@ -83,7 +90,7 @@ ...@@ -83,7 +90,7 @@
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" /> android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
<!-- TODO: Change to fragment--> <!-- TODO: Change to fragment -->
<activity <activity
android:name=".settings.password.ui.PasswordActivity" android:name=".settings.password.ui.PasswordActivity"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme" />
......
package chat.rocket.android.about.di
import chat.rocket.android.about.ui.AboutFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class AboutFragmentProvider {
@ContributesAndroidInjector()
abstract fun provideAboutFragment(): AboutFragment
}
package chat.rocket.android.about.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import chat.rocket.android.BuildConfig
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.main.ui.MainActivity
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_about.*
import javax.inject.Inject
internal const val TAG_ABOUT_FRAGMENT = "AboutFragment"
class AboutFragment : Fragment() {
@Inject
lateinit var analyticsManager: AnalyticsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.fragment_about, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToolbar()
setupViews()
analyticsManager.logScreenView(ScreenViewEvent.About)
}
private fun setupViews() {
text_version_name.text = BuildConfig.VERSION_NAME
text_build_number.text = getString(
R.string.msg_build, BuildConfig.VERSION_CODE,
BuildConfig.GIT_SHA, BuildConfig.FLAVOR
)
}
private fun setupToolbar() {
with((activity as MainActivity).toolbar) {
title = getString(R.string.title_about)
setNavigationIcon(R.drawable.ic_arrow_back_white_24dp)
setNavigationOnClickListener { activity?.onBackPressed() }
}
}
companion object {
fun newInstance() = AboutFragment()
}
}
...@@ -10,7 +10,7 @@ interface Analytics { ...@@ -10,7 +10,7 @@ interface Analytics {
* Logs the login event. * Logs the login event.
* *
* @param event The [AuthenticationEvent] used to log in. * @param event The [AuthenticationEvent] used to log in.
* @param loginSucceeded True if successful logged in, false otherwise. * @param loginSucceeded True if logged in successfully, false otherwise.
*/ */
fun logLogin(event: AuthenticationEvent, loginSucceeded: Boolean) {} fun logLogin(event: AuthenticationEvent, loginSucceeded: Boolean) {}
...@@ -18,7 +18,7 @@ interface Analytics { ...@@ -18,7 +18,7 @@ interface Analytics {
* Logs the sign up event. * Logs the sign up event.
* *
* @param event The [AuthenticationEvent] used to sign up. * @param event The [AuthenticationEvent] used to sign up.
* @param signUpSucceeded True if successful signed up, false otherwise. * @param signUpSucceeded True if signed up successfully, false otherwise.
*/ */
fun logSignUp(event: AuthenticationEvent, signUpSucceeded: Boolean) {} fun logSignUp(event: AuthenticationEvent, signUpSucceeded: Boolean) {}
...@@ -71,4 +71,67 @@ interface Analytics { ...@@ -71,4 +71,67 @@ interface Analytics {
* @param resetPasswordSucceeded True if successful reset password, false otherwise. * @param resetPasswordSucceeded True if successful reset password, false otherwise.
*/ */
fun logResetPassword(resetPasswordSucceeded: Boolean) {} fun logResetPassword(resetPasswordSucceeded: Boolean) {}
/**
* Logs the video conference event.
*
* @param event The [SubscriptionTypeEvent] to log.
* @param serverUrl The server URL to log.
*/
fun logVideoConference(event: SubscriptionTypeEvent, serverUrl: String) {}
/**
* Logs the add reaction message action.
*/
fun logMessageActionAddReaction() {}
/**
* Logs the replay message action.
*/
fun logMessageActionReply() {}
/**
* Logs the quote message action.
*/
fun logMessageActionQuote() {}
/**
* Logs the permalink message action.
*/
fun logMessageActionPermalink() {}
/**
* Logs the copy message action.
*/
fun logMessageActionCopy() {}
/**
* Logs the edit message action.
*/
fun logMessageActionEdit() {}
/**
* Logs the info message action.
*/
fun logMessageActionInfo() {}
/**
* Logs the star message action.
*/
fun logMessageActionStar() {}
/**
* Logs the pin message action.
*/
fun logMessageActionPin() {}
/**
* Logs the report message action.
*/
fun logMessageActionReport() {}
/**
* Logs the delete message action.
*/
fun logMessageActionDelete() {}
} }
...@@ -76,4 +76,76 @@ class AnalyticsManager @Inject constructor( ...@@ -76,4 +76,76 @@ class AnalyticsManager @Inject constructor(
analytics.forEach { it.logResetPassword(resetPasswordSucceeded) } analytics.forEach { it.logResetPassword(resetPasswordSucceeded) }
} }
} }
fun logVideoConference(event: SubscriptionTypeEvent) {
if (analyticsTrackingInteractor.get() && serverUrl != null) {
analytics.forEach { it.logVideoConference(event, serverUrl) }
}
}
fun logMessageActionAddReaction() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionAddReaction() }
}
}
fun logMessageActionReply() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionReply() }
}
}
fun logMessageActionQuote() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionQuote() }
}
}
fun logMessageActionPermalink() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionPermalink() }
}
}
fun logMessageActionCopy() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionCopy() }
}
}
fun logMessageActionEdit() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionEdit() }
}
}
fun logMessageActionInfo() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionInfo() }
}
}
fun logMessageActionStar() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionStar() }
}
}
fun logMessageActionPin() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionPin() }
}
}
fun logMessageActionReport() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionReport() }
}
}
fun logMessageActionDelete() {
if (analyticsTrackingInteractor.get()) {
analytics.forEach { it.logMessageActionDelete() }
}
}
} }
...@@ -27,4 +27,5 @@ sealed class ScreenViewEvent(val screenName: String) { ...@@ -27,4 +27,5 @@ sealed class ScreenViewEvent(val screenName: String) {
object Preferences : ScreenViewEvent("PreferencesFragment") object Preferences : ScreenViewEvent("PreferencesFragment")
object Profile : ScreenViewEvent("ProfileFragment") object Profile : ScreenViewEvent("ProfileFragment")
object Settings : ScreenViewEvent("SettingsFragment") object Settings : ScreenViewEvent("SettingsFragment")
object Directory : ScreenViewEvent("DirectoryFragment")
} }
...@@ -3,15 +3,11 @@ package chat.rocket.android.app ...@@ -3,15 +3,11 @@ package chat.rocket.android.app
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.OnLifecycleEvent
import chat.rocket.android.server.domain.GetAccountInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
import chat.rocket.core.internal.realtime.setTemporaryStatus import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class AppLifecycleObserver @Inject constructor( class AppLifecycleObserver @Inject constructor(
...@@ -33,7 +29,7 @@ class AppLifecycleObserver @Inject constructor( ...@@ -33,7 +29,7 @@ class AppLifecycleObserver @Inject constructor(
} }
private fun changeTemporaryStatus(userStatus: UserStatus) { private fun changeTemporaryStatus(userStatus: UserStatus) {
launch { GlobalScope.launch {
serverInteractor.get()?.let { currentServer -> serverInteractor.get()?.let { currentServer ->
factory.create(currentServer).setTemporaryStatus(userStatus) factory.create(currentServer).setTemporaryStatus(userStatus)
} }
......
import android.content.Context import android.content.Context
import chat.rocket.android.R import chat.rocket.android.R
import org.threeten.bp.* import org.threeten.bp.Instant
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime
import org.threeten.bp.LocalTime
import org.threeten.bp.Period
import org.threeten.bp.ZoneId
import org.threeten.bp.format.DateTimeFormatter import org.threeten.bp.format.DateTimeFormatter
import org.threeten.bp.format.FormatStyle import org.threeten.bp.format.FormatStyle
import org.threeten.bp.format.TextStyle import org.threeten.bp.format.TextStyle
...@@ -53,39 +58,39 @@ object DateTimeHelper { ...@@ -53,39 +58,39 @@ object DateTimeHelper {
} }
} }
/** /**
* Returns a time from a [LocalDateTime]. * Returns a time from a [LocalDateTime].
* *
* @param localDateTime The [LocalDateTime]. * @param localDateTime The [LocalDateTime].
* @return The time from a [LocalDateTime]. * @return The time from a [LocalDateTime].
*/ */
fun getTime(localDateTime: LocalDateTime): String { fun getTime(localDateTime: LocalDateTime): String {
val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
return localDateTime.toLocalTime().format(formatter).toString() return localDateTime.toLocalTime().format(formatter).toString()
} }
/** /**
* Returns a date time from a [LocalDateTime]. * Returns a date time from a [LocalDateTime].
* *
* @param localDateTime The [LocalDateTime]. * @param localDateTime The [LocalDateTime].
* @return The time from a [LocalDateTime]. * @return The time from a [LocalDateTime].
*/ */
fun getDateTime(localDateTime: LocalDateTime): String { fun getDateTime(localDateTime: LocalDateTime): String {
return formatLocalDateTime(localDateTime) return formatLocalDateTime(localDateTime)
} }
private fun formatLocalDateTime(localDateTime: LocalDateTime): String { private fun formatLocalDateTime(localDateTime: LocalDateTime): String {
val formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT) val formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
return localDateTime.format(formatter).toString() return localDateTime.format(formatter).toString()
} }
private fun formatLocalDate(localDate: LocalDate): String { private fun formatLocalDate(localDate: LocalDate): String {
val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM) val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
return localDate.format(formatter).toString() return localDate.format(formatter).toString()
} }
private fun formatLocalTime(localTime: LocalTime): String { private fun formatLocalTime(localTime: LocalTime): String {
val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
return localTime.format(formatter).toString() return localTime.format(formatter).toString()
} }
} }
\ No newline at end of file
import android.content.Context import android.content.Context
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.View
import android.widget.TextView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat import androidx.core.graphics.drawable.DrawableCompat
import android.widget.TextView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
...@@ -43,7 +44,7 @@ object DrawableHelper { ...@@ -43,7 +44,7 @@ object DrawableHelper {
/** /**
* Tints an array of Drawable. * Tints an array of Drawable.
* *
* REMARK: you MUST always wrap the array of Drawable before tint it. * REMARK: you MUST always wrap the array of Drawable before tinting it.
* *
* @param drawables The array of Drawable to tint. * @param drawables The array of Drawable to tint.
* @param context The context. * @param context The context.
...@@ -60,7 +61,7 @@ object DrawableHelper { ...@@ -60,7 +61,7 @@ object DrawableHelper {
/** /**
* Tints a Drawable. * Tints a Drawable.
* *
* REMARK: you MUST always wrap the Drawable before tint it. * REMARK: you MUST always wrap the Drawable before tinting it.
* *
* @param drawable The Drawable to tint. * @param drawable The Drawable to tint.
* @param context The context. * @param context The context.
...@@ -72,33 +73,74 @@ object DrawableHelper { ...@@ -72,33 +73,74 @@ object DrawableHelper {
DrawableCompat.setTint(drawable, ContextCompat.getColor(context, resId)) DrawableCompat.setTint(drawable, ContextCompat.getColor(context, resId))
/** /**
* Compounds an array of Drawable (to appear to the left of the text) into an array of TextView. * Compounds an array of Drawable (to appear on the start side of a text) into an array of TextView.
* *
* REMARK: the number of elements in both array of Drawable and EditText MUST be equal. * REMARK: the number of elements in both arrays of Drawable and TextView MUST be equal.
* *
* @param textView The array of TextView. * @param textView The array of TextView.
* @param drawables The array of Drawable. * @param drawables The array of Drawable.
* @see compoundDrawable * @see compoundStartDrawable
*/ */
fun compoundDrawables(textView: Array<TextView>, drawables: Array<Drawable>) { fun compoundDrawables(textView: Array<TextView>, drawables: Array<Drawable>) {
if (textView.size != drawables.size) { if (textView.size != drawables.size) {
return return
} else { } else {
for (i in textView.indices) { for (i in textView.indices) {
textView[i].setCompoundDrawablesWithIntrinsicBounds(drawables[i], null, null, null) if (textView[i].resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
textView[i].setCompoundDrawablesWithIntrinsicBounds(null, null, drawables[i], null)
} else {
textView[i].setCompoundDrawablesWithIntrinsicBounds(drawables[i], null, null, null)
}
} }
} }
} }
/** /**
* Compounds a Drawable (to appear to the left of the text) into a TextView. * Compounds a Drawable (to appear on the start side of a text) into a TextView.
* *
* @param textView The TextView. * @param textView The TextView.
* @param drawable The Drawable. * @param drawable The Drawable.
* @see compoundDrawables * @see compoundDrawables
*/ */
fun compoundDrawable(textView: TextView, drawable: Drawable) = fun compoundStartDrawable(textView: TextView, drawable: Drawable) =
textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null) if (textView.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
textView.setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null)
} else {
textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
}
/**
* Compounds a Drawable (to appear on the end side of a text) into a TextView.
*
* @param textView The TextView.
* @param drawable The Drawable.
* @see compoundStartDrawable
*/
fun compoundEndDrawable(textView: TextView, drawable: Drawable) =
if (textView.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
} else {
textView.setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null)
}
/**
* Compounds a Drawable (to appear on the start and end side of a text) into a TextView.
*
* @param textView The TextView.
* @param startDrawable The start Drawable.
* @param endDrawable The end Drawable.
* @see compoundStartDrawable
*/
fun compoundStartAndEndDrawable(
textView: TextView,
startDrawable: Drawable,
endDrawable: Drawable
) =
if (textView.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
textView.setCompoundDrawablesWithIntrinsicBounds(endDrawable, null, startDrawable, null)
} else {
textView.setCompoundDrawablesWithIntrinsicBounds(startDrawable, null, endDrawable, null)
}
/** /**
* Returns the user status drawable. * Returns the user status drawable.
...@@ -116,4 +158,4 @@ object DrawableHelper { ...@@ -116,4 +158,4 @@ object DrawableHelper {
else -> getDrawableFromId(R.drawable.ic_status_invisible_12dp, context) else -> getDrawableFromId(R.drawable.ic_status_invisible_12dp, context)
} }
} }
} }
\ No newline at end of file
...@@ -24,7 +24,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor ...@@ -24,7 +24,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.SITE_URL import chat.rocket.android.server.domain.SITE_URL
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.android.util.setupFabric import chat.rocket.android.util.setupFabric
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
...@@ -37,7 +37,8 @@ import dagger.android.DispatchingAndroidInjector ...@@ -37,7 +37,8 @@ import dagger.android.DispatchingAndroidInjector
import dagger.android.HasActivityInjector import dagger.android.HasActivityInjector
import dagger.android.HasBroadcastReceiverInjector import dagger.android.HasBroadcastReceiverInjector
import dagger.android.HasServiceInjector import dagger.android.HasServiceInjector
import kotlinx.coroutines.experimental.launch import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import javax.inject.Inject import javax.inject.Inject
...@@ -114,7 +115,7 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje ...@@ -114,7 +115,7 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
// TODO - remove this // TODO - remove this
checkCurrentServer() checkCurrentServer()
// TODO - FIXME - we need to proper inject the EmojiRepository and initialize it properly // TODO - FIXME - we need to properly inject and initialize the EmojiRepository
loadEmojis() loadEmojis()
} }
...@@ -174,8 +175,8 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje ...@@ -174,8 +175,8 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
EmojiRepository.init(this) EmojiRepository.init(this)
val currentServer = getCurrentServerInteractor.get() val currentServer = getCurrentServerInteractor.get()
currentServer?.let { server -> currentServer?.let { server ->
launch { GlobalScope.launch {
val client = factory.create(server) val client = factory.get(server)
EmojiRepository.setCurrentServerUrl(server) EmojiRepository.setCurrentServerUrl(server)
val customEmojiList = mutableListOf<Emoji>() val customEmojiList = mutableListOf<Emoji>()
try { try {
......
...@@ -7,7 +7,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy ...@@ -7,7 +7,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerActivity import chat.rocket.android.dagger.scope.PerActivity
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import kotlinx.coroutines.experimental.Job import kotlinx.coroutines.Job
@Module @Module
class AuthenticationModule { class AuthenticationModule {
......
package chat.rocket.android.authentication.infraestructure package chat.rocket.android.authentication.infrastructure
import chat.rocket.android.authentication.domain.model.TokenModel import chat.rocket.android.authentication.domain.model.TokenModel
import chat.rocket.android.dagger.scope.PerActivity import chat.rocket.android.dagger.scope.PerActivity
...@@ -8,19 +8,16 @@ import chat.rocket.android.server.domain.MultiServerTokenRepository ...@@ -8,19 +8,16 @@ import chat.rocket.android.server.domain.MultiServerTokenRepository
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
@PerActivity @PerActivity
class SharedPreferencesMultiServerTokenRepository(private val repository: LocalRepository, class SharedPreferencesMultiServerTokenRepository(
private val moshi: Moshi private val repository: LocalRepository,
private val moshi: Moshi
) : MultiServerTokenRepository { ) : MultiServerTokenRepository {
override fun get(server: String): TokenModel? { override fun get(server: String): TokenModel? {
val token = repository.get("$TOKEN_KEY$server") val token = repository.get("$TOKEN_KEY$server")
val adapter = moshi.adapter<TokenModel>(TokenModel::class.java) val adapter = moshi.adapter<TokenModel>(TokenModel::class.java)
token?.let { return token?.let { adapter.fromJson(it) }
return adapter.fromJson(token)
}
return null
} }
override fun save(server: String, token: TokenModel) { override fun save(server: String, token: TokenModel) {
......
package chat.rocket.android.authentication.infraestructure package chat.rocket.android.authentication.infrastructure
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
......
...@@ -15,8 +15,9 @@ import chat.rocket.android.server.domain.favicon ...@@ -15,8 +15,9 @@ import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.isLdapAuthenticationEnabled import chat.rocket.android.server.domain.isLdapAuthenticationEnabled
import chat.rocket.android.server.domain.isPasswordResetEnabled import chat.rocket.android.server.domain.isPasswordResetEnabled
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.isEmail import chat.rocket.android.util.extensions.isEmail
...@@ -50,6 +51,7 @@ class LoginPresenter @Inject constructor( ...@@ -50,6 +51,7 @@ class LoginPresenter @Inject constructor(
) { ) {
// TODO - we should validate the current server when opening the app, and have a nonnull get() // TODO - we should validate the current server when opening the app, and have a nonnull get()
private var currentServer = serverInteractor.get()!! private var currentServer = serverInteractor.get()!!
private val token = tokenRepository.get(currentServer)
private lateinit var client: RocketChatClient private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings private lateinit var settings: PublicSettings
...@@ -60,7 +62,7 @@ class LoginPresenter @Inject constructor( ...@@ -60,7 +62,7 @@ class LoginPresenter @Inject constructor(
private fun setupConnectionInfo(serverUrl: String) { private fun setupConnectionInfo(serverUrl: String) {
currentServer = serverUrl currentServer = serverUrl
client = factory.create(currentServer) client = factory.get(currentServer)
settings = settingsInteractor.get(currentServer) settings = settingsInteractor.get(currentServer)
} }
...@@ -85,20 +87,20 @@ class LoginPresenter @Inject constructor( ...@@ -85,20 +87,20 @@ class LoginPresenter @Inject constructor(
} }
} }
val myself = retryIO("me()") { client.me() } val myself = retryIO("me()") { client.me() }
if (myself.username != null) { myself.username?.let { username ->
val user = User( val user = User(
id = myself.id, id = myself.id,
roles = myself.roles, roles = myself.roles,
status = myself.status, status = myself.status,
name = myself.name, name = myself.name,
emails = myself.emails?.map { Email(it.address ?: "", it.verified) }, emails = myself.emails?.map { Email(it.address ?: "", it.verified) },
username = myself.username, username = username,
utcOffset = myself.utcOffset utcOffset = myself.utcOffset
) )
localRepository.saveCurrentUser(currentServer, user) localRepository.saveCurrentUser(currentServer, user)
saveCurrentServer.save(currentServer) saveCurrentServer.save(currentServer)
localRepository.save(LocalRepository.CURRENT_USERNAME_KEY, myself.username) localRepository.save(LocalRepository.CURRENT_USERNAME_KEY, username)
saveAccount(myself.username!!) saveAccount(username)
saveToken(token) saveToken(token)
analyticsManager.logLogin( analyticsManager.logLogin(
AuthenticationEvent.AuthenticationWithUserAndPassword, AuthenticationEvent.AuthenticationWithUserAndPassword,
...@@ -133,15 +135,22 @@ class LoginPresenter @Inject constructor( ...@@ -133,15 +135,22 @@ class LoginPresenter @Inject constructor(
fun forgotPassword() = navigator.toForgotPassword() fun forgotPassword() = navigator.toForgotPassword()
private suspend fun saveAccount(username: String) { private fun saveAccount(username: String) {
val icon = settings.favicon()?.let { val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val logo = settings.wideTile()?.let { val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val thumb = currentServer.avatarUrl(username) val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val account = Account(currentServer, icon, logo, username, thumb) val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
username,
thumb
)
saveAccountInteractor.save(account) saveAccountInteractor.save(account)
} }
......
...@@ -39,11 +39,9 @@ internal const val REQUEST_CODE_FOR_SIGN_IN_REQUIRED = 1 ...@@ -39,11 +39,9 @@ internal const val REQUEST_CODE_FOR_SIGN_IN_REQUIRED = 1
internal const val REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION = 2 internal const val REQUEST_CODE_FOR_MULTIPLE_ACCOUNTS_RESOLUTION = 2
internal const val REQUEST_CODE_FOR_SAVE_RESOLUTION = 3 internal const val REQUEST_CODE_FOR_SAVE_RESOLUTION = 3
fun newInstance(serverName: String): Fragment { fun newInstance(serverName: String): Fragment = LoginFragment().apply {
return LoginFragment().apply { arguments = Bundle(1).apply {
arguments = Bundle(1).apply { putString(SERVER_NAME, serverName)
putString(SERVER_NAME, serverName)
}
} }
} }
...@@ -59,9 +57,8 @@ class LoginFragment : Fragment(), LoginView { ...@@ -59,9 +57,8 @@ class LoginFragment : Fragment(), LoginView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { serverName = getString(SERVER_NAME)
serverName = bundle.getString(SERVER_NAME)
} }
} }
...@@ -93,7 +90,7 @@ class LoginFragment : Fragment(), LoginView { ...@@ -93,7 +90,7 @@ class LoginFragment : Fragment(), LoginView {
text_username_or_email.setText(credential.first) text_username_or_email.setText(credential.first)
text_password.setText(credential.second) text_password.setText(credential.second)
} }
REQUEST_CODE_FOR_SAVE_RESOLUTION -> showMessage(getString(R.string.message_credentials_saved_successfully)) REQUEST_CODE_FOR_SAVE_RESOLUTION -> showMessage(getString(R.string.msg_credentials_saved_successfully))
} }
} }
} }
...@@ -150,7 +147,7 @@ class LoginFragment : Fragment(), LoginView { ...@@ -150,7 +147,7 @@ class LoginFragment : Fragment(), LoginView {
override fun showGenericErrorMessage() = showMessage(R.string.msg_generic_error) override fun showGenericErrorMessage() = showMessage(R.string.msg_generic_error)
private fun setupOnClickListener() = private fun setupOnClickListener() =
ui { _ -> ui {
button_log_in.setOnClickListener { button_log_in.setOnClickListener {
presenter.authenticateWithUserAndPassword( presenter.authenticateWithUserAndPassword(
text_username_or_email.textContent, text_username_or_email.textContent,
...@@ -160,7 +157,7 @@ class LoginFragment : Fragment(), LoginView { ...@@ -160,7 +157,7 @@ class LoginFragment : Fragment(), LoginView {
} }
override fun showForgotPasswordView() { override fun showForgotPasswordView() {
ui { _ -> ui {
button_forgot_your_password.isVisible = true button_forgot_your_password.isVisible = true
button_forgot_your_password.setOnClickListener { presenter.forgotPassword() } button_forgot_your_password.setOnClickListener { presenter.forgotPassword() }
......
...@@ -14,8 +14,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor ...@@ -14,8 +14,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.serverLogoUrl import chat.rocket.android.util.extensions.serverLogoUrl
...@@ -31,8 +32,7 @@ import chat.rocket.core.internal.rest.loginWithCas ...@@ -31,8 +32,7 @@ import chat.rocket.core.internal.rest.loginWithCas
import chat.rocket.core.internal.rest.loginWithOauth import chat.rocket.core.internal.rest.loginWithOauth
import chat.rocket.core.internal.rest.loginWithSaml import chat.rocket.core.internal.rest.loginWithSaml
import chat.rocket.core.internal.rest.me import chat.rocket.core.internal.rest.me
import kotlinx.coroutines.experimental.delay import kotlinx.coroutines.delay
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
private const val TYPE_LOGIN_OAUTH = 1 private const val TYPE_LOGIN_OAUTH = 1
...@@ -55,6 +55,7 @@ class LoginOptionsPresenter @Inject constructor( ...@@ -55,6 +55,7 @@ class LoginOptionsPresenter @Inject constructor(
) { ) {
// TODO - we should validate the current server when opening the app, and have a nonnull get() // TODO - we should validate the current server when opening the app, and have a nonnull get()
private var currentServer = serverInteractor.get()!! private var currentServer = serverInteractor.get()!!
private val token = tokenRepository.get(currentServer)
private lateinit var client: RocketChatClient private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings private lateinit var settings: PublicSettings
private lateinit var credentialToken: String private lateinit var credentialToken: String
...@@ -109,11 +110,11 @@ class LoginOptionsPresenter @Inject constructor( ...@@ -109,11 +110,11 @@ class LoginOptionsPresenter @Inject constructor(
when (loginType) { when (loginType) {
TYPE_LOGIN_OAUTH -> client.loginWithOauth(credentialToken, credentialSecret) TYPE_LOGIN_OAUTH -> client.loginWithOauth(credentialToken, credentialSecret)
TYPE_LOGIN_CAS -> { TYPE_LOGIN_CAS -> {
delay(3, TimeUnit.SECONDS) delay(3000)
client.loginWithCas(credentialToken) client.loginWithCas(credentialToken)
} }
TYPE_LOGIN_SAML -> { TYPE_LOGIN_SAML -> {
delay(3, TimeUnit.SECONDS) delay(3000)
client.loginWithSaml(credentialToken) client.loginWithSaml(credentialToken)
} }
TYPE_LOGIN_DEEP_LINK -> { TYPE_LOGIN_DEEP_LINK -> {
...@@ -170,19 +171,26 @@ class LoginOptionsPresenter @Inject constructor( ...@@ -170,19 +171,26 @@ class LoginOptionsPresenter @Inject constructor(
private fun setupConnectionInfo(serverUrl: String) { private fun setupConnectionInfo(serverUrl: String) {
currentServer = serverUrl currentServer = serverUrl
client = factory.create(currentServer) client = factory.get(currentServer)
settings = settingsInteractor.get(currentServer) settings = settingsInteractor.get(currentServer)
} }
private suspend fun saveAccount(username: String) { private fun saveAccount(username: String) {
val icon = settings.favicon()?.let { val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val logo = settings.wideTile()?.let { val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val thumb = currentServer.avatarUrl(username) val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val account = Account(currentServer, icon, logo, username, thumb) val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
username,
thumb
)
saveAccountInteractor.save(account) saveAccountInteractor.save(account)
} }
......
...@@ -25,18 +25,18 @@ interface LoginOptionsView : LoadingView, MessageView { ...@@ -25,18 +25,18 @@ interface LoginOptionsView : LoadingView, MessageView {
fun setupFacebookButtonListener(facebookOauthUrl: String, state: String) fun setupFacebookButtonListener(facebookOauthUrl: String, state: String)
/** /**
* Shows the "login by Github" view if it is enabled by the server settings. * Shows the "login by GitHub" view if it is enabled by the server settings.
* *
* REMARK: We must set up the Github button listener before enabling it * REMARK: We must set up the GitHub button listener before enabling it
* [setupGithubButtonListener]. * [setupGithubButtonListener].
* @see [showAccountsView] * @see [showAccountsView]
*/ */
fun enableLoginByGithub() fun enableLoginByGithub()
/** /**
* Setups the Github button. * Setups the GitHub button.
* *
* @param githubUrl The Github OAuth URL to authenticate with. * @param githubUrl The GitHub OAuth URL to authenticate with.
* @param state A random string generated by the app, which you'll verify later * @param state A random string generated by the app, which you'll verify later
* (to protect against forgery attacks). * (to protect against forgery attacks).
*/ */
...@@ -61,36 +61,36 @@ interface LoginOptionsView : LoadingView, MessageView { ...@@ -61,36 +61,36 @@ interface LoginOptionsView : LoadingView, MessageView {
fun setupGoogleButtonListener(googleUrl: String, state: String) fun setupGoogleButtonListener(googleUrl: String, state: String)
/** /**
* Shows the "login by Linkedin" view if it is enabled by the server settings. * Shows the "login by LinkedIn" view if it is enabled by the server settings.
* *
* REMARK: We must set up the Linkedin button listener before enabling it * REMARK: We must set up the LinkedIn button listener before enabling it
* [setupLinkedinButtonListener]. * [setupLinkedinButtonListener].
* @see [showAccountsView] * @see [showAccountsView]
*/ */
fun enableLoginByLinkedin() fun enableLoginByLinkedin()
/** /**
* Setups the Linkedin button. * Setups the LinkedIn button.
* *
* @param linkedinUrl The Linkedin OAuth URL to authenticate with. * @param linkedinUrl The LinkedIn OAuth URL to authenticate with.
* @param state A random string generated by the app, which you'll verify later * @param state A random string generated by the app, which you'll verify later
* (to protect against forgery attacks). * (to protect against forgery attacks).
*/ */
fun setupLinkedinButtonListener(linkedinUrl: String, state: String) fun setupLinkedinButtonListener(linkedinUrl: String, state: String)
/** /**
* Shows the "login by Gitlab" view if it is enabled by the server settings. * Shows the "login by GitLab" view if it is enabled by the server settings.
* *
* REMARK: We must set up the Gitlab button listener before enabling it * REMARK: We must set up the GitLab button listener before enabling it
* [setupGitlabButtonListener]. * [setupGitlabButtonListener].
* @see [showAccountsView] * @see [showAccountsView]
*/ */
fun enableLoginByGitlab() fun enableLoginByGitlab()
/** /**
* Setups the Gitlab button. * Setups the GitLab button.
* *
* @param gitlabUrl The Gitlab OAuth URL to authenticate with. * @param gitlabUrl The GitLab OAuth URL to authenticate with.
* @param state A random string generated by the app, which you'll verify later * @param state A random string generated by the app, which you'll verify later
* (to protect against forgery attacks). * (to protect against forgery attacks).
*/ */
...@@ -99,7 +99,7 @@ interface LoginOptionsView : LoadingView, MessageView { ...@@ -99,7 +99,7 @@ interface LoginOptionsView : LoadingView, MessageView {
/** /**
* Shows the "login by WordPress" view if it is enabled by the server settings. * Shows the "login by WordPress" view if it is enabled by the server settings.
* *
* REMARK: We must set up the Gitlab button listener before enabling it [setupWordpressButtonListener]. * REMARK: We must set up the GitLab button listener before enabling it [setupWordpressButtonListener].
*/ */
fun enableLoginByWordpress() fun enableLoginByWordpress()
......
...@@ -7,11 +7,11 @@ import chat.rocket.android.server.domain.GetAccountsInteractor ...@@ -7,11 +7,11 @@ import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.RefreshSettingsInteractor import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.domain.SaveConnectingServerInteractor import chat.rocket.android.server.domain.SaveConnectingServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import kotlinx.coroutines.experimental.DefaultDispatcher import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
class OnBoardingPresenter @Inject constructor( class OnBoardingPresenter @Inject constructor(
...@@ -19,7 +19,7 @@ class OnBoardingPresenter @Inject constructor( ...@@ -19,7 +19,7 @@ class OnBoardingPresenter @Inject constructor(
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator, private val navigator: AuthenticationNavigator,
private val serverInteractor: SaveConnectingServerInteractor, private val serverInteractor: SaveConnectingServerInteractor,
private val refreshSettingsInteractor: RefreshSettingsInteractor, refreshSettingsInteractor: RefreshSettingsInteractor,
private val getAccountsInteractor: GetAccountsInteractor, private val getAccountsInteractor: GetAccountsInteractor,
val settingsInteractor: GetSettingsInteractor, val settingsInteractor: GetSettingsInteractor,
val factory: RocketChatClientFactory val factory: RocketChatClientFactory
...@@ -80,7 +80,7 @@ class OnBoardingPresenter @Inject constructor( ...@@ -80,7 +80,7 @@ class OnBoardingPresenter @Inject constructor(
} }
view.showLoading() view.showLoading()
try { try {
withContext(DefaultDispatcher) { withContext(Dispatchers.Default) {
setupConnectionInfo(serverUrl) setupConnectionInfo(serverUrl)
// preparing next fragment before showing it // preparing next fragment before showing it
......
...@@ -12,8 +12,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor ...@@ -12,8 +12,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.serverLogoUrl import chat.rocket.android.util.extensions.serverLogoUrl
...@@ -38,8 +39,9 @@ class RegisterUsernamePresenter @Inject constructor( ...@@ -38,8 +39,9 @@ class RegisterUsernamePresenter @Inject constructor(
val settingsInteractor: GetSettingsInteractor val settingsInteractor: GetSettingsInteractor
) { ) {
private val currentServer = serverInteractor.get()!! private val currentServer = serverInteractor.get()!!
private val client: RocketChatClient = factory.create(currentServer) private val client: RocketChatClient = factory.get(currentServer)
private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!) private var settings: PublicSettings = settingsInteractor.get(currentServer)
private val token = tokenRepository.get(currentServer)
fun registerUsername(username: String, userId: String, authToken: String) { fun registerUsername(username: String, userId: String, authToken: String) {
launchUI(strategy) { launchUI(strategy) {
...@@ -72,15 +74,22 @@ class RegisterUsernamePresenter @Inject constructor( ...@@ -72,15 +74,22 @@ class RegisterUsernamePresenter @Inject constructor(
} }
} }
private suspend fun saveAccount(username: String) { private fun saveAccount(username: String) {
val icon = settings.favicon()?.let { val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val logo = settings.wideTile()?.let { val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val thumb = currentServer.avatarUrl(username) val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val account = Account(currentServer, icon, logo, username, thumb) val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
username,
thumb
)
saveAccountInteractor.save(account) saveAccountInteractor.save(account)
} }
} }
\ No newline at end of file
...@@ -31,12 +31,10 @@ import javax.inject.Inject ...@@ -31,12 +31,10 @@ import javax.inject.Inject
private const val BUNDLE_USER_ID = "user_id" private const val BUNDLE_USER_ID = "user_id"
private const val BUNDLE_AUTH_TOKEN = "auth_token" private const val BUNDLE_AUTH_TOKEN = "auth_token"
fun newInstance(userId: String, authToken: String): Fragment { fun newInstance(userId: String, authToken: String): Fragment = RegisterUsernameFragment().apply {
return RegisterUsernameFragment().apply { arguments = Bundle(2).apply {
arguments = Bundle(2).apply { putString(BUNDLE_USER_ID, userId)
putString(BUNDLE_USER_ID, userId) putString(BUNDLE_AUTH_TOKEN, authToken)
putString(BUNDLE_AUTH_TOKEN, authToken)
}
} }
} }
...@@ -53,13 +51,10 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView { ...@@ -53,13 +51,10 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
val bundle = arguments arguments?.run {
if (bundle != null) { userId = getString(BUNDLE_USER_ID, "")
userId = bundle.getString(BUNDLE_USER_ID) authToken = getString(BUNDLE_AUTH_TOKEN, "")
authToken = bundle.getString(BUNDLE_AUTH_TOKEN) } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
} }
override fun onCreateView( override fun onCreateView(
...@@ -145,7 +140,7 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView { ...@@ -145,7 +140,7 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_20dp, it) val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_20dp, it)
DrawableHelper.wrapDrawable(atDrawable) DrawableHelper.wrapDrawable(atDrawable)
DrawableHelper.tintDrawable(atDrawable, it, R.color.colorDrawableTintGrey) DrawableHelper.tintDrawable(atDrawable, it, R.color.colorDrawableTintGrey)
DrawableHelper.compoundDrawable(text_username, atDrawable) DrawableHelper.compoundStartDrawable(text_username, atDrawable)
} }
} }
......
...@@ -21,7 +21,7 @@ interface ResetPasswordView : LoadingView, MessageView { ...@@ -21,7 +21,7 @@ interface ResetPasswordView : LoadingView, MessageView {
fun enableButtonConnect() fun enableButtonConnect()
/** /**
* Disables the button to reset the password when the user entered an invalid email address * Disables the button to reset the password when the user has entered an invalid email address
*/ */
fun disableButtonConnect() fun disableButtonConnect()
} }
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment