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

Feature/attachments #619

Merged
merged 23 commits into from
Oct 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3073470
Attachments: start working on new UI (using system file picker) [WIP]
ganfra Oct 8, 2019
0a9ebb6
Attachments: use a lib which handles for us all the intent stuff.
ganfra Oct 9, 2019
6e39164
Sharing: start handling incoming share [WIP]
ganfra Oct 9, 2019
ae5b6bd
Attachments/Sharing: refact a bit and handle more data.
ganfra Oct 10, 2019
2069635
Attachments: try to improve a bit the UI and adding options [WIP]
ganfra Oct 10, 2019
ee5ebb4
Attachments: get better layout
ganfra Oct 11, 2019
0ca8696
Attachments/Share: cleaning code and add contact picking
ganfra Oct 11, 2019
13a5f78
Merge branch 'develop' into feature/attachments
ganfra Oct 11, 2019
679b0ff
Use klint and update CHANGES
ganfra Oct 11, 2019
c28be6a
Fix code quality check
ganfra Oct 11, 2019
3c3c6ae
Removes the RoomList handling from a viewmodel as it doesn't have a V…
ganfra Oct 15, 2019
6cd0452
Clean after Benoit's review
ganfra Oct 15, 2019
a1a71e2
App state: fix session
ganfra Oct 16, 2019
05a069b
Attachments: fix themes for selection view
ganfra Oct 16, 2019
9e43648
Use klint
ganfra Oct 16, 2019
8e3234d
Clean some code
ganfra Oct 21, 2019
2c8cd89
Handle rich content from app (WIP not compiling)
ganfra Oct 21, 2019
c7a4d34
Attachments: handle rich content from keyboard
ganfra Oct 22, 2019
7388a40
Permissions: allow to provide the rationale message as it requires "c…
ganfra Oct 22, 2019
2974f8b
Merge branch 'develop' into feature/attachments
ganfra Oct 22, 2019
6d55c15
Fix lint issue
ganfra Oct 22, 2019
dbc17ae
Use AppCompatEditText instead of EditText
bmarty Oct 22, 2019
cac5fb7
Code cleanup
bmarty Oct 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@
/tmp

ktlint
.idea/copyright/New_vector.xml
.idea/copyright/profiles_settings.xml
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Improvements:
- Persist active tab between sessions (#503)
- Do not upload file too big for the homeserver (#587)
- Handle read markers (#84)
- Attachments: start using system pickers (#52)
- Attachments: start handling incoming share (#58)
- Mark all messages as read (#396)
- Add ability to report content (#515)

Expand Down
2 changes: 1 addition & 1 deletion vector/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ dependencies {
implementation 'me.leolin:ShortcutBadger:1.1.22@aar'

// File picker
implementation 'com.github.jaiselrahman:FilePicker:1.2.2'
implementation 'com.kbeanie:multipicker:1.6@aar'

// DI
implementation "com.google.dagger:dagger:$daggerVersion"
Expand Down
17 changes: 17 additions & 0 deletions vector/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package="im.vector.riotx">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

<application
android:name=".VectorApplication"
Expand Down Expand Up @@ -79,6 +80,22 @@
</intent-filter>
</activity>

<activity android:name=".features.share.IncomingShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.OPENABLE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<data android:mimeType="*/*" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.OPENABLE" />
</intent-filter>
</activity>
<!-- Services -->

<service
Expand Down
10 changes: 5 additions & 5 deletions vector/src/main/assets/open_source_licenses.html
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,6 @@ <h3>
<br/>
Copyright 2014 Leo Lin
</li>
<li>
<b>FilePicker</b>
<br/>
Copyright (c) 2018, Jaisel Rahman
</li>
<li>
<b>diff-match-patch</b>
<br/>
Expand All @@ -359,6 +354,11 @@ <h3>
<br/>
Copyright 2017 Gabriel Ittner.
</li>
<li>
<b>Android-multipicker-library</b>
<br/>
Copyright 2018 Kumar Bibek
</li>
</ul>
<pre>
Apache License
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package im.vector.riotx

import arrow.core.Option
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.core.utils.RxStore
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ActiveSessionObservableStore @Inject constructor() : RxStore<Option<Session>>()
Original file line number Diff line number Diff line change
Expand Up @@ -14,56 +14,59 @@
* limitations under the License.
*/

package im.vector.riotx.features.home
package im.vector.riotx

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import arrow.core.Option
import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.group.model.GroupSummary
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.rx.rx
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.features.home.HomeRoomListObservableStore
import im.vector.riotx.features.home.group.ALL_COMMUNITIES_GROUP_ID
import im.vector.riotx.features.home.group.SelectedGroupStore
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.BiFunction
import io.reactivex.rxkotlin.addTo
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton

data class EmptyState(val isEmpty: Boolean = true) : MvRxState

class HomeActivityViewModel @AssistedInject constructor(@Assisted initialState: EmptyState,
private val session: Session,
private val selectedGroupStore: SelectedGroupStore,
private val homeRoomListStore: HomeRoomListObservableStore
) : VectorViewModel<EmptyState>(initialState) {

@AssistedInject.Factory
interface Factory {
fun create(initialState: EmptyState): HomeActivityViewModel
}
/**
* This class handles the global app state. At the moment, it only manages room list.
* It requires to be added to ProcessLifecycleOwner.get().lifecycle
*/
@Singleton
class AppStateHandler @Inject constructor(
private val sessionObservableStore: ActiveSessionObservableStore,
private val homeRoomListStore: HomeRoomListObservableStore,
private val selectedGroupStore: SelectedGroupStore) : LifecycleObserver {

companion object : MvRxViewModelFactory<HomeActivityViewModel, EmptyState> {
private val compositeDisposable = CompositeDisposable()

@JvmStatic
override fun create(viewModelContext: ViewModelContext, state: EmptyState): HomeActivityViewModel? {
val homeActivity: HomeActivity = (viewModelContext as ActivityViewModelContext).activity()
return homeActivity.homeActivityViewModelFactory.create(state)
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun entersForeground() {
observeRoomsAndGroup()
}

init {
observeRoomAndGroup()
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun entersBackground() {
compositeDisposable.clear()
}

private fun observeRoomAndGroup() {
private fun observeRoomsAndGroup() {
Observable
.combineLatest<List<RoomSummary>, Option<GroupSummary>, List<RoomSummary>>(
session.rx().liveRoomSummaries().throttleLast(300, TimeUnit.MILLISECONDS),
sessionObservableStore.observe()
.observeOn(AndroidSchedulers.mainThread())
.switchMap {
it.orNull()?.rx()?.liveRoomSummaries()
?: Observable.just(emptyList())
}
.throttleLast(300, TimeUnit.MILLISECONDS),
selectedGroupStore.observe(),
BiFunction { rooms, selectedGroupOption ->
val selectedGroup = selectedGroupOption.orNull()
Expand All @@ -83,14 +86,14 @@ class HomeActivityViewModel @AssistedInject constructor(@Assisted initialState:
.filter { !it.isDirect }
.filter {
selectedGroup?.groupId == ALL_COMMUNITIES_GROUP_ID
|| selectedGroup?.roomIds?.contains(it.roomId) ?: true
|| selectedGroup?.roomIds?.contains(it.roomId) ?: true
}
filteredDirectRooms + filteredGroupRooms
}
)
.subscribe {
homeRoomListStore.post(it)
}
.disposeOnClear()
.addTo(compositeDisposable)
}
}
2 changes: 2 additions & 0 deletions vector/src/main/java/im/vector/riotx/VectorApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
@Inject lateinit var vectorPreferences: VectorPreferences
@Inject lateinit var versionProvider: VersionProvider
@Inject lateinit var notificationUtils: NotificationUtils
@Inject lateinit var appStateHandler: AppStateHandler
lateinit var vectorComponent: VectorComponent
private var fontThreadHandler: Handler? = null

Expand Down Expand Up @@ -134,6 +135,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
FcmHelper.onEnterBackground(appContext, vectorPreferences, activeSessionHolder)
}
})
ProcessLifecycleOwner.get().lifecycle.addObserver(appStateHandler)
// This should be done as early as possible
initKnownEmojiHashSet(appContext)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

package im.vector.riotx.core.di

import arrow.core.Option
import im.vector.matrix.android.api.auth.Authenticator
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.ActiveSessionObservableStore
import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler
import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler
import java.util.concurrent.atomic.AtomicReference
Expand All @@ -26,6 +28,7 @@ import javax.inject.Singleton

@Singleton
class ActiveSessionHolder @Inject constructor(private val authenticator: Authenticator,
private val sessionObservableStore: ActiveSessionObservableStore,
private val keyRequestHandler: KeyRequestHandler,
private val incomingVerificationRequestHandler: IncomingVerificationRequestHandler
) {
Expand All @@ -34,12 +37,14 @@ class ActiveSessionHolder @Inject constructor(private val authenticator: Authent

fun setActiveSession(session: Session) {
activeSession.set(session)
sessionObservableStore.post(Option.fromNullable(session))
keyRequestHandler.start(session)
incomingVerificationRequestHandler.start(session)
}

fun clearActiveSession() {
activeSession.set(null)
sessionObservableStore.post(Option.empty())
keyRequestHandler.stop()
incomingVerificationRequestHandler.stop()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import im.vector.riotx.features.roomdirectory.picker.RoomDirectoryPickerFragment
import im.vector.riotx.features.roomdirectory.roompreview.RoomPreviewNoPreviewFragment
import im.vector.riotx.features.settings.*
import im.vector.riotx.features.settings.push.PushGatewaysFragment
import im.vector.riotx.features.share.IncomingShareActivity
import im.vector.riotx.features.ui.UiStateRepository

@Component(dependencies = [VectorComponent::class], modules = [AssistedInjectModule::class, ViewModelModule::class, HomeModule::class])
Expand Down Expand Up @@ -183,6 +184,8 @@ interface ScreenComponent {

fun inject(reactionButton: ReactionButton)

fun inject(incomingShareActivity: IncomingShareActivity)

@Component.Factory
interface Factory {
fun create(vectorComponent: VectorComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,10 @@ fun EditText.showPassword(visible: Boolean, updateCursor: Boolean = true) {
}
if (updateCursor) setSelection(text?.length ?: 0)
}

fun View.getMeasurements(): Pair<Int, Int> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a data class to avoid using generic pair? (give sense to first and second)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a utility method, I don't think it's worth it

measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
val width = measuredWidth
val height = measuredHeight
return width to height
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.riotx.core.utils

import android.app.Activity
import android.graphics.Rect
import android.view.View
import android.view.ViewTreeObserver

class KeyboardStateUtils(activity: Activity) : ViewTreeObserver.OnGlobalLayoutListener {

private val contentView: View = activity.findViewById<View>(android.R.id.content).also {
it.viewTreeObserver.addOnGlobalLayoutListener(this)
}
var isKeyboardShowing: Boolean = false
private set

override fun onGlobalLayout() {
val rect = Rect()
contentView.getWindowVisibleDisplayFrame(rect)
val screenHeight = contentView.rootView.height

val keypadHeight = screenHeight - rect.bottom
isKeyboardShowing = keypadHeight > screenHeight * 0.15
}
}
Loading