Reformatting

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2019-10-17 13:12:29 +02:00
parent 8441fd2475
commit fd44934b98
234 changed files with 18720 additions and 17790 deletions

View File

@ -47,102 +47,111 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
open class BaseActivity : AppCompatActivity() { open class BaseActivity : AppCompatActivity() {
@Inject @Inject
lateinit var eventBus: EventBus lateinit var eventBus: EventBus
@Inject @Inject
lateinit var appPreferences: AppPreferences lateinit var appPreferences: AppPreferences
@Inject @Inject
lateinit var context: Context lateinit var context: Context
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
}
public override fun onResume() {
super.onResume()
if (appPreferences.isScreenSecured) {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
} }
public override fun onResume() { if (appPreferences.isScreenLocked) {
super.onResume() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (appPreferences.isScreenSecured) { SecurityUtils.createKey(appPreferences.screenLockTimeout)
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE) }
} else { }
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) }
fun showCertificateDialog(
cert: X509Certificate,
magicTrustManager: MagicTrustManager,
sslErrorHandler: SslErrorHandler?
) {
val formatter = DateFormat.getDateInstance(DateFormat.LONG)
val validFrom = formatter.format(cert.notBefore)
val validUntil = formatter.format(cert.notAfter)
val issuedBy = cert.issuerDN.toString()
val issuedFor: String
try {
if (cert.subjectAlternativeNames != null) {
val stringBuilder = StringBuilder()
for (o in cert.subjectAlternativeNames) {
val list = o as List<*>
val type = list[0] as Int
if (type == 2) {
val name = list[1] as String
stringBuilder.append("[")
.append(type)
.append("]")
.append(name)
.append(" ")
}
} }
issuedFor = stringBuilder.toString()
} else {
issuedFor = cert.subjectDN.name
}
if (appPreferences.isScreenLocked) { @SuppressLint("StringFormatMatches") val dialogText = String.format(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { resources
SecurityUtils.createKey(appPreferences.screenLockTimeout) .getString(R.string.nc_certificate_dialog_text),
} issuedBy, issuedFor, validFrom, validUntil
} )
LovelyStandardDialog(this)
.setTopColorRes(R.color.nc_darkRed)
.setNegativeButtonColorRes(R.color.nc_darkRed)
.setPositiveButtonColorRes(R.color.colorPrimaryDark)
.setIcon(R.drawable.ic_security_white_24dp)
.setTitle(R.string.nc_certificate_dialog_title)
.setMessage(dialogText)
.setPositiveButton(R.string.nc_yes) { v ->
magicTrustManager.addCertInTrustStore(cert)
sslErrorHandler?.proceed()
}
.setNegativeButton(R.string.nc_no) { view1 ->
sslErrorHandler?.cancel()
}
.show()
} catch (e: CertificateParsingException) {
Log.d(TAG, "Failed to parse the certificate")
} }
fun showCertificateDialog(cert: X509Certificate, magicTrustManager: MagicTrustManager, }
sslErrorHandler: SslErrorHandler?) {
val formatter = DateFormat.getDateInstance(DateFormat.LONG)
val validFrom = formatter.format(cert.notBefore)
val validUntil = formatter.format(cert.notAfter)
val issuedBy = cert.issuerDN.toString() @Subscribe(threadMode = ThreadMode.MAIN)
val issuedFor: String fun onMessageEvent(event: CertificateEvent) {
showCertificateDialog(event.x509Certificate, event.magicTrustManager, event.sslErrorHandler)
}
try { public override fun onStart() {
if (cert.subjectAlternativeNames != null) { super.onStart()
val stringBuilder = StringBuilder() eventBus.register(this)
for (o in cert.subjectAlternativeNames) { }
val list = o as List<*>
val type = list[0] as Int
if (type == 2) {
val name = list[1] as String
stringBuilder.append("[").append(type).append("]").append(name).append(" ")
}
}
issuedFor = stringBuilder.toString()
} else {
issuedFor = cert.subjectDN.name
}
@SuppressLint("StringFormatMatches") val dialogText = String.format(resources public override fun onStop() {
.getString(R.string.nc_certificate_dialog_text), super.onStop()
issuedBy, issuedFor, validFrom, validUntil) eventBus.unregister(this)
}
LovelyStandardDialog(this) companion object {
.setTopColorRes(R.color.nc_darkRed) private val TAG = "BaseActivity"
.setNegativeButtonColorRes(R.color.nc_darkRed) }
.setPositiveButtonColorRes(R.color.colorPrimaryDark)
.setIcon(R.drawable.ic_security_white_24dp)
.setTitle(R.string.nc_certificate_dialog_title)
.setMessage(dialogText)
.setPositiveButton(R.string.nc_yes) { v ->
magicTrustManager.addCertInTrustStore(cert)
sslErrorHandler?.proceed()
}
.setNegativeButton(R.string.nc_no) { view1 ->
sslErrorHandler?.cancel()
}
.show()
} catch (e: CertificateParsingException) {
Log.d(TAG, "Failed to parse the certificate")
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: CertificateEvent) {
showCertificateDialog(event.x509Certificate, event.magicTrustManager, event.sslErrorHandler)
}
public override fun onStart() {
super.onStart()
eventBus.register(this)
}
public override fun onStop() {
super.onStop()
eventBus.unregister(this)
}
companion object {
private val TAG = "BaseActivity"
}
} }

View File

@ -43,54 +43,60 @@ import com.nextcloud.talk.utils.bundle.BundleKeys
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class MagicCallActivity : BaseActivity() { class MagicCallActivity : BaseActivity() {
@BindView(R.id.controller_container) @BindView(R.id.controller_container)
lateinit var container: ViewGroup lateinit var container: ViewGroup
private var router: Router? = null private var router: Router? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
requestWindowFeature(Window.FEATURE_NO_TITLE) requestWindowFeature(Window.FEATURE_NO_TITLE)
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN or window.addFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or WindowManager.LayoutParams.FLAG_FULLSCREEN or
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
window.decorView.systemUiVisibility = systemUiVisibility WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
)
window.decorView.systemUiVisibility = systemUiVisibility
setContentView(R.layout.activity_magic_call) setContentView(R.layout.activity_magic_call)
ButterKnife.bind(this) ButterKnife.bind(this)
router = Conductor.attachRouter(this, container, savedInstanceState) router = Conductor.attachRouter(this, container, savedInstanceState)
router!!.setPopsLastView(false) router!!.setPopsLastView(false)
if (!router!!.hasRootController()) { if (!router!!.hasRootController()) {
if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) { if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
router!!.setRoot(RouterTransaction.with(CallNotificationController(intent.extras)) router!!.setRoot(
.pushChangeHandler(HorizontalChangeHandler()) RouterTransaction.with(CallNotificationController(intent.extras))
.popChangeHandler(HorizontalChangeHandler())) .pushChangeHandler(HorizontalChangeHandler())
} else { .popChangeHandler(HorizontalChangeHandler())
router!!.setRoot(RouterTransaction.with(CallController(intent.extras)) )
.pushChangeHandler(HorizontalChangeHandler()) } else {
.popChangeHandler(HorizontalChangeHandler())) router!!.setRoot(
} RouterTransaction.with(CallController(intent.extras))
} .pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
}
} }
}
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
eventBus.post(ConfigurationChangeEvent()) eventBus.post(ConfigurationChangeEvent())
} }
companion object { companion object {
private val TAG = "MagicCallActivity" private val TAG = "MagicCallActivity"
private val systemUiVisibility: Int private val systemUiVisibility: Int
get() { get() {
var flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN var flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN
flags = flags or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY flags = flags or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
return flags return flags
} }
} }
} }

View File

@ -39,7 +39,6 @@ import com.google.android.material.appbar.MaterialToolbar
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.controllers.CallNotificationController import com.nextcloud.talk.controllers.CallNotificationController
import com.nextcloud.talk.controllers.ConversationsListController
import com.nextcloud.talk.controllers.LockedController import com.nextcloud.talk.controllers.LockedController
import com.nextcloud.talk.controllers.ServerSelectionController import com.nextcloud.talk.controllers.ServerSelectionController
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
@ -56,117 +55,129 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class MainActivity : BaseActivity(), ActionBarProvider { class MainActivity : BaseActivity(), ActionBarProvider {
@BindView(R.id.toolbar) @BindView(R.id.toolbar)
lateinit var toolbar: MaterialToolbar lateinit var toolbar: MaterialToolbar
@BindView(R.id.controller_container) @BindView(R.id.controller_container)
lateinit var container: ViewGroup lateinit var container: ViewGroup
@Inject @Inject
lateinit var userUtils: UserUtils lateinit var userUtils: UserUtils
@Inject @Inject
lateinit var dataStore: ReactiveEntityStore<Persistable> lateinit var dataStore: ReactiveEntityStore<Persistable>
@Inject @Inject
lateinit var sqlCipherDatabaseSource: SqlCipherDatabaseSource lateinit var sqlCipherDatabaseSource: SqlCipherDatabaseSource
private var router: Router? = null private var router: Router? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
ButterKnife.bind(this) ButterKnife.bind(this)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
router = Conductor.attachRouter(this, container, savedInstanceState) router = Conductor.attachRouter(this, container, savedInstanceState)
var hasDb = true var hasDb = true
try { try {
sqlCipherDatabaseSource.writableDatabase sqlCipherDatabaseSource.writableDatabase
} catch (exception: Exception) { } catch (exception: Exception) {
hasDb = false hasDb = false
}
if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
if (!router!!.hasRootController()) {
router!!.setRoot(RouterTransaction.with(ConversationsListView())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
}
onNewIntent(intent)
} else if (!router!!.hasRootController()) {
if (hasDb) {
if (userUtils.anyUserExists()) {
router!!.setRoot(RouterTransaction.with(ConversationsListView())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
} else {
router!!.setRoot(RouterTransaction.with(ServerSelectionController())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
}
} else {
router!!.setRoot(RouterTransaction.with(ServerSelectionController())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
}
}
} }
override fun onStart() { if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
super.onStart() if (!router!!.hasRootController()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { router!!.setRoot(
checkIfWeAreSecure() RouterTransaction.with(ConversationsListView())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
}
onNewIntent(intent)
} else if (!router!!.hasRootController()) {
if (hasDb) {
if (userUtils.anyUserExists()) {
router!!.setRoot(
RouterTransaction.with(ConversationsListView())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} else {
router!!.setRoot(
RouterTransaction.with(ServerSelectionController())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} }
} else {
router!!.setRoot(
RouterTransaction.with(ServerSelectionController())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
}
}
}
override fun onStart() {
super.onStart()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkIfWeAreSecure()
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
fun checkIfWeAreSecure() {
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
if (keyguardManager.isKeyguardSecure && appPreferences.isScreenLocked) {
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
if (router != null && router!!.getControllerWithTag(LockedController.TAG) == null) {
router!!.pushController(
RouterTransaction.with(LockedController())
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
.tag(LockedController.TAG)
)
}
}
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
router!!.pushController(
RouterTransaction.with(CallNotificationController(intent.extras))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} else {
ConductorRemapping.remapChatController(
router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1),
intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN), intent.extras!!, false
)
}
}
}
override fun onBackPressed() {
if (router!!.getControllerWithTag(LockedController.TAG) != null) {
return
} }
if (!router!!.handleBack()) {
@RequiresApi(api = Build.VERSION_CODES.M) super.onBackPressed()
fun checkIfWeAreSecure() {
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
if (keyguardManager.isKeyguardSecure && appPreferences.isScreenLocked) {
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
if (router != null && router!!.getControllerWithTag(LockedController.TAG) == null) {
router!!.pushController(RouterTransaction.with(LockedController())
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
.tag(LockedController.TAG))
}
}
}
} }
}
companion object {
override fun onNewIntent(intent: Intent) { private val TAG = "MainActivity"
super.onNewIntent(intent) }
if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
router!!.pushController(RouterTransaction.with(CallNotificationController(intent.extras))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
} else {
ConductorRemapping.remapChatController(router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1),
intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN), intent.extras!!, false)
}
}
}
override fun onBackPressed() {
if (router!!.getControllerWithTag(LockedController.TAG) != null) {
return
}
if (!router!!.handleBack()) {
super.onBackPressed()
}
}
companion object {
private val TAG = "MainActivity"
}
} }

View File

@ -48,126 +48,134 @@ import eu.davidea.viewholders.FlexibleViewHolder;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.UserItemViewHolder> implements public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.UserItemViewHolder>
IFilterable<String> { implements
IFilterable<String> {
private Participant participant; private Participant participant;
private UserEntity userEntity; private UserEntity userEntity;
@Nullable @Nullable
private Account account; private Account account;
public AdvancedUserItem(Participant participant, UserEntity userEntity, @Nullable Account account) { public AdvancedUserItem(Participant participant, UserEntity userEntity,
this.participant = participant; @Nullable Account account) {
this.userEntity = userEntity; this.participant = participant;
this.account = account; this.userEntity = userEntity;
this.account = account;
}
@Override
public boolean equals(Object o) {
if (o instanceof AdvancedUserItem) {
AdvancedUserItem inItem = (AdvancedUserItem) o;
return participant.equals(inItem.getModel());
}
return false;
}
@Override
public int hashCode() {
return participant.hashCode();
}
/**
* @return the model object
*/
public Participant getModel() {
return participant;
}
public UserEntity getEntity() {
return userEntity;
}
@Nullable
public Account getAccount() {
return account;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_conversation;
}
@Override
public UserItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new UserItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position,
List payloads) {
holder.avatarImageView.setController(null);
if (adapter.hasFilter()) {
FlexibleUtils.highlightText(holder.contactDisplayName, participant.getName(),
String.valueOf(adapter.getFilter(String.class)),
NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.colorPrimary));
} else {
holder.contactDisplayName.setText(participant.getName());
} }
@Override holder.serverUrl.setText(userEntity.getBaseUrl());
public boolean equals(Object o) {
if (o instanceof AdvancedUserItem) {
AdvancedUserItem inItem = (AdvancedUserItem) o;
return participant.equals(inItem.getModel());
}
return false;
}
@Override if (userEntity != null && userEntity.getBaseUrl() != null && userEntity.getBaseUrl()
public int hashCode() { .startsWith("http://") || userEntity.getBaseUrl().startsWith("https://")) {
return participant.hashCode(); holder.avatarImageView.setVisibility(View.VISIBLE);
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.avatarImageView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
participant.getUserId(), R.dimen.avatar_size), null))
.build();
holder.avatarImageView.setController(draweeController);
} else {
holder.avatarImageView.setVisibility(View.GONE);
RelativeLayout.LayoutParams layoutParams =
(RelativeLayout.LayoutParams) holder.linearLayout.getLayoutParams();
layoutParams.setMarginStart(
(int) NextcloudTalkApplication.Companion.getSharedApplication().getApplicationContext()
.getResources().getDimension(R.dimen.activity_horizontal_margin));
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_START);
holder.linearLayout.setLayoutParams(layoutParams);
} }
}
@Override
public boolean filter(String constraint) {
return participant.getName() != null &&
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
.matcher(participant.getName().trim())
.find();
}
static class UserItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.name_text)
public EmojiTextView contactDisplayName;
@BindView(R.id.secondary_text)
public TextView serverUrl;
@BindView(R.id.avatar_image)
public SimpleDraweeView avatarImageView;
@BindView(R.id.linear_layout)
LinearLayout linearLayout;
@BindView(R.id.more_menu)
ImageButton moreMenuButton;
@BindView(R.id.password_protected_image_view)
ImageView passwordProtectedImageView;
/** /**
* @return the model object * Default constructor.
*/ */
UserItemViewHolder(View view, FlexibleAdapter adapter) {
public Participant getModel() { super(view, adapter);
return participant; ButterKnife.bind(this, view);
} moreMenuButton.setVisibility(View.GONE);
passwordProtectedImageView.setVisibility(View.GONE);
public UserEntity getEntity() {
return userEntity;
}
@Nullable
public Account getAccount() {
return account;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_conversation;
}
@Override
public UserItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new UserItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) {
holder.avatarImageView.setController(null);
if (adapter.hasFilter()) {
FlexibleUtils.highlightText(holder.contactDisplayName, participant.getName(),
String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.colorPrimary));
} else {
holder.contactDisplayName.setText(participant.getName());
}
holder.serverUrl.setText(userEntity.getBaseUrl());
if (userEntity != null && userEntity.getBaseUrl() != null && userEntity.getBaseUrl().startsWith("http://") || userEntity.getBaseUrl().startsWith("https://")) {
holder.avatarImageView.setVisibility(View.VISIBLE);
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.avatarImageView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
participant.getUserId(), R.dimen.avatar_size), null))
.build();
holder.avatarImageView.setController(draweeController);
} else {
holder.avatarImageView.setVisibility(View.GONE);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) holder.linearLayout.getLayoutParams();
layoutParams.setMarginStart((int) NextcloudTalkApplication.Companion.getSharedApplication().getApplicationContext()
.getResources().getDimension(R.dimen.activity_horizontal_margin));
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_START);
holder.linearLayout.setLayoutParams(layoutParams);
}
}
@Override
public boolean filter(String constraint) {
return participant.getName() != null &&
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getName().trim()).find();
}
static class UserItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.name_text)
public EmojiTextView contactDisplayName;
@BindView(R.id.secondary_text)
public TextView serverUrl;
@BindView(R.id.avatar_image)
public SimpleDraweeView avatarImageView;
@BindView(R.id.linear_layout)
LinearLayout linearLayout;
@BindView(R.id.more_menu)
ImageButton moreMenuButton;
@BindView(R.id.password_protected_image_view)
ImageView passwordProtectedImageView;
/**
* Default constructor.
*/
UserItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
moreMenuButton.setVisibility(View.GONE);
passwordProtectedImageView.setVisibility(View.GONE);
}
} }
}
} }

View File

@ -39,86 +39,89 @@ import eu.davidea.viewholders.FlexibleViewHolder;
import java.util.List; import java.util.List;
public class AppItem extends AbstractFlexibleItem<AppItem.AppItemViewHolder> { public class AppItem extends AbstractFlexibleItem<AppItem.AppItemViewHolder> {
private String title; private String title;
private String packageName; private String packageName;
private String name; private String name;
@Nullable @Nullable
private Drawable drawable; private Drawable drawable;
public AppItem(String title, String packageName, String name, @Nullable Drawable drawable) { public AppItem(String title, String packageName, String name, @Nullable Drawable drawable) {
this.title = title; this.title = title;
this.packageName = packageName; this.packageName = packageName;
this.name = name; this.name = name;
this.drawable = drawable; this.drawable = drawable;
}
@Override
public boolean equals(Object o) {
if (o instanceof AppItem) {
AppItem inItem = (AppItem) o;
return title.equals(inItem.getTitle())
&& packageName.equals(inItem.getPackageName())
&& name.equals(inItem
.getName());
} }
@Override return false;
public boolean equals(Object o) { }
if (o instanceof AppItem) {
AppItem inItem = (AppItem) o;
return title.equals(inItem.getTitle()) && packageName.equals(inItem.getPackageName()) && name.equals(inItem
.getName());
}
return false; public String getTitle() {
return title;
}
public String getPackageName() {
return packageName;
}
public String getName() {
return name;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_app;
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, AppItemViewHolder holder,
int position, List<Object> payloads) {
if (drawable != null) {
holder.iconImageView.setVisibility(View.VISIBLE);
holder.iconImageView.setImageDrawable(drawable);
} else {
holder.iconImageView.setVisibility(View.GONE);
} }
public String getTitle() { if (position == 0) {
return title; Spannable spannableString = new SpannableString(title);
spannableString.setSpan(
new ForegroundColorSpan(NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.grey_600)), 0,
spannableString.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
holder.appTitleTextView.setText(spannableString);
} else {
holder.appTitleTextView.setText(title);
} }
}
public String getPackageName() { @Override
return packageName; public AppItem.AppItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new AppItemViewHolder(view, adapter);
}
static class AppItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.icon_image_view)
public ImageView iconImageView;
@BindView(R.id.app_title_text_view)
public TextView appTitleTextView;
/**
* Default constructor.
*/
AppItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
} }
}
public String getName() {
return name;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_app;
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, AppItemViewHolder holder, int position, List<Object> payloads) {
if (drawable != null) {
holder.iconImageView.setVisibility(View.VISIBLE);
holder.iconImageView.setImageDrawable(drawable);
} else {
holder.iconImageView.setVisibility(View.GONE);
}
if (position == 0) {
Spannable spannableString = new SpannableString(title);
spannableString.setSpan(new ForegroundColorSpan(NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.grey_600)), 0,
spannableString.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
holder.appTitleTextView.setText(spannableString);
} else {
holder.appTitleTextView.setText(title);
}
}
@Override
public AppItem.AppItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new AppItemViewHolder(view, adapter);
}
static class AppItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.icon_image_view)
public ImageView iconImageView;
@BindView(R.id.app_title_text_view)
public TextView appTitleTextView;
/**
* Default constructor.
*/
AppItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
}
}
} }

View File

@ -48,138 +48,145 @@ import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder> implements IFilterable<String> { public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
implements IFilterable<String> {
private Conversation conversation; private Conversation conversation;
private UserEntity userEntity; private UserEntity userEntity;
public CallItem(Conversation conversation, UserEntity userEntity) { public CallItem(Conversation conversation, UserEntity userEntity) {
this.conversation = conversation; this.conversation = conversation;
this.userEntity = userEntity; this.userEntity = userEntity;
}
@Override
public boolean equals(Object o) {
if (o instanceof CallItem) {
CallItem inItem = (CallItem) o;
return conversation.equals(inItem.getModel());
}
return false;
}
@Override
public int hashCode() {
return conversation.hashCode();
}
/**
* @return the model object
*/
public Conversation getModel() {
return conversation;
}
/**
* Filter is applied to the model fields.
*/
@Override
public int getLayoutRes() {
return R.layout.rv_item_conversation;
}
@Override
public RoomItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new RoomItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(final FlexibleAdapter adapter, RoomItemViewHolder holder, int position,
List payloads) {
if (adapter.hasFilter()) {
FlexibleUtils.highlightText(holder.roomDisplayName, conversation.getDisplayName(),
String.valueOf(adapter.getFilter(String.class)),
NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.colorPrimary));
} else {
holder.roomDisplayName.setText(conversation.getDisplayName());
} }
@Override if (conversation.getLastPing() == 0) {
public boolean equals(Object o) { holder.roomLastPing.setText(R.string.nc_never);
if (o instanceof CallItem) { } else {
CallItem inItem = (CallItem) o; holder.roomLastPing.setText(
return conversation.equals(inItem.getModel()); DateUtils.getRelativeTimeSpanString(conversation.getLastPing() * 1000L,
} System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
return false;
} }
@Override if (conversation.hasPassword) {
public int hashCode() { holder.passwordProtectedImageView.setVisibility(View.VISIBLE);
return conversation.hashCode(); } else {
holder.passwordProtectedImageView.setVisibility(View.GONE);
} }
/** Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources();
* @return the model object switch (conversation.getType()) {
*/ case ROOM_TYPE_ONE_TO_ONE_CALL:
holder.avatarImageView.setVisibility(View.VISIBLE);
public Conversation getModel() { holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
return conversation; .nc_description_more_menu_one_to_one), conversation.getDisplayName()));
}
/** if (!TextUtils.isEmpty(conversation.getName())) {
* Filter is applied to the model fields. DraweeController draweeController = Fresco.newDraweeControllerBuilder()
*/ .setOldController(holder.avatarImageView.getController())
.setAutoPlayAnimations(true)
@Override .setImageRequest(DisplayUtils.getImageRequestForUrl(
public int getLayoutRes() { ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
return R.layout.rv_item_conversation; conversation.getName(),
} R.dimen.avatar_size), null))
.build();
@Override holder.avatarImageView.setController(draweeController);
public RoomItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new RoomItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(final FlexibleAdapter adapter, RoomItemViewHolder holder, int position, List payloads) {
if (adapter.hasFilter()) {
FlexibleUtils.highlightText(holder.roomDisplayName, conversation.getDisplayName(),
String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.colorPrimary));
} else { } else {
holder.roomDisplayName.setText(conversation.getDisplayName()); holder.avatarImageView.setVisibility(View.GONE);
} }
break;
if (conversation.getLastPing() == 0) { case ROOM_GROUP_CALL:
holder.roomLastPing.setText(R.string.nc_never); holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
} else { .nc_description_more_menu_group), conversation.getDisplayName()));
holder.roomLastPing.setText(DateUtils.getRelativeTimeSpanString(conversation.getLastPing() * 1000L, holder.avatarImageView.setActualImageResource(R.drawable.ic_people_group_white_24px);
System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE)); holder.avatarImageView.setVisibility(View.VISIBLE);
} break;
case ROOM_PUBLIC_CALL:
if (conversation.hasPassword) { holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
holder.passwordProtectedImageView.setVisibility(View.VISIBLE); .nc_description_more_menu_public), conversation.getDisplayName()));
} else { holder.avatarImageView.setActualImageResource(R.drawable.ic_link_white_24px);
holder.passwordProtectedImageView.setVisibility(View.GONE); holder.avatarImageView.setVisibility(View.VISIBLE);
} break;
default:
Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources(); holder.avatarImageView.setVisibility(View.GONE);
switch (conversation.getType()) {
case ROOM_TYPE_ONE_TO_ONE_CALL:
holder.avatarImageView.setVisibility(View.VISIBLE);
holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
.nc_description_more_menu_one_to_one), conversation.getDisplayName()));
if (!TextUtils.isEmpty(conversation.getName())) {
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.avatarImageView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
conversation.getName(),
R.dimen.avatar_size), null))
.build();
holder.avatarImageView.setController(draweeController);
} else {
holder.avatarImageView.setVisibility(View.GONE);
}
break;
case ROOM_GROUP_CALL:
holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
.nc_description_more_menu_group), conversation.getDisplayName()));
holder.avatarImageView.setActualImageResource(R.drawable.ic_people_group_white_24px);
holder.avatarImageView.setVisibility(View.VISIBLE);
break;
case ROOM_PUBLIC_CALL:
holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
.nc_description_more_menu_public), conversation.getDisplayName()));
holder.avatarImageView.setActualImageResource(R.drawable.ic_link_white_24px);
holder.avatarImageView.setVisibility(View.VISIBLE);
break;
default:
holder.avatarImageView.setVisibility(View.GONE);
}
holder.moreMenuButton.setOnClickListener(view -> EventBus.getDefault().post(new MoreMenuClickEvent(conversation)));
} }
@Override holder.moreMenuButton.setOnClickListener(
public boolean filter(String constraint) { view -> EventBus.getDefault().post(new MoreMenuClickEvent(conversation)));
return conversation.getDisplayName() != null && }
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(conversation.getDisplayName().trim()).find();
} @Override
public boolean filter(String constraint) {
static class RoomItemViewHolder extends FlexibleViewHolder { return conversation.getDisplayName() != null &&
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
@BindView(R.id.name_text) .matcher(conversation.getDisplayName().trim())
public EmojiTextView roomDisplayName; .find();
@BindView(R.id.secondary_text) }
public EmojiTextView roomLastPing;
@BindView(R.id.avatar_image) static class RoomItemViewHolder extends FlexibleViewHolder {
public SimpleDraweeView avatarImageView;
@BindView(R.id.more_menu) @BindView(R.id.name_text)
public ImageButton moreMenuButton; public EmojiTextView roomDisplayName;
@BindView(R.id.password_protected_image_view) @BindView(R.id.secondary_text)
ImageView passwordProtectedImageView; public EmojiTextView roomLastPing;
@BindView(R.id.avatar_image)
RoomItemViewHolder(View view, FlexibleAdapter adapter) { public SimpleDraweeView avatarImageView;
super(view, adapter); @BindView(R.id.more_menu)
ButterKnife.bind(this, view); public ImageButton moreMenuButton;
} @BindView(R.id.password_protected_image_view)
ImageView passwordProtectedImageView;
RoomItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
} }
}
} }

View File

@ -35,11 +35,11 @@ import butterknife.ButterKnife;
import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController; import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView; import com.facebook.drawee.view.SimpleDraweeView;
import com.nextcloud.talk.models.json.conversations.Conversation;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.chat.ChatMessage; import com.nextcloud.talk.models.json.chat.ChatMessage;
import com.nextcloud.talk.models.json.conversations.Conversation;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils; import com.nextcloud.talk.utils.DisplayUtils;
import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.FlexibleAdapter;
@ -51,215 +51,233 @@ import eu.davidea.viewholders.FlexibleViewHolder;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class ConversationItem extends AbstractFlexibleItem<ConversationItem.ConversationItemViewHolder> implements public class ConversationItem
IFilterable<String> { extends AbstractFlexibleItem<ConversationItem.ConversationItemViewHolder> implements
IFilterable<String> {
private Conversation conversation;
private UserEntity userEntity;
private Context context;
private Conversation conversation; public ConversationItem(Conversation conversation, UserEntity userEntity,
private UserEntity userEntity; Context activityContext) {
private Context context; this.conversation = conversation;
this.userEntity = userEntity;
this.context = activityContext;
}
public ConversationItem(Conversation conversation, UserEntity userEntity, @Override
Context activityContext) { public boolean equals(Object o) {
this.conversation = conversation; if (o instanceof ConversationItem) {
this.userEntity = userEntity; ConversationItem inItem = (ConversationItem) o;
this.context = activityContext; return conversation.equals(inItem.getModel());
}
return false;
}
public Conversation getModel() {
return conversation;
}
@Override
public int hashCode() {
return conversation.hashCode();
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_conversation_with_last_message;
}
@Override
public ConversationItemViewHolder createViewHolder(View view,
FlexibleAdapter<IFlexible> adapter) {
return new ConversationItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ConversationItemViewHolder holder,
int position, List<Object> payloads) {
Context appContext =
NextcloudTalkApplication.Companion.getSharedApplication().getApplicationContext();
holder.dialogAvatar.setController(null);
if (adapter.hasFilter()) {
FlexibleUtils.highlightText(holder.dialogName, conversation.getDisplayName(),
String.valueOf(adapter.getFilter(String.class)),
NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.colorPrimary));
} else {
holder.dialogName.setText(conversation.getDisplayName());
} }
@Override if (conversation.getUnreadMessages() > 0) {
public boolean equals(Object o) { holder.dialogUnreadBubble.setVisibility(View.VISIBLE);
if (o instanceof ConversationItem) { if (conversation.getUnreadMessages() < 100) {
ConversationItem inItem = (ConversationItem) o; holder.dialogUnreadBubble.setText(Long.toString(conversation.getUnreadMessages()));
return conversation.equals(inItem.getModel()); } else {
} holder.dialogUnreadBubble.setText("99+");
return false; }
if (conversation.isUnreadMention()) {
holder.dialogUnreadBubble.setBackground(
context.getDrawable(R.drawable.bubble_circle_unread_mention));
} else {
holder.dialogUnreadBubble.setBackground(
context.getDrawable(R.drawable.bubble_circle_unread));
}
} else {
holder.dialogUnreadBubble.setVisibility(View.GONE);
} }
public Conversation getModel() { if (conversation.isHasPassword()) {
return conversation; holder.passwordProtectedRoomImageView.setVisibility(View.VISIBLE);
} else {
holder.passwordProtectedRoomImageView.setVisibility(View.GONE);
} }
@Override if (conversation.isFavorite()) {
public int hashCode() { holder.pinnedConversationImageView.setVisibility(View.VISIBLE);
return conversation.hashCode(); } else {
holder.pinnedConversationImageView.setVisibility(View.GONE);
} }
@Override if (conversation.getLastMessage() != null) {
public int getLayoutRes() { holder.dialogDate.setVisibility(View.VISIBLE);
return R.layout.rv_item_conversation_with_last_message; holder.dialogDate.setText(
} DateUtils.getRelativeTimeSpanString(conversation.getLastActivity() * 1000L,
System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
@Override if (!TextUtils.isEmpty(conversation.getLastMessage().getSystemMessage())
public ConversationItemViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) { || Conversation.ConversationType.ROOM_SYSTEM.equals(conversation.getType())) {
return new ConversationItemViewHolder(view, adapter); holder.dialogLastMessage.setText(conversation.getLastMessage().getText());
} } else {
String authorDisplayName = "";
@Override conversation.getLastMessage().setActiveUser(userEntity);
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ConversationItemViewHolder holder, int position, List<Object> payloads) { String text;
Context appContext = if (conversation.getLastMessage()
NextcloudTalkApplication.Companion.getSharedApplication().getApplicationContext(); .getMessageType()
.equals(ChatMessage.MessageType.REGULAR_TEXT_MESSAGE)) {
holder.dialogAvatar.setController(null); if (conversation.getLastMessage().getActorId().equals(userEntity.getUserId())) {
text = String.format(appContext.getString(R.string.nc_formatted_message_you),
if (adapter.hasFilter()) { conversation.getLastMessage().getLastMessageDisplayText());
FlexibleUtils.highlightText(holder.dialogName, conversation.getDisplayName(), } else {
String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication() authorDisplayName =
.getResources().getColor(R.color.colorPrimary)); !TextUtils.isEmpty(conversation.getLastMessage().getActorDisplayName()) ?
conversation.getLastMessage().getActorDisplayName() :
"guests".equals(conversation.getLastMessage().getActorType())
? appContext.getString(R.string.nc_guest) : "";
text = String.format(appContext.getString(R.string.nc_formatted_message),
authorDisplayName,
conversation.getLastMessage().getLastMessageDisplayText());
}
} else { } else {
holder.dialogName.setText(conversation.getDisplayName()); text = conversation.getLastMessage().getLastMessageDisplayText();
} }
if (conversation.getUnreadMessages() > 0) { holder.dialogLastMessage.setText(text);
holder.dialogUnreadBubble.setVisibility(View.VISIBLE); }
if (conversation.getUnreadMessages() < 100) { } else {
holder.dialogUnreadBubble.setText(Long.toString(conversation.getUnreadMessages())); holder.dialogDate.setVisibility(View.GONE);
} else { holder.dialogLastMessage.setText(R.string.nc_no_messages_yet);
holder.dialogUnreadBubble.setText("99+");
}
if (conversation.isUnreadMention()) {
holder.dialogUnreadBubble.setBackground(context.getDrawable(R.drawable.bubble_circle_unread_mention));
} else {
holder.dialogUnreadBubble.setBackground(context.getDrawable(R.drawable.bubble_circle_unread));
}
} else {
holder.dialogUnreadBubble.setVisibility(View.GONE);
}
if (conversation.isHasPassword()) {
holder.passwordProtectedRoomImageView.setVisibility(View.VISIBLE);
} else {
holder.passwordProtectedRoomImageView.setVisibility(View.GONE);
}
if (conversation.isFavorite()) {
holder.pinnedConversationImageView.setVisibility(View.VISIBLE);
} else {
holder.pinnedConversationImageView.setVisibility(View.GONE);
}
if (conversation.getLastMessage() != null) {
holder.dialogDate.setVisibility(View.VISIBLE);
holder.dialogDate.setText(DateUtils.getRelativeTimeSpanString(conversation.getLastActivity() * 1000L,
System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
if (!TextUtils.isEmpty(conversation.getLastMessage().getSystemMessage()) || Conversation.ConversationType.ROOM_SYSTEM.equals(conversation.getType())) {
holder.dialogLastMessage.setText(conversation.getLastMessage().getText());
} else {
String authorDisplayName = "";
conversation.getLastMessage().setActiveUser(userEntity);
String text;
if (conversation.getLastMessage().getMessageType().equals(ChatMessage.MessageType.REGULAR_TEXT_MESSAGE)) {
if (conversation.getLastMessage().getActorId().equals(userEntity.getUserId())) {
text = String.format(appContext.getString(R.string.nc_formatted_message_you),
conversation.getLastMessage().getLastMessageDisplayText());
} else {
authorDisplayName = !TextUtils.isEmpty(conversation.getLastMessage().getActorDisplayName()) ?
conversation.getLastMessage().getActorDisplayName() :
"guests".equals(conversation.getLastMessage().getActorType()) ? appContext.getString(R.string.nc_guest) : "";
text = String.format(appContext.getString(R.string.nc_formatted_message),
authorDisplayName,
conversation.getLastMessage().getLastMessageDisplayText());
}
} else {
text = conversation.getLastMessage().getLastMessageDisplayText();
}
holder.dialogLastMessage.setText(text);
}
} else {
holder.dialogDate.setVisibility(View.GONE);
holder.dialogLastMessage.setText(R.string.nc_no_messages_yet);
}
holder.dialogAvatar.setVisibility(View.VISIBLE);
boolean shouldLoadAvatar = true;
String objectType;
if (!TextUtils.isEmpty(objectType = conversation.getObjectType())) {
switch (objectType) {
case "share:password":
shouldLoadAvatar = false;
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_file_password_request)), 100, true);
break;
case "file":
shouldLoadAvatar = false;
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_file_icon)), 100, true);
break;
default:
break;
}
}
if (Conversation.ConversationType.ROOM_SYSTEM.equals(conversation.getType())) {
Drawable[] layers = new Drawable[2];
layers[0] = context.getDrawable(R.drawable.ic_launcher_background);
layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground);
LayerDrawable layerDrawable = new LayerDrawable(layers);
holder.dialogAvatar.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
shouldLoadAvatar = false;
}
if (shouldLoadAvatar) {
switch (conversation.getType()) {
case ROOM_TYPE_ONE_TO_ONE_CALL:
if (!TextUtils.isEmpty(conversation.getName())) {
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.dialogAvatar.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), conversation.getName(), R.dimen.avatar_size), null))
.build();
holder.dialogAvatar.setController(draweeController);
} else {
holder.dialogAvatar.setVisibility(View.GONE);
}
break;
case ROOM_GROUP_CALL:
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils.getRoundedBitmapFromVectorDrawableResource(context.getResources(), R.drawable.ic_people_group_white_24px)), 100, true);
break;
case ROOM_PUBLIC_CALL:
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_link_white_24px)), 100, true);
break;
default:
holder.dialogAvatar.setVisibility(View.GONE);
}
}
} }
@Override holder.dialogAvatar.setVisibility(View.VISIBLE);
public boolean filter(String constraint) {
return conversation.getDisplayName() != null && boolean shouldLoadAvatar = true;
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(conversation.getDisplayName().trim()).find(); String objectType;
if (!TextUtils.isEmpty(objectType = conversation.getObjectType())) {
switch (objectType) {
case "share:password":
shouldLoadAvatar = false;
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_file_password_request)), 100, true);
break;
case "file":
shouldLoadAvatar = false;
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_file_icon)), 100, true);
break;
default:
break;
}
} }
static class ConversationItemViewHolder extends FlexibleViewHolder { if (Conversation.ConversationType.ROOM_SYSTEM.equals(conversation.getType())) {
@BindView(R.id.dialogAvatar) Drawable[] layers = new Drawable[2];
SimpleDraweeView dialogAvatar; layers[0] = context.getDrawable(R.drawable.ic_launcher_background);
@BindView(R.id.dialogName) layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground);
EmojiTextView dialogName; LayerDrawable layerDrawable = new LayerDrawable(layers);
@BindView(R.id.dialogDate)
TextView dialogDate;
@BindView(R.id.dialogLastMessage)
EmojiTextView dialogLastMessage;
@BindView(R.id.dialogUnreadBubble)
TextView dialogUnreadBubble;
@BindView(R.id.passwordProtectedRoomImageView)
ImageView passwordProtectedRoomImageView;
@BindView(R.id.favoriteConversationImageView)
ImageView pinnedConversationImageView;
ConversationItemViewHolder(View view, FlexibleAdapter adapter) { holder.dialogAvatar.getHierarchy()
super(view, adapter); .setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
ButterKnife.bind(this, view);
} shouldLoadAvatar = false;
} }
if (shouldLoadAvatar) {
switch (conversation.getType()) {
case ROOM_TYPE_ONE_TO_ONE_CALL:
if (!TextUtils.isEmpty(conversation.getName())) {
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.dialogAvatar.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
conversation.getName(), R.dimen.avatar_size), null))
.build();
holder.dialogAvatar.setController(draweeController);
} else {
holder.dialogAvatar.setVisibility(View.GONE);
}
break;
case ROOM_GROUP_CALL:
holder.dialogAvatar.getHierarchy()
.setImage(new BitmapDrawable(
DisplayUtils.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_people_group_white_24px)), 100, true);
break;
case ROOM_PUBLIC_CALL:
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_link_white_24px)), 100, true);
break;
default:
holder.dialogAvatar.setVisibility(View.GONE);
}
}
}
@Override
public boolean filter(String constraint) {
return conversation.getDisplayName() != null &&
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
.matcher(conversation.getDisplayName().trim())
.find();
}
static class ConversationItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.dialogAvatar)
SimpleDraweeView dialogAvatar;
@BindView(R.id.dialogName)
EmojiTextView dialogName;
@BindView(R.id.dialogDate)
TextView dialogDate;
@BindView(R.id.dialogLastMessage)
EmojiTextView dialogLastMessage;
@BindView(R.id.dialogUnreadBubble)
TextView dialogUnreadBubble;
@BindView(R.id.passwordProtectedRoomImageView)
ImageView passwordProtectedRoomImageView;
@BindView(R.id.favoriteConversationImageView)
ImageView pinnedConversationImageView;
ConversationItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
}
}
} }

View File

@ -32,63 +32,63 @@ import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.viewholders.FlexibleViewHolder; import eu.davidea.viewholders.FlexibleViewHolder;
import java.util.List; import java.util.List;
public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderItem.HeaderViewHolder> { public class GenericTextHeaderItem
private static final String TAG = "GenericTextHeaderItem"; extends AbstractHeaderItem<GenericTextHeaderItem.HeaderViewHolder> {
private static final String TAG = "GenericTextHeaderItem";
private String title; private String title;
public GenericTextHeaderItem(String title) { public GenericTextHeaderItem(String title) {
super(); super();
setHidden(false); setHidden(false);
setSelectable(false); setSelectable(false);
this.title = title; this.title = title;
}
public String getModel() {
return title;
}
@Override
public boolean equals(Object o) {
if (o instanceof GenericTextHeaderItem) {
GenericTextHeaderItem inItem = (GenericTextHeaderItem) o;
return title.equals(inItem.getModel());
} }
return false;
}
public String getModel() { @Override
return title; public int getLayoutRes() {
return R.layout.rv_item_title_header;
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, HeaderViewHolder holder,
int position, List<Object> payloads) {
if (payloads.size() > 0) {
Log.d(TAG, "We have payloads, so ignoring!");
} else {
holder.titleTextView.setText(title);
} }
}
@Override @Override
public boolean equals(Object o) { public HeaderViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
if (o instanceof GenericTextHeaderItem) { return new HeaderViewHolder(view, adapter);
GenericTextHeaderItem inItem = (GenericTextHeaderItem) o; }
return title.equals(inItem.getModel());
} static class HeaderViewHolder extends FlexibleViewHolder {
return false;
@BindView(R.id.title_text_view)
public TextView titleTextView;
/**
* Default constructor.
*/
HeaderViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter, true);
ButterKnife.bind(this, view);
} }
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_title_header;
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, HeaderViewHolder holder, int position, List<Object> payloads) {
if (payloads.size() > 0) {
Log.d(TAG, "We have payloads, so ignoring!");
} else {
holder.titleTextView.setText(title);
}
}
@Override
public HeaderViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new HeaderViewHolder(view, adapter);
}
static class HeaderViewHolder extends FlexibleViewHolder {
@BindView(R.id.title_text_view)
public TextView titleTextView;
/**
* Default constructor.
*/
HeaderViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter, true);
ButterKnife.bind(this, view);
}
}
} }

View File

@ -38,103 +38,112 @@ import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder> public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
implements IFilterable<String> { implements IFilterable<String> {
private String objectId; private String objectId;
private String displayName; private String displayName;
private String source; private String source;
private UserEntity currentUser; private UserEntity currentUser;
public MentionAutocompleteItem(String objectId, String displayName, String source, UserEntity currentUser) { public MentionAutocompleteItem(String objectId, String displayName, String source,
this.objectId = objectId; UserEntity currentUser) {
this.displayName = displayName; this.objectId = objectId;
this.source = source; this.displayName = displayName;
this.currentUser = currentUser; this.source = source;
this.currentUser = currentUser;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getObjectId() {
return objectId;
}
public String getDisplayName() {
return displayName;
}
@Override
public boolean equals(Object o) {
if (o instanceof MentionAutocompleteItem) {
MentionAutocompleteItem inItem = (MentionAutocompleteItem) o;
return (objectId.equals(inItem.objectId) && displayName.equals(inItem.displayName));
} }
public String getSource() { return false;
return source; }
@Override
public int getLayoutRes() {
return R.layout.rv_item_mention;
}
@Override
public UserItem.UserItemViewHolder createViewHolder(View view,
FlexibleAdapter<IFlexible> adapter) {
return new UserItem.UserItemViewHolder(view, adapter);
}
@SuppressLint("SetTextI18n")
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, UserItem.UserItemViewHolder holder,
int position, List<Object> payloads) {
if (adapter.hasFilter()) {
FlexibleUtils.highlightText(holder.contactDisplayName, displayName,
String.valueOf(adapter.getFilter(String.class)),
NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.colorPrimary));
if (holder.contactMentionId != null) {
FlexibleUtils.highlightText(holder.contactMentionId, "@" + objectId,
String.valueOf(adapter.getFilter(String.class)),
NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.colorPrimary));
}
} else {
holder.contactDisplayName.setText(displayName);
if (holder.contactMentionId != null) {
holder.contactMentionId.setText("@" + objectId);
}
} }
public void setSource(String source) { if (source.equals("calls")) {
this.source = source; holder.simpleDraweeView.getHierarchy()
.setPlaceholderImage(DisplayUtils.getRoundedBitmapDrawableFromVectorDrawableResource(
NextcloudTalkApplication.Companion.getSharedApplication().getResources(),
R.drawable.ic_people_group_white_24px));
} else {
String avatarId = objectId;
String avatarUrl = ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
avatarId, R.dimen.avatar_size_big);
if (source.equals("guests")) {
avatarId = displayName;
avatarUrl = ApiUtils.getUrlForAvatarWithNameForGuests(currentUser.getBaseUrl(), avatarId,
R.dimen.avatar_size_big);
}
holder.simpleDraweeView.setController(null);
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.simpleDraweeView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(avatarUrl, null))
.build();
holder.simpleDraweeView.setController(draweeController);
} }
}
public String getObjectId() { @Override
return objectId; public boolean filter(String constraint) {
} return objectId != null && Pattern.compile(constraint,
Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(objectId).find()
public String getDisplayName() { || displayName != null && Pattern.compile(constraint,
return displayName; Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(displayName).find();
} }
@Override
public boolean equals(Object o) {
if (o instanceof MentionAutocompleteItem) {
MentionAutocompleteItem inItem = (MentionAutocompleteItem) o;
return (objectId.equals(inItem.objectId) && displayName.equals(inItem.displayName));
}
return false;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_mention;
}
@Override
public UserItem.UserItemViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) {
return new UserItem.UserItemViewHolder(view, adapter);
}
@SuppressLint("SetTextI18n")
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, UserItem.UserItemViewHolder holder, int position, List<Object> payloads) {
if (adapter.hasFilter()) {
FlexibleUtils.highlightText(holder.contactDisplayName, displayName,
String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.colorPrimary));
if (holder.contactMentionId != null) {
FlexibleUtils.highlightText(holder.contactMentionId, "@" + objectId,
String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.colorPrimary));
}
} else {
holder.contactDisplayName.setText(displayName);
if (holder.contactMentionId != null) {
holder.contactMentionId.setText("@" + objectId);
}
}
if (source.equals("calls")) {
holder.simpleDraweeView.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedBitmapDrawableFromVectorDrawableResource(NextcloudTalkApplication.Companion.getSharedApplication().getResources(), R.drawable.ic_people_group_white_24px));
} else {
String avatarId = objectId;
String avatarUrl = ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
avatarId, R.dimen.avatar_size_big);
if (source.equals("guests")) {
avatarId = displayName;
avatarUrl = ApiUtils.getUrlForAvatarWithNameForGuests(currentUser.getBaseUrl(), avatarId, R.dimen.avatar_size_big);
}
holder.simpleDraweeView.setController(null);
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.simpleDraweeView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(avatarUrl, null))
.build();
holder.simpleDraweeView.setController(draweeController);
}
}
@Override
public boolean filter(String constraint) {
return objectId != null && Pattern.compile(constraint,
Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(objectId).find()
|| displayName != null && Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(displayName).find();
}
} }

View File

@ -39,69 +39,71 @@ import eu.davidea.viewholders.FlexibleViewHolder;
import java.util.List; import java.util.List;
public class MenuItem extends AbstractFlexibleItem<MenuItem.MenuItemViewHolder> { public class MenuItem extends AbstractFlexibleItem<MenuItem.MenuItemViewHolder> {
private String title; private String title;
private Drawable icon; private Drawable icon;
private int tag; private int tag;
private int padding; private int padding;
public MenuItem(String title, int tag, Drawable icon) { public MenuItem(String title, int tag, Drawable icon) {
this.title = title; this.title = title;
this.tag = tag; this.tag = tag;
this.icon = icon; this.icon = icon;
padding = (int) DisplayUtils.convertDpToPixel(16, padding = (int) DisplayUtils.convertDpToPixel(16,
NextcloudTalkApplication.Companion.getSharedApplication().getApplicationContext()); NextcloudTalkApplication.Companion.getSharedApplication().getApplicationContext());
}
@Override
public boolean equals(Object o) {
if (o instanceof MenuItem) {
MenuItem inItem = (MenuItem) o;
return tag == inItem.tag;
} }
return false;
}
@Override public int getTag() {
public boolean equals(Object o) { return tag;
if (o instanceof MenuItem) { }
MenuItem inItem = (MenuItem) o;
return tag == inItem.tag; @Override
} public int getLayoutRes() {
return false; return R.layout.rv_item_menu;
}
@Override
public MenuItem.MenuItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new MenuItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(FlexibleAdapter adapter, MenuItem.MenuItemViewHolder holder,
int position, List payloads) {
if (position == 0) {
Spannable spannableString = new SpannableString(title);
spannableString.setSpan(
new ForegroundColorSpan(NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.grey_600)), 0,
spannableString.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
holder.menuTitle.setText(spannableString);
} else {
holder.menuTitle.setText(title);
holder.menuTitle.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
holder.menuTitle.setCompoundDrawablePadding(padding);
} }
}
public int getTag() { static class MenuItemViewHolder extends FlexibleViewHolder {
return tag;
} @BindView(R.id.menu_text)
public TextView menuTitle;
@Override
public int getLayoutRes() { /**
return R.layout.rv_item_menu; * Default constructor.
} */
MenuItemViewHolder(View view, FlexibleAdapter adapter) {
@Override super(view, adapter);
public MenuItem.MenuItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) { ButterKnife.bind(this, view);
return new MenuItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(FlexibleAdapter adapter, MenuItem.MenuItemViewHolder holder, int position, List payloads) {
if (position == 0) {
Spannable spannableString = new SpannableString(title);
spannableString.setSpan(new ForegroundColorSpan(NextcloudTalkApplication.Companion.getSharedApplication()
.getResources().getColor(R.color.grey_600)), 0,
spannableString.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
holder.menuTitle.setText(spannableString);
} else {
holder.menuTitle.setText(title);
holder.menuTitle.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
holder.menuTitle.setCompoundDrawablePadding(padding);
}
}
static class MenuItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.menu_text)
public TextView menuTitle;
/**
* Default constructor.
*/
MenuItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
}
} }
}
} }

View File

@ -36,76 +36,80 @@ import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.viewholders.FlexibleViewHolder; import eu.davidea.viewholders.FlexibleViewHolder;
import java.util.List; import java.util.List;
public class NotificationSoundItem extends AbstractFlexibleItem<NotificationSoundItem.NotificationSoundItemViewHolder> { public class NotificationSoundItem
extends AbstractFlexibleItem<NotificationSoundItem.NotificationSoundItemViewHolder> {
private String notificationSoundName; private String notificationSoundName;
private String notificationSoundUri; private String notificationSoundUri;
public NotificationSoundItem(String notificationSoundName, String notificationSoundUri) { public NotificationSoundItem(String notificationSoundName, String notificationSoundUri) {
this.notificationSoundName = notificationSoundName; this.notificationSoundName = notificationSoundName;
this.notificationSoundUri = notificationSoundUri; this.notificationSoundUri = notificationSoundUri;
}
public String getNotificationSoundUri() {
return notificationSoundUri;
}
public String getNotificationSoundName() {
return notificationSoundName;
}
@Override
public boolean equals(Object o) {
return false;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_notification_sound;
}
@Override
public NotificationSoundItemViewHolder createViewHolder(View view,
FlexibleAdapter<IFlexible> adapter) {
return new NotificationSoundItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter,
NotificationSoundItemViewHolder holder, int position, List<Object> payloads) {
holder.notificationName.setText(notificationSoundName);
if (adapter.isSelected(position)) {
holder.checkedImageView.setVisibility(View.VISIBLE);
} else {
holder.checkedImageView.setVisibility(View.GONE);
} }
public String getNotificationSoundUri() { Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources();
return notificationSoundUri; holder.simpleDraweeView.getHierarchy()
.setBackgroundImage(new ColorDrawable(resources.getColor(R.color.colorPrimary)));
if (position == 0) {
holder.simpleDraweeView.getHierarchy()
.setImage(resources.getDrawable(R.drawable.ic_stop_white_24dp), 100,
true);
} else {
holder.simpleDraweeView.getHierarchy()
.setImage(resources.getDrawable(R.drawable.ic_play_circle_outline_white_24dp), 100,
true);
} }
}
public String getNotificationSoundName() { static class NotificationSoundItemViewHolder extends FlexibleViewHolder {
return notificationSoundName; @BindView(R.id.notificationNameTextView)
public TextView notificationName;
@BindView(R.id.simpleDraweeView)
SimpleDraweeView simpleDraweeView;
@BindView(R.id.checkedImageView)
ImageView checkedImageView;
/**
* Default constructor.
*/
NotificationSoundItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
} }
}
@Override
public boolean equals(Object o) {
return false;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_notification_sound;
}
@Override
public NotificationSoundItemViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) {
return new NotificationSoundItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, NotificationSoundItemViewHolder holder, int position, List<Object> payloads) {
holder.notificationName.setText(notificationSoundName);
if (adapter.isSelected(position)) {
holder.checkedImageView.setVisibility(View.VISIBLE);
} else {
holder.checkedImageView.setVisibility(View.GONE);
}
Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources();
holder.simpleDraweeView.getHierarchy().setBackgroundImage(new ColorDrawable(resources.getColor(R.color.colorPrimary)));
if (position == 0) {
holder.simpleDraweeView.getHierarchy().setImage(resources.getDrawable(R.drawable.ic_stop_white_24dp), 100,
true);
} else {
holder.simpleDraweeView.getHierarchy().setImage(resources.getDrawable(R.drawable.ic_play_circle_outline_white_24dp), 100,
true);
}
}
static class NotificationSoundItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.notificationNameTextView)
public TextView notificationName;
@BindView(R.id.simpleDraweeView)
SimpleDraweeView simpleDraweeView;
@BindView(R.id.checkedImageView)
ImageView checkedImageView;
/**
* Default constructor.
*/
NotificationSoundItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
}
}
} }

View File

@ -47,95 +47,95 @@ import java.util.List;
*/ */
public class ProgressItem extends AbstractFlexibleItem<ProgressItem.ProgressViewHolder> { public class ProgressItem extends AbstractFlexibleItem<ProgressItem.ProgressViewHolder> {
private StatusEnum status = StatusEnum.MORE_TO_LOAD; private StatusEnum status = StatusEnum.MORE_TO_LOAD;
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return this == o;//The default implementation return this == o;//The default implementation
}
public StatusEnum getStatus() {
return status;
}
public void setStatus(StatusEnum status) {
this.status = status;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_progress;
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ProgressViewHolder holder,
int position, List<Object> payloads) {
Context context = holder.itemView.getContext();
holder.progressBar.setVisibility(View.GONE);
holder.progressMessage.setVisibility(View.VISIBLE);
if (!adapter.isEndlessScrollEnabled()) {
setStatus(StatusEnum.DISABLE_ENDLESS);
} else if (payloads.contains(Payload.NO_MORE_LOAD)) {
setStatus(StatusEnum.NO_MORE_LOAD);
} }
public StatusEnum getStatus() { switch (this.status) {
return status; case NO_MORE_LOAD:
holder.progressMessage.setText(
context.getString(R.string.nc_no_more_load_retry));
// Reset to default status for next binding
setStatus(StatusEnum.MORE_TO_LOAD);
break;
case DISABLE_ENDLESS:
holder.progressMessage.setText(context.getString(R.string.nc_endless_disabled));
break;
case ON_CANCEL:
holder.progressMessage.setText(context.getString(R.string.nc_endless_cancel));
// Reset to default status for next binding
setStatus(StatusEnum.MORE_TO_LOAD);
break;
case ON_ERROR:
holder.progressMessage.setText(context.getString(R.string.nc_endless_error));
// Reset to default status for next binding
setStatus(StatusEnum.MORE_TO_LOAD);
break;
default:
holder.progressBar.setVisibility(View.VISIBLE);
holder.progressMessage.setVisibility(View.GONE);
break;
} }
}
public void setStatus(StatusEnum status) { @Override
this.status = status; public ProgressViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new ProgressViewHolder(view, adapter);
}
public enum StatusEnum {
MORE_TO_LOAD, //Default = should have an empty Payload
DISABLE_ENDLESS, //Endless is disabled because user has set limits
NO_MORE_LOAD, //Non-empty Payload = Payload.NO_MORE_LOAD
ON_CANCEL,
ON_ERROR
}
static class ProgressViewHolder extends FlexibleViewHolder {
@BindView(R.id.progress_bar)
ProgressBar progressBar;
@BindView(R.id.progress_message)
TextView progressMessage;
ProgressViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
} }
@Override @Override
public int getLayoutRes() { public void scrollAnimators(@NonNull List<Animator> animators, int position,
return R.layout.rv_item_progress; boolean isForward) {
AnimatorHelper.scaleAnimator(animators, itemView, 0f);
} }
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ProgressViewHolder holder, int position, List<Object> payloads) {
Context context = holder.itemView.getContext();
holder.progressBar.setVisibility(View.GONE);
holder.progressMessage.setVisibility(View.VISIBLE);
if (!adapter.isEndlessScrollEnabled()) {
setStatus(StatusEnum.DISABLE_ENDLESS);
} else if (payloads.contains(Payload.NO_MORE_LOAD)) {
setStatus(StatusEnum.NO_MORE_LOAD);
}
switch (this.status) {
case NO_MORE_LOAD:
holder.progressMessage.setText(
context.getString(R.string.nc_no_more_load_retry));
// Reset to default status for next binding
setStatus(StatusEnum.MORE_TO_LOAD);
break;
case DISABLE_ENDLESS:
holder.progressMessage.setText(context.getString(R.string.nc_endless_disabled));
break;
case ON_CANCEL:
holder.progressMessage.setText(context.getString(R.string.nc_endless_cancel));
// Reset to default status for next binding
setStatus(StatusEnum.MORE_TO_LOAD);
break;
case ON_ERROR:
holder.progressMessage.setText(context.getString(R.string.nc_endless_error));
// Reset to default status for next binding
setStatus(StatusEnum.MORE_TO_LOAD);
break;
default:
holder.progressBar.setVisibility(View.VISIBLE);
holder.progressMessage.setVisibility(View.GONE);
break;
}
}
@Override
public ProgressViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new ProgressViewHolder(view, adapter);
}
public enum StatusEnum {
MORE_TO_LOAD, //Default = should have an empty Payload
DISABLE_ENDLESS, //Endless is disabled because user has set limits
NO_MORE_LOAD, //Non-empty Payload = Payload.NO_MORE_LOAD
ON_CANCEL,
ON_ERROR
}
static class ProgressViewHolder extends FlexibleViewHolder {
@BindView(R.id.progress_bar)
ProgressBar progressBar;
@BindView(R.id.progress_message)
TextView progressMessage;
ProgressViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
}
@Override
public void scrollAnimators(@NonNull List<Animator> animators, int position, boolean isForward) {
AnimatorHelper.scaleAnimator(animators, itemView, 0f);
}
}
} }

View File

@ -50,248 +50,266 @@ import java.util.regex.Pattern;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder> implements public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder> implements
ISectionable<UserItem.UserItemViewHolder, GenericTextHeaderItem>, IFilterable<String> { ISectionable<UserItem.UserItemViewHolder, GenericTextHeaderItem>, IFilterable<String> {
private Participant participant; public boolean isOnline = true;
private UserEntity userEntity; private Participant participant;
private GenericTextHeaderItem header; private UserEntity userEntity;
private Context activityContext; private GenericTextHeaderItem header;
public boolean isOnline = true; private Context activityContext;
public UserItem(Participant participant, UserEntity userEntity, public UserItem(Participant participant, UserEntity userEntity,
GenericTextHeaderItem genericTextHeaderItem, Context activityContext) { GenericTextHeaderItem genericTextHeaderItem, Context activityContext) {
this.participant = participant; this.participant = participant;
this.userEntity = userEntity; this.userEntity = userEntity;
this.header = genericTextHeaderItem; this.header = genericTextHeaderItem;
this.activityContext = activityContext; this.activityContext = activityContext;
}
@Override
public boolean equals(Object o) {
if (o instanceof UserItem) {
UserItem inItem = (UserItem) o;
return participant.getUserId().equals(inItem.getModel().getUserId());
}
return false;
}
@Override
public int hashCode() {
return participant.hashCode();
}
/**
* @return the model object
*/
public Participant getModel() {
return participant;
}
public UserEntity getEntity() {
return userEntity;
}
@Override
public int getLayoutRes() {
if (header != null) {
return R.layout.rv_item_contact;
} else {
return R.layout.rv_item_conversation_info_participant;
}
}
@Override
public UserItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new UserItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position,
List payloads) {
holder.simpleDraweeView.setController(null);
if (holder.checkedImageView != null) {
if (participant.isSelected()) {
holder.checkedImageView.setVisibility(View.VISIBLE);
} else {
holder.checkedImageView.setVisibility(View.GONE);
}
} }
@Override if (!isOnline) {
public boolean equals(Object o) { if (holder.contactMentionId != null) {
if (o instanceof UserItem) { holder.contactMentionId.setAlpha(0.38f);
UserItem inItem = (UserItem) o; }
return participant.getUserId().equals(inItem.getModel().getUserId()); holder.contactDisplayName.setAlpha(0.38f);
holder.simpleDraweeView.setAlpha(0.38f);
} else {
if (holder.contactMentionId != null) {
holder.contactMentionId.setAlpha(1.0f);
}
holder.contactDisplayName.setAlpha(1.0f);
holder.simpleDraweeView.setAlpha(1.0f);
}
if (adapter.hasFilter()) {
FlexibleUtils.highlightText(holder.contactDisplayName, participant.getDisplayName(),
String.valueOf(adapter.getFilter(String.class)),
activityContext.getResources().getColor(R.color.colorPrimary));
}
holder.contactDisplayName.setText(participant.getDisplayName());
if (TextUtils.isEmpty(participant.getDisplayName()) &&
(participant.getType().equals(Participant.ParticipantType.GUEST) || participant.getType()
.equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) {
holder.contactDisplayName.setText(
NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest));
}
if (TextUtils.isEmpty(participant.getSource()) || participant.getSource().equals("users")) {
if (Participant.ParticipantType.GUEST.equals(participant.getType()) ||
Participant.ParticipantType.USER_FOLLOWING_LINK.equals(participant.getType())) {
String displayName = NextcloudTalkApplication.Companion.getSharedApplication()
.getResources()
.getString(R.string.nc_guest);
if (!TextUtils.isEmpty(participant.getDisplayName())) {
displayName = participant.getDisplayName();
} }
return false;
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.simpleDraweeView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForAvatarWithNameForGuests(userEntity.getBaseUrl(),
displayName, R.dimen.avatar_size), null))
.build();
holder.simpleDraweeView.setController(draweeController);
} else {
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.simpleDraweeView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
participant.getUserId(), R.dimen.avatar_size), null))
.build();
holder.simpleDraweeView.setController(draweeController);
}
} else if ("groups".equals(participant.getSource())) {
holder.simpleDraweeView.getHierarchy()
.setImage(new BitmapDrawable(DisplayUtils.getRoundedBitmapFromVectorDrawableResource(
activityContext.getResources(), R.drawable.ic_people_group_white_24px)), 100, true);
} }
@Override Resources resources = activityContext.getResources();
public int hashCode() {
return participant.hashCode(); if (header == null) {
Participant.ParticipantFlags participantFlags = participant.getParticipantFlags();
switch (participantFlags) {
case NOT_IN_CALL:
holder.voiceOrSimpleCallImageView.setVisibility(View.GONE);
holder.videoCallImageView.setVisibility(View.GONE);
break;
case IN_CALL:
holder.voiceOrSimpleCallImageView.setBackground(
resources.getDrawable(R.drawable.shape_call_bubble));
holder.voiceOrSimpleCallImageView.setVisibility(View.VISIBLE);
holder.videoCallImageView.setVisibility(View.GONE);
break;
case IN_CALL_WITH_AUDIO:
holder.voiceOrSimpleCallImageView.setBackground(
resources.getDrawable(R.drawable.shape_voice_bubble));
holder.voiceOrSimpleCallImageView.setVisibility(View.VISIBLE);
holder.videoCallImageView.setVisibility(View.GONE);
break;
case IN_CALL_WITH_VIDEO:
holder.voiceOrSimpleCallImageView.setBackground(
resources.getDrawable(R.drawable.shape_call_bubble));
holder.videoCallImageView.setBackground(
resources.getDrawable(R.drawable.shape_video_bubble));
holder.voiceOrSimpleCallImageView.setVisibility(View.VISIBLE);
holder.videoCallImageView.setVisibility(View.VISIBLE);
break;
case IN_CALL_WITH_AUDIO_AND_VIDEO:
holder.voiceOrSimpleCallImageView.setBackground(
resources.getDrawable(R.drawable.shape_voice_bubble));
holder.videoCallImageView.setBackground(
resources.getDrawable(R.drawable.shape_video_bubble));
holder.voiceOrSimpleCallImageView.setVisibility(View.VISIBLE);
holder.videoCallImageView.setVisibility(View.VISIBLE);
break;
default:
holder.voiceOrSimpleCallImageView.setVisibility(View.GONE);
holder.videoCallImageView.setVisibility(View.GONE);
break;
}
if (holder.contactMentionId != null) {
String userType = "";
switch (new EnumParticipantTypeConverter().convertToInt(participant.getType())) {
case 1:
//userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_owner);
//break;
case 2:
userType = NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_moderator);
break;
case 3:
userType = NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_user);
break;
case 4:
userType = NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_guest);
break;
case 5:
userType = NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_following_link);
break;
default:
break;
}
if (!holder.contactMentionId.getText().equals(userType)) {
holder.contactMentionId.setText(userType);
holder.contactMentionId.setTextColor(
activityContext.getResources().getColor(R.color.colorPrimary));
}
}
} }
}
@Override
public boolean filter(String constraint) {
return participant.getDisplayName() != null &&
(Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
.matcher(participant.getDisplayName().trim())
.find() ||
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL)
.matcher(participant.getUserId().trim())
.find());
}
@Override
public GenericTextHeaderItem getHeader() {
return header;
}
@Override
public void setHeader(GenericTextHeaderItem header) {
this.header = header;
}
static class UserItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.name_text)
public EmojiTextView contactDisplayName;
@BindView(R.id.simple_drawee_view)
public SimpleDraweeView simpleDraweeView;
@Nullable
@BindView(R.id.secondary_text)
public EmojiTextView contactMentionId;
@Nullable
@BindView(R.id.voiceOrSimpleCallImageView)
ImageView voiceOrSimpleCallImageView;
@Nullable
@BindView(R.id.videoCallImageView)
ImageView videoCallImageView;
@Nullable
@BindView(R.id.checkedImageView)
ImageView checkedImageView;
/** /**
* @return the model object * Default constructor.
*/ */
UserItemViewHolder(View view, FlexibleAdapter adapter) {
public Participant getModel() { super(view, adapter);
return participant; ButterKnife.bind(this, view);
} }
}
public UserEntity getEntity() {
return userEntity;
}
@Override
public int getLayoutRes() {
if (header != null) {
return R.layout.rv_item_contact;
} else {
return R.layout.rv_item_conversation_info_participant;
}
}
@Override
public UserItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) {
return new UserItemViewHolder(view, adapter);
}
@Override
public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) {
holder.simpleDraweeView.setController(null);
if (holder.checkedImageView != null) {
if (participant.isSelected()) {
holder.checkedImageView.setVisibility(View.VISIBLE);
} else {
holder.checkedImageView.setVisibility(View.GONE);
}
}
if (!isOnline) {
if (holder.contactMentionId != null) {
holder.contactMentionId.setAlpha(0.38f);
}
holder.contactDisplayName.setAlpha(0.38f);
holder.simpleDraweeView.setAlpha(0.38f);
} else {
if (holder.contactMentionId != null) {
holder.contactMentionId.setAlpha(1.0f);
}
holder.contactDisplayName.setAlpha(1.0f);
holder.simpleDraweeView.setAlpha(1.0f);
}
if (adapter.hasFilter()) {
FlexibleUtils.highlightText(holder.contactDisplayName, participant.getDisplayName(),
String.valueOf(adapter.getFilter(String.class)), activityContext.getResources().getColor(R.color.colorPrimary));
}
holder.contactDisplayName.setText(participant.getDisplayName());
if (TextUtils.isEmpty(participant.getDisplayName()) &&
(participant.getType().equals(Participant.ParticipantType.GUEST) || participant.getType().equals(Participant.ParticipantType.USER_FOLLOWING_LINK))) {
holder.contactDisplayName.setText(NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest));
}
if (TextUtils.isEmpty(participant.getSource()) || participant.getSource().equals("users")) {
if (Participant.ParticipantType.GUEST.equals(participant.getType()) ||
Participant.ParticipantType.USER_FOLLOWING_LINK.equals(participant.getType())) {
String displayName = NextcloudTalkApplication.Companion.getSharedApplication().getResources().getString(R.string.nc_guest);
if (!TextUtils.isEmpty(participant.getDisplayName())) {
displayName = participant.getDisplayName();
}
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.simpleDraweeView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameForGuests(userEntity.getBaseUrl(),
displayName, R.dimen.avatar_size), null))
.build();
holder.simpleDraweeView.setController(draweeController);
} else {
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.simpleDraweeView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
participant.getUserId(), R.dimen.avatar_size), null))
.build();
holder.simpleDraweeView.setController(draweeController);
}
} else if ("groups".equals(participant.getSource())) {
holder.simpleDraweeView.getHierarchy().setImage(new BitmapDrawable(DisplayUtils.getRoundedBitmapFromVectorDrawableResource(activityContext.getResources(), R.drawable.ic_people_group_white_24px)), 100, true);
}
Resources resources = activityContext.getResources();
if (header == null) {
Participant.ParticipantFlags participantFlags = participant.getParticipantFlags();
switch (participantFlags) {
case NOT_IN_CALL:
holder.voiceOrSimpleCallImageView.setVisibility(View.GONE);
holder.videoCallImageView.setVisibility(View.GONE);
break;
case IN_CALL:
holder.voiceOrSimpleCallImageView.setBackground(resources.getDrawable(R.drawable.shape_call_bubble));
holder.voiceOrSimpleCallImageView.setVisibility(View.VISIBLE);
holder.videoCallImageView.setVisibility(View.GONE);
break;
case IN_CALL_WITH_AUDIO:
holder.voiceOrSimpleCallImageView.setBackground(resources.getDrawable(R.drawable.shape_voice_bubble));
holder.voiceOrSimpleCallImageView.setVisibility(View.VISIBLE);
holder.videoCallImageView.setVisibility(View.GONE);
break;
case IN_CALL_WITH_VIDEO:
holder.voiceOrSimpleCallImageView.setBackground(resources.getDrawable(R.drawable.shape_call_bubble));
holder.videoCallImageView.setBackground(resources.getDrawable(R.drawable.shape_video_bubble));
holder.voiceOrSimpleCallImageView.setVisibility(View.VISIBLE);
holder.videoCallImageView.setVisibility(View.VISIBLE);
break;
case IN_CALL_WITH_AUDIO_AND_VIDEO:
holder.voiceOrSimpleCallImageView.setBackground(resources.getDrawable(R.drawable.shape_voice_bubble));
holder.videoCallImageView.setBackground(resources.getDrawable(R.drawable.shape_video_bubble));
holder.voiceOrSimpleCallImageView.setVisibility(View.VISIBLE);
holder.videoCallImageView.setVisibility(View.VISIBLE);
break;
default:
holder.voiceOrSimpleCallImageView.setVisibility(View.GONE);
holder.videoCallImageView.setVisibility(View.GONE);
break;
}
if (holder.contactMentionId != null) {
String userType = "";
switch (new EnumParticipantTypeConverter().convertToInt(participant.getType())) {
case 1:
//userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_owner);
//break;
case 2:
userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_moderator);
break;
case 3:
userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_user);
break;
case 4:
userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest);
break;
case 5:
userType = NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_following_link);
break;
default:
break;
}
if (!holder.contactMentionId.getText().equals(userType)) {
holder.contactMentionId.setText(userType);
holder.contactMentionId.setTextColor(activityContext.getResources().getColor(R.color.colorPrimary));
}
}
}
}
@Override
public boolean filter(String constraint) {
return participant.getDisplayName() != null &&
(Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getDisplayName().trim()).find() ||
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getUserId().trim()).find());
}
@Override
public GenericTextHeaderItem getHeader() {
return header;
}
@Override
public void setHeader(GenericTextHeaderItem header) {
this.header = header;
}
static class UserItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.name_text)
public EmojiTextView contactDisplayName;
@BindView(R.id.simple_drawee_view)
public SimpleDraweeView simpleDraweeView;
@Nullable
@BindView(R.id.secondary_text)
public EmojiTextView contactMentionId;
@Nullable
@BindView(R.id.voiceOrSimpleCallImageView)
ImageView voiceOrSimpleCallImageView;
@Nullable
@BindView(R.id.videoCallImageView)
ImageView videoCallImageView;
@Nullable
@BindView(R.id.checkedImageView)
ImageView checkedImageView;
/**
* Default constructor.
*/
UserItemViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
}
}
} }

View File

@ -54,150 +54,154 @@ import javax.inject.Inject;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class MagicIncomingTextMessageViewHolder public class MagicIncomingTextMessageViewHolder
extends MessageHolders.IncomingTextMessageViewHolder<ChatMessage> { extends MessageHolders.IncomingTextMessageViewHolder<ChatMessage> {
@BindView(R.id.messageAuthor) @BindView(R.id.messageAuthor)
EmojiTextView messageAuthor; EmojiTextView messageAuthor;
@BindView(R.id.messageText) @BindView(R.id.messageText)
EmojiTextView messageText; EmojiTextView messageText;
@BindView(R.id.messageUserAvatar) @BindView(R.id.messageUserAvatar)
SimpleDraweeView messageUserAvatarView; SimpleDraweeView messageUserAvatarView;
@BindView(R.id.messageTime) @BindView(R.id.messageTime)
TextView messageTimeView; TextView messageTimeView;
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
Context context; Context context;
@Inject @Inject
AppPreferences appPreferences; AppPreferences appPreferences;
private View itemView; private View itemView;
public MagicIncomingTextMessageViewHolder(View itemView) { public MagicIncomingTextMessageViewHolder(View itemView) {
super(itemView); super(itemView);
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
this.itemView = itemView; this.itemView = itemView;
}
@Override
public void onBind(ChatMessage message) {
super.onBind(message);
String author;
if (!TextUtils.isEmpty(author = message.getActorDisplayName())) {
messageAuthor.setText(author);
} else {
messageAuthor.setText(R.string.nc_nick_guest);
} }
if (!message.isGrouped() && !message.isOneToOneConversation()) {
messageUserAvatarView.setVisibility(View.VISIBLE);
if (message.getActorType().equals("guests")) {
// do nothing, avatar is set
} else if (message.getActorType().equals("bots") && message.getActorId()
.equals("changelog")) {
messageUserAvatarView.setController(null);
Drawable[] layers = new Drawable[2];
layers[0] = context.getDrawable(R.drawable.ic_launcher_background);
layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground);
LayerDrawable layerDrawable = new LayerDrawable(layers);
@Override messageUserAvatarView.getHierarchy()
public void onBind(ChatMessage message) { .setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
super.onBind(message); } else if (message.getActorType().equals("bots")) {
String author; messageUserAvatarView.setController(null);
TextDrawable drawable =
TextDrawable.builder().beginConfig().bold().endConfig().buildRound(">",
context.getResources().getColor(R.color.black));
messageUserAvatarView.setVisibility(View.VISIBLE);
messageUserAvatarView.getHierarchy().setPlaceholderImage(drawable);
}
} else {
if (message.isOneToOneConversation()) {
messageUserAvatarView.setVisibility(View.GONE);
} else {
messageUserAvatarView.setVisibility(View.INVISIBLE);
}
messageAuthor.setVisibility(View.GONE);
}
if (!TextUtils.isEmpty(author = message.getActorDisplayName())) { Resources resources = itemView.getResources();
messageAuthor.setText(author);
} else {
messageAuthor.setText(R.string.nc_nick_guest);
}
if (!message.isGrouped() && !message.isOneToOneConversation()) { int bg_bubble_color = resources.getColor(R.color.bg_message_list_incoming_bubble);
messageUserAvatarView.setVisibility(View.VISIBLE);
if (message.getActorType().equals("guests")) {
// do nothing, avatar is set
} else if (message.getActorType().equals("bots") && message.getActorId().equals("changelog")) {
messageUserAvatarView.setController(null);
Drawable[] layers = new Drawable[2];
layers[0] = context.getDrawable(R.drawable.ic_launcher_background);
layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground);
LayerDrawable layerDrawable = new LayerDrawable(layers);
messageUserAvatarView.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable)); int bubbleResource = R.drawable.shape_incoming_message;
} else if (message.getActorType().equals("bots")) {
messageUserAvatarView.setController(null); if (message.isGrouped) {
TextDrawable drawable = TextDrawable.builder().beginConfig().bold().endConfig().buildRound(">", bubbleResource = R.drawable.shape_grouped_incoming_message;
context.getResources().getColor(R.color.black)); }
messageUserAvatarView.setVisibility(View.VISIBLE);
messageUserAvatarView.getHierarchy().setPlaceholderImage(drawable); Drawable bubbleDrawable = DisplayUtils.getMessageSelector(bg_bubble_color,
} resources.getColor(R.color.transparent),
} else { bg_bubble_color, bubbleResource);
if (message.isOneToOneConversation()) { ViewCompat.setBackground(bubble, bubbleDrawable);
messageUserAvatarView.setVisibility(View.GONE);
HashMap<String, HashMap<String, String>> messageParameters = message.getMessageParameters();
itemView.setSelected(false);
messageTimeView.setTextColor(context.getResources().getColor(R.color.warm_grey_four));
FlexboxLayout.LayoutParams layoutParams =
(FlexboxLayout.LayoutParams) messageTimeView.getLayoutParams();
layoutParams.setWrapBefore(false);
Spannable messageString = new SpannableString(message.getText());
float textSize = context.getResources().getDimension(R.dimen.chat_text_size);
if (messageParameters != null && messageParameters.size() > 0) {
for (String key : messageParameters.keySet()) {
Map<String, String> individualHashMap = message.getMessageParameters().get(key);
if (individualHashMap != null) {
if (individualHashMap.get("type").equals("user") || individualHashMap.get("type")
.equals("guest") || individualHashMap.get("type").equals("call")) {
if (individualHashMap.get("id").equals(message.getActiveUser().getUserId())) {
messageString =
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
messageString,
individualHashMap.get("id"),
individualHashMap.get("name"),
individualHashMap.get("type"),
userUtils.getUserById(message.getActiveUser().getUserId()),
R.xml.chip_you);
} else { } else {
messageUserAvatarView.setVisibility(View.INVISIBLE); messageString =
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
messageString,
individualHashMap.get("id"),
individualHashMap.get("name"),
individualHashMap.get("type"),
userUtils.getUserById(message.getActiveUser().getUserId()),
R.xml.chip_others);
} }
messageAuthor.setVisibility(View.GONE); } else if (individualHashMap.get("type").equals("file")) {
itemView.setOnClickListener(v -> {
Intent browserIntent =
new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link")));
context.startActivity(browserIntent);
});
}
} }
}
Resources resources = itemView.getResources(); } else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.getText())) {
textSize = (float) (textSize * 2.5);
int bg_bubble_color = resources.getColor(R.color.bg_message_list_incoming_bubble); layoutParams.setWrapBefore(true);
itemView.setSelected(true);
int bubbleResource = R.drawable.shape_incoming_message; messageAuthor.setVisibility(View.GONE);
if (message.isGrouped) {
bubbleResource = R.drawable.shape_grouped_incoming_message;
}
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(bg_bubble_color,
resources.getColor(R.color.transparent),
bg_bubble_color, bubbleResource);
ViewCompat.setBackground(bubble, bubbleDrawable);
HashMap<String, HashMap<String, String>> messageParameters = message.getMessageParameters();
itemView.setSelected(false);
messageTimeView.setTextColor(context.getResources().getColor(R.color.warm_grey_four));
FlexboxLayout.LayoutParams layoutParams = (FlexboxLayout.LayoutParams) messageTimeView.getLayoutParams();
layoutParams.setWrapBefore(false);
Spannable messageString = new SpannableString(message.getText());
float textSize = context.getResources().getDimension(R.dimen.chat_text_size);
if (messageParameters != null && messageParameters.size() > 0) {
for (String key : messageParameters.keySet()) {
Map<String, String> individualHashMap = message.getMessageParameters().get(key);
if (individualHashMap != null) {
if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
if (individualHashMap.get("id").equals(message.getActiveUser().getUserId())) {
messageString =
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
messageString,
individualHashMap.get("id"),
individualHashMap.get("name"),
individualHashMap.get("type"),
userUtils.getUserById(message.getActiveUser().getUserId()),
R.xml.chip_you);
} else {
messageString =
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
messageString,
individualHashMap.get("id"),
individualHashMap.get("name"),
individualHashMap.get("type"),
userUtils.getUserById(message.getActiveUser().getUserId()),
R.xml.chip_others);
}
} else if (individualHashMap.get("type").equals("file")) {
itemView.setOnClickListener(v -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link")));
context.startActivity(browserIntent);
});
}
}
}
} else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.getText())) {
textSize = (float) (textSize * 2.5);
layoutParams.setWrapBefore(true);
itemView.setSelected(true);
messageAuthor.setVisibility(View.GONE);
}
messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
messageTimeView.setLayoutParams(layoutParams);
messageText.setText(messageString);
} }
messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
messageTimeView.setLayoutParams(layoutParams);
messageText.setText(messageString);
}
} }

View File

@ -48,91 +48,99 @@ import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class MagicOutcomingTextMessageViewHolder extends MessageHolders.OutcomingTextMessageViewHolder<ChatMessage> { public class MagicOutcomingTextMessageViewHolder
@BindView(R.id.messageText) extends MessageHolders.OutcomingTextMessageViewHolder<ChatMessage> {
EmojiTextView messageText; @BindView(R.id.messageText)
EmojiTextView messageText;
@BindView(R.id.messageTime) @BindView(R.id.messageTime)
TextView messageTimeView; TextView messageTimeView;
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
Context context; Context context;
private View itemView; private View itemView;
public MagicOutcomingTextMessageViewHolder(View itemView) { public MagicOutcomingTextMessageViewHolder(View itemView) {
super(itemView); super(itemView);
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
this.itemView = itemView; this.itemView = itemView;
}
@Override
public void onBind(ChatMessage message) {
super.onBind(message);
HashMap<String, HashMap<String, String>> messageParameters = message.getMessageParameters();
Spannable messageString = new SpannableString(message.getText());
itemView.setSelected(false);
messageTimeView.setTextColor(context.getResources().getColor(R.color.white60));
FlexboxLayout.LayoutParams layoutParams =
(FlexboxLayout.LayoutParams) messageTimeView.getLayoutParams();
layoutParams.setWrapBefore(false);
float textSize = context.getResources().getDimension(R.dimen.chat_text_size);
if (messageParameters != null && messageParameters.size() > 0) {
for (String key : messageParameters.keySet()) {
Map<String, String> individualHashMap = message.getMessageParameters().get(key);
if (individualHashMap != null) {
if (individualHashMap.get("type").equals("user") || individualHashMap.get("type")
.equals("guest") || individualHashMap.get("type").equals("call")) {
messageString =
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
messageString,
individualHashMap.get("id"),
individualHashMap.get("name"),
individualHashMap.get("type"),
userUtils.getUserById(message.getActiveUser().getUserId()),
R.xml.chip_others);
} else if (individualHashMap.get("type").equals("file")) {
itemView.setOnClickListener(v -> {
Intent browserIntent =
new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link")));
context.startActivity(browserIntent);
});
}
}
}
} else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.getText())) {
textSize = (float) (textSize * 2.5);
layoutParams.setWrapBefore(true);
messageTimeView.setTextColor(context.getResources().getColor(R.color.warm_grey_four));
itemView.setSelected(true);
} }
@Override Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources();
public void onBind(ChatMessage message) { if (message.isGrouped) {
super.onBind(message); Drawable bubbleDrawable =
DisplayUtils.getMessageSelector(
HashMap<String, HashMap<String, String>> messageParameters = message.getMessageParameters(); resources.getColor(R.color.bg_message_list_outcoming_bubble),
resources.getColor(R.color.transparent),
Spannable messageString = new SpannableString(message.getText()); resources.getColor(R.color.bg_message_list_outcoming_bubble),
R.drawable.shape_grouped_outcoming_message);
itemView.setSelected(false); ViewCompat.setBackground(bubble, bubbleDrawable);
messageTimeView.setTextColor(context.getResources().getColor(R.color.white60)); } else {
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(
FlexboxLayout.LayoutParams layoutParams = (FlexboxLayout.LayoutParams) messageTimeView.getLayoutParams(); resources.getColor(R.color.bg_message_list_outcoming_bubble),
layoutParams.setWrapBefore(false); resources.getColor(R.color.transparent),
resources.getColor(R.color.bg_message_list_outcoming_bubble),
float textSize = context.getResources().getDimension(R.dimen.chat_text_size); R.drawable.shape_outcoming_message);
ViewCompat.setBackground(bubble, bubbleDrawable);
if (messageParameters != null && messageParameters.size() > 0) {
for (String key : messageParameters.keySet()) {
Map<String, String> individualHashMap = message.getMessageParameters().get(key);
if (individualHashMap != null) {
if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
messageString =
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
messageString,
individualHashMap.get("id"),
individualHashMap.get("name"),
individualHashMap.get("type"),
userUtils.getUserById(message.getActiveUser().getUserId()),
R.xml.chip_others);
} else if (individualHashMap.get("type").equals("file")) {
itemView.setOnClickListener(v -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link")));
context.startActivity(browserIntent);
});
}
}
}
} else if (TextMatchers.isMessageWithSingleEmoticonOnly(message.getText())) {
textSize = (float) (textSize * 2.5);
layoutParams.setWrapBefore(true);
messageTimeView.setTextColor(context.getResources().getColor(R.color.warm_grey_four));
itemView.setSelected(true);
}
Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources();
if (message.isGrouped) {
Drawable bubbleDrawable =
DisplayUtils.getMessageSelector(resources.getColor(R.color.bg_message_list_outcoming_bubble),
resources.getColor(R.color.transparent),
resources.getColor(R.color.bg_message_list_outcoming_bubble), R.drawable.shape_grouped_outcoming_message);
ViewCompat.setBackground(bubble, bubbleDrawable);
} else {
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(resources.getColor(R.color.bg_message_list_outcoming_bubble),
resources.getColor(R.color.transparent),
resources.getColor(R.color.bg_message_list_outcoming_bubble), R.drawable.shape_outcoming_message);
ViewCompat.setBackground(bubble, bubbleDrawable);
}
messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
messageTimeView.setLayoutParams(layoutParams);
messageText.setText(messageString);
} }
messageText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
messageTimeView.setLayoutParams(layoutParams);
messageText.setText(messageString);
}
} }

View File

@ -55,126 +55,144 @@ import javax.inject.Inject;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageMessageViewHolder<ChatMessage> { public class MagicPreviewMessageViewHolder
extends MessageHolders.IncomingImageMessageViewHolder<ChatMessage> {
@BindView(R.id.messageText) @BindView(R.id.messageText)
EmojiTextView messageText; EmojiTextView messageText;
@Inject @Inject
Context context; Context context;
@Inject @Inject
OkHttpClient okHttpClient; OkHttpClient okHttpClient;
public MagicPreviewMessageViewHolder(View itemView) { public MagicPreviewMessageViewHolder(View itemView) {
super(itemView); super(itemView);
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication()
} .getComponentApplication()
.inject(this);
}
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
@Override @Override
public void onBind(ChatMessage message) { public void onBind(ChatMessage message) {
super.onBind(message); super.onBind(message);
if (userAvatar != null) { if (userAvatar != null) {
if (message.isGrouped || message.isOneToOneConversation) { if (message.isGrouped || message.isOneToOneConversation) {
if (message.isOneToOneConversation) { if (message.isOneToOneConversation) {
userAvatar.setVisibility(View.GONE); userAvatar.setVisibility(View.GONE);
} else {
userAvatar.setVisibility(View.INVISIBLE);
}
} else {
userAvatar.setVisibility(View.VISIBLE);
if ("bots".equals(message.getActorType()) && "changelog".equals(message.getActorId())) {
Drawable[] layers = new Drawable[2];
layers[0] = context.getDrawable(R.drawable.ic_launcher_background);
layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground);
LayerDrawable layerDrawable = new LayerDrawable(layers);
userAvatar.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
}
}
}
if (message.getMessageType() == ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE) {
// it's a preview for a Nextcloud share
messageText.setText(message.getSelectedIndividualHashMap().get("name"));
DisplayUtils.setClickableString(message.getSelectedIndividualHashMap().get("name"), message.getSelectedIndividualHashMap().get("link"), messageText);
if (message.getSelectedIndividualHashMap().containsKey("mimetype")) {
image.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(message.getSelectedIndividualHashMap().get("mimetype"))));
} else {
fetchFileInformation("/" + message.getSelectedIndividualHashMap().get("path"), message.getActiveUser());
}
image.setOnClickListener(v -> {
String accountString =
message.getActiveUser().getUsername() + "@" + message.getActiveUser().getBaseUrl().replace("https://", "").replace("http://", "");
if (AccountUtils.INSTANCE.canWeOpenFilesApp(context, accountString)) {
Intent filesAppIntent = new Intent(Intent.ACTION_VIEW, null);
final ComponentName componentName = new ComponentName(context.getString(R.string.nc_import_accounts_from), "com.owncloud.android.ui.activity.FileDisplayActivity");
filesAppIntent.setComponent(componentName);
filesAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
filesAppIntent.setPackage(context.getString(R.string.nc_import_accounts_from));
filesAppIntent.putExtra(BundleKeys.INSTANCE.getKEY_ACCOUNT(), accountString);
filesAppIntent.putExtra(BundleKeys.INSTANCE.getKEY_FILE_ID(), message.getSelectedIndividualHashMap().get("id"));
context.startActivity(filesAppIntent);
} else {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(message.getSelectedIndividualHashMap().get("link")));
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(browserIntent);
}
});
} else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_GIPHY_MESSAGE) {
messageText.setText("GIPHY");
DisplayUtils.setClickableString("GIPHY", "https://giphy.com", messageText);
} else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_TENOR_MESSAGE) {
messageText.setText("Tenor");
DisplayUtils.setClickableString("Tenor", "https://tenor.com", messageText);
} else { } else {
if (message.getMessageType().equals(ChatMessage.MessageType.SINGLE_LINK_IMAGE_MESSAGE)) { userAvatar.setVisibility(View.INVISIBLE);
image.setOnClickListener(v -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(message.getImageUrl()));
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(browserIntent);
});
} else {
image.setOnClickListener(null);
}
messageText.setText("");
} }
} else {
userAvatar.setVisibility(View.VISIBLE);
if ("bots".equals(message.getActorType()) && "changelog".equals(message.getActorId())) {
Drawable[] layers = new Drawable[2];
layers[0] = context.getDrawable(R.drawable.ic_launcher_background);
layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground);
LayerDrawable layerDrawable = new LayerDrawable(layers);
userAvatar.getHierarchy()
.setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
}
}
} }
private void fetchFileInformation(String url, UserEntity activeUser) { if (message.getMessageType() == ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE) {
Single.fromCallable(new Callable<ReadFilesystemOperation>() { // it's a preview for a Nextcloud share
@Override messageText.setText(message.getSelectedIndividualHashMap().get("name"));
public ReadFilesystemOperation call() { DisplayUtils.setClickableString(message.getSelectedIndividualHashMap().get("name"),
return new ReadFilesystemOperation(okHttpClient, activeUser, url, 0); message.getSelectedIndividualHashMap().get("link"), messageText);
if (message.getSelectedIndividualHashMap().containsKey("mimetype")) {
image.getHierarchy()
.setPlaceholderImage(context.getDrawable(
DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(
message.getSelectedIndividualHashMap().get("mimetype"))));
} else {
fetchFileInformation("/" + message.getSelectedIndividualHashMap().get("path"),
message.getActiveUser());
}
image.setOnClickListener(v -> {
String accountString =
message.getActiveUser().getUsername() + "@" + message.getActiveUser()
.getBaseUrl()
.replace("https://", "")
.replace("http://", "");
if (AccountUtils.INSTANCE.canWeOpenFilesApp(context, accountString)) {
Intent filesAppIntent = new Intent(Intent.ACTION_VIEW, null);
final ComponentName componentName =
new ComponentName(context.getString(R.string.nc_import_accounts_from),
"com.owncloud.android.ui.activity.FileDisplayActivity");
filesAppIntent.setComponent(componentName);
filesAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
filesAppIntent.setPackage(context.getString(R.string.nc_import_accounts_from));
filesAppIntent.putExtra(BundleKeys.INSTANCE.getKEY_ACCOUNT(), accountString);
filesAppIntent.putExtra(BundleKeys.INSTANCE.getKEY_FILE_ID(),
message.getSelectedIndividualHashMap().get("id"));
context.startActivity(filesAppIntent);
} else {
Intent browserIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse(message.getSelectedIndividualHashMap().get("link")));
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(browserIntent);
}
});
} else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_GIPHY_MESSAGE) {
messageText.setText("GIPHY");
DisplayUtils.setClickableString("GIPHY", "https://giphy.com", messageText);
} else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_TENOR_MESSAGE) {
messageText.setText("Tenor");
DisplayUtils.setClickableString("Tenor", "https://tenor.com", messageText);
} else {
if (message.getMessageType().equals(ChatMessage.MessageType.SINGLE_LINK_IMAGE_MESSAGE)) {
image.setOnClickListener(v -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(message.getImageUrl()));
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(browserIntent);
});
} else {
image.setOnClickListener(null);
}
messageText.setText("");
}
}
private void fetchFileInformation(String url, UserEntity activeUser) {
Single.fromCallable(new Callable<ReadFilesystemOperation>() {
@Override
public ReadFilesystemOperation call() {
return new ReadFilesystemOperation(okHttpClient, activeUser, url, 0);
}
}).observeOn(Schedulers.io())
.subscribe(new SingleObserver<ReadFilesystemOperation>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(ReadFilesystemOperation readFilesystemOperation) {
DavResponse davResponse = readFilesystemOperation.readRemotePath();
if (davResponse.getData() != null) {
List<BrowserFile> browserFileList = (List<BrowserFile>) davResponse.getData();
if (!browserFileList.isEmpty()) {
new Handler(context.getMainLooper()).post(() -> image.getHierarchy()
.setPlaceholderImage(context.getDrawable(
DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(
browserFileList.get(0).getMimeType()))));
}
} }
}).observeOn(Schedulers.io()) }
.subscribe(new SingleObserver<ReadFilesystemOperation>() {
@Override
public void onSubscribe(Disposable d) {
} @Override
public void onError(Throwable e) {
@Override }
public void onSuccess(ReadFilesystemOperation readFilesystemOperation) { });
DavResponse davResponse = readFilesystemOperation.readRemotePath(); }
if (davResponse.getData() != null) {
List<BrowserFile> browserFileList = (List<BrowserFile>) davResponse.getData();
if (!browserFileList.isEmpty()) {
new Handler(context.getMainLooper()).post(() -> image.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(browserFileList.get(0).getMimeType()))));
}
}
}
@Override
public void onError(Throwable e) {
}
});
}
} }

View File

@ -38,48 +38,54 @@ import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class MagicSystemMessageViewHolder extends MessageHolders.IncomingTextMessageViewHolder<ChatMessage> { public class MagicSystemMessageViewHolder
extends MessageHolders.IncomingTextMessageViewHolder<ChatMessage> {
@Inject @Inject
AppPreferences appPreferences; AppPreferences appPreferences;
@Inject @Inject
Context context; Context context;
public MagicSystemMessageViewHolder(View itemView) { public MagicSystemMessageViewHolder(View itemView) {
super(itemView); super(itemView);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication()
} .getComponentApplication()
.inject(this);
}
@Override @Override
public void onBind(ChatMessage message) { public void onBind(ChatMessage message) {
super.onBind(message); super.onBind(message);
Resources resources = itemView.getResources(); Resources resources = itemView.getResources();
int normalColor = resources.getColor(R.color.bg_message_list_incoming_bubble); int normalColor = resources.getColor(R.color.bg_message_list_incoming_bubble);
int pressedColor; int pressedColor;
int mentionColor; int mentionColor;
pressedColor = normalColor;
mentionColor = resources.getColor(R.color.nc_author_text);
pressedColor = normalColor; Drawable bubbleDrawable = DisplayUtils.getMessageSelector(normalColor,
mentionColor = resources.getColor(R.color.nc_author_text); resources.getColor(R.color.transparent), pressedColor,
R.drawable.shape_grouped_incoming_message);
ViewCompat.setBackground(bubble, bubbleDrawable);
Drawable bubbleDrawable = DisplayUtils.getMessageSelector(normalColor, Spannable messageString = new SpannableString(message.getText());
resources.getColor(R.color.transparent), pressedColor,
R.drawable.shape_grouped_incoming_message);
ViewCompat.setBackground(bubble, bubbleDrawable);
Spannable messageString = new SpannableString(message.getText()); if (message.getMessageParameters() != null && message.getMessageParameters().size() > 0) {
for (String key : message.getMessageParameters().keySet()) {
if (message.getMessageParameters() != null && message.getMessageParameters().size() > 0) { Map<String, String> individualHashMap = message.getMessageParameters().get(key);
for (String key : message.getMessageParameters().keySet()) { if (individualHashMap != null && (individualHashMap.get("type").equals("user")
Map<String, String> individualHashMap = message.getMessageParameters().get(key); || individualHashMap.get("type").equals("guest")
if (individualHashMap != null && (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call"))) { || individualHashMap.get("type").equals("call"))) {
messageString = DisplayUtils.searchAndColor(messageString, "@" + individualHashMap.get("name"), mentionColor); messageString =
} DisplayUtils.searchAndColor(messageString, "@" + individualHashMap.get("name"),
} mentionColor);
} }
}
text.setText(messageString);
} }
text.setText(messageString);
}
} }

View File

@ -24,27 +24,28 @@ import android.view.View;
import com.nextcloud.talk.models.json.chat.ChatMessage; import com.nextcloud.talk.models.json.chat.ChatMessage;
import com.stfalcon.chatkit.messages.MessageHolders; import com.stfalcon.chatkit.messages.MessageHolders;
public class MagicUnreadNoticeMessageViewHolder extends MessageHolders.SystemMessageViewHolder<ChatMessage> { public class MagicUnreadNoticeMessageViewHolder
extends MessageHolders.SystemMessageViewHolder<ChatMessage> {
public MagicUnreadNoticeMessageViewHolder(View itemView) { public MagicUnreadNoticeMessageViewHolder(View itemView) {
super(itemView); super(itemView);
} }
public MagicUnreadNoticeMessageViewHolder(View itemView, Object payload) { public MagicUnreadNoticeMessageViewHolder(View itemView, Object payload) {
super(itemView, payload); super(itemView, payload);
} }
@Override @Override
public void viewDetached() { public void viewDetached() {
messagesListAdapter.deleteById("-1"); messagesListAdapter.deleteById("-1");
} }
@Override @Override
public void viewAttached() { public void viewAttached() {
} }
@Override @Override
public void viewRecycled() { public void viewRecycled() {
} }
} }

View File

@ -54,36 +54,37 @@ import retrofit2.http.Url;
public interface NcApi { public interface NcApi {
/* /*
QueryMap items are as follows: QueryMap items are as follows:
- "format" : "json" - "format" : "json"
- "search" : "" - "search" : ""
- "perPage" : "200" - "perPage" : "200"
- "itemType" : "call" - "itemType" : "call"
Server URL is: baseUrl + ocsApiVersion + /apps/files_sharing/api/v1/sharees Server URL is: baseUrl + ocsApiVersion + /apps/files_sharing/api/v1/sharees
or if we're on 14 and up: or if we're on 14 and up:
baseUrl + ocsApiVersion + "/core/autocomplete/get"); baseUrl + ocsApiVersion + "/core/autocomplete/get");
*/ */
@GET @GET
Observable<ResponseBody> getContactsWithSearchParam(@Header("Authorization") String authorization, @Url String url, Observable<ResponseBody> getContactsWithSearchParam(@Header("Authorization") String authorization,
@Nullable @Query("shareTypes[]") List<String> listOfShareTypes, @QueryMap Map<String, Object> options); @Url String url,
@Nullable @Query("shareTypes[]") List<String> listOfShareTypes,
@QueryMap Map<String, Object> options);
/*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room
*/
@GET
Observable<RoomsOverall> getRooms(@Header("Authorization") String authorization, @Url String url);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken
*/ */
@GET @GET
Observable<RoomsOverall> getRooms(@Header("Authorization") String authorization, @Url String url); Observable<RoomOverall> getRoom(@Header("Authorization") String authorization, @Url String url);
/*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken
*/
@GET
Observable<RoomOverall> getRoom(@Header("Authorization") String authorization, @Url String url);
/* /*
QueryMap items are as follows: QueryMap items are as follows:
@ -93,9 +94,9 @@ public interface NcApi {
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room
*/ */
@POST @POST
Observable<RoomOverall> createRoom(@Header("Authorization") String authorization, @Url String url, Observable<RoomOverall> createRoom(@Header("Authorization") String authorization, @Url String url,
@QueryMap Map<String, String> options); @QueryMap Map<String, String> options);
/* /*
QueryMap items are as follows: QueryMap items are as follows:
@ -104,109 +105,126 @@ public interface NcApi {
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken
*/ */
@FormUrlEncoded @FormUrlEncoded
@PUT @PUT
Observable<GenericOverall> renameRoom(@Header("Authorization") String authorization, @Url String url, Observable<GenericOverall> renameRoom(@Header("Authorization") String authorization,
@Field("roomName") String roomName); @Url String url,
@Field("roomName") String roomName);
/*
QueryMap items are as follows:
- "newParticipant" : "user"
/* Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/participants
QueryMap items are as follows: */
- "newParticipant" : "user" @POST
Observable<AddParticipantOverall> addParticipant(@Header("Authorization") String authorization,
@Url String url,
@QueryMap Map<String, String> options);
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/participants // also used for removing a guest from a conversation
*/ @DELETE
@POST Observable<GenericOverall> removeParticipantFromConversation(
Observable<AddParticipantOverall> addParticipant(@Header("Authorization") String authorization, @Url String url, @Header("Authorization") String authorization, @Url String url,
@QueryMap Map<String, String> options); @Query("participant") String participantId);
@POST
Observable<GenericOverall> promoteUserToModerator(@Header("Authorization") String authorization,
@Url String url, @Query("participant") String participantId);
// also used for removing a guest from a conversation @DELETE
@DELETE Observable<GenericOverall> demoteModeratorToUser(@Header("Authorization") String authorization,
Observable<GenericOverall> removeParticipantFromConversation(@Header("Authorization") String authorization, @Url String url, @Query("participant") String participantId); @Url String url, @Query("participant") String participantId);
@POST
Observable<GenericOverall> promoteUserToModerator(@Header("Authorization") String authorization, @Url String url, @Query("participant") String participantId);
@DELETE
Observable<GenericOverall> demoteModeratorToUser(@Header("Authorization") String authorization, @Url String url, @Query("participant") String participantId);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/participants/self Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/participants/self
*/ */
@DELETE @DELETE
Observable<GenericOverall> removeSelfFromRoom(@Header("Authorization") String authorization, @Url String url); Observable<GenericOverall> removeSelfFromRoom(@Header("Authorization") String authorization,
@Url String url);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/public Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/public
*/ */
@POST @POST
Observable<GenericOverall> makeRoomPublic(@Header("Authorization") String authorization, @Url String url); Observable<GenericOverall> makeRoomPublic(@Header("Authorization") String authorization,
@Url String url);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/public Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room/roomToken/public
*/ */
@DELETE @DELETE
Observable<GenericOverall> makeRoomPrivate(@Header("Authorization") String authorization, @Url String url); Observable<GenericOverall> makeRoomPrivate(@Header("Authorization") String authorization,
@Url String url);
@DELETE @DELETE
Observable<GenericOverall> deleteRoom(@Header("Authorization") String authorization, @Url String url); Observable<GenericOverall> deleteRoom(@Header("Authorization") String authorization,
@Url String url);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken
*/ */
@GET @GET
Observable<ParticipantsOverall> getPeersForCall(@Header("Authorization") String authorization, @Url String url); Observable<ParticipantsOverall> getPeersForCall(@Header("Authorization") String authorization,
@Url String url);
@FormUrlEncoded @FormUrlEncoded
@POST @POST
Observable<RoomOverall> joinRoom(@Nullable @Header("Authorization") String authorization, @Url String url, @Nullable @Field("password") String password); Observable<RoomOverall> joinRoom(@Nullable @Header("Authorization") String authorization,
@Url String url, @Nullable @Field("password") String password);
@DELETE @DELETE
Observable<GenericOverall> leaveRoom(@Nullable @Header("Authorization") String authorization, @Url String url); Observable<GenericOverall> leaveRoom(@Nullable @Header("Authorization") String authorization,
@Url String url);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken
*/ */
@POST @POST
Observable<GenericOverall> joinCall(@Nullable @Header("Authorization") String authorization, @Url String url); Observable<GenericOverall> joinCall(@Nullable @Header("Authorization") String authorization,
@Url String url);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken
*/ */
@DELETE @DELETE
Observable<GenericOverall> leaveCall(@Nullable @Header("Authorization") String authorization, @Url String url); Observable<GenericOverall> leaveCall(@Nullable @Header("Authorization") String authorization,
@Url String url);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken/ping Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken/ping
*/ */
@POST @POST
Observable<GenericOverall> pingCall(@Nullable @Header("Authorization") String authorization, @Url String url); Observable<GenericOverall> pingCall(@Nullable @Header("Authorization") String authorization,
@Url String url);
@GET @GET
Observable<SignalingSettingsOverall> getSignalingSettings(@Nullable @Header("Authorization") String authorization, Observable<SignalingSettingsOverall> getSignalingSettings(
@Url String url); @Nullable @Header("Authorization") String authorization,
@Url String url);
/* /*
QueryMap items are as follows: QueryMap items are as follows:
- "messages" : "message" - "messages" : "message"
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /signaling Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /signaling
*/ */
@FormUrlEncoded @FormUrlEncoded
@POST @POST
Observable<SignalingOverall> sendSignalingMessages(@Nullable @Header("Authorization") String authorization, @Url String url, Observable<SignalingOverall> sendSignalingMessages(
@Field("messages") String messages); @Nullable @Header("Authorization") String authorization, @Url String url,
@Field("messages") String messages);
/* /*
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /signaling Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /signaling
*/ */
@GET @GET
Observable<SignalingOverall> pullSignalingMessages(@Nullable @Header("Authorization") String authorization, @Url Observable<SignalingOverall> pullSignalingMessages(
String @Nullable @Header("Authorization") String authorization, @Url
url); String
url);
/* /*
QueryMap items are as follows: QueryMap items are as follows:
@ -215,14 +233,15 @@ public interface NcApi {
Server URL is: baseUrl + ocsApiVersion + "/cloud/user" Server URL is: baseUrl + ocsApiVersion + "/cloud/user"
*/ */
@GET @GET
Observable<UserProfileOverall> getUserProfile(@Header("Authorization") String authorization, @Url String url); Observable<UserProfileOverall> getUserProfile(@Header("Authorization") String authorization,
@Url String url);
/* /*
Server URL is: baseUrl + /status.php Server URL is: baseUrl + /status.php
*/ */
@GET @GET
Observable<Status> getServerStatus(@Url String url); Observable<Status> getServerStatus(@Url String url);
/* /*
@ -235,52 +254,55 @@ public interface NcApi {
Server URL is: baseUrl + ocsApiVersion + "/apps/notifications/api/v2/push Server URL is: baseUrl + ocsApiVersion + "/apps/notifications/api/v2/push
*/ */
@POST @POST
Observable<PushRegistrationOverall> registerDeviceForNotificationsWithNextcloud(@Header("Authorization") Observable<PushRegistrationOverall> registerDeviceForNotificationsWithNextcloud(
String authorization, @Header("Authorization")
@Url String url, String authorization,
@QueryMap Map<String, @Url String url,
String> options); @QueryMap Map<String,
String> options);
@DELETE @DELETE
Observable<GenericOverall> unregisterDeviceForNotificationsWithNextcloud(@Header("Authorization") Observable<GenericOverall> unregisterDeviceForNotificationsWithNextcloud(@Header("Authorization")
String authorization, String authorization,
@Url String url); @Url String url);
@FormUrlEncoded @FormUrlEncoded
@POST @POST
Observable<Void> registerDeviceForNotificationsWithProxy(@Url String url, Observable<Void> registerDeviceForNotificationsWithProxy(@Url String url,
@FieldMap Map<String, String> fields); @FieldMap Map<String, String> fields);
/*
QueryMap items are as follows:
- "deviceIdentifier": "{{deviceIdentifier}}",
- "deviceIdentifierSignature": "{{signature}}",
- "userPublicKey": "{{userPublicKey}}"
*/
@DELETE
Observable<Void> unregisterDeviceForNotificationsWithProxy(@Url String url,
@QueryMap Map<String, String> fields);
/* @FormUrlEncoded
QueryMap items are as follows: @PUT
- "deviceIdentifier": "{{deviceIdentifier}}", Observable<GenericOverall> setPassword(@Header("Authorization") String authorization,
- "deviceIdentifierSignature": "{{signature}}", @Url String url,
- "userPublicKey": "{{userPublicKey}}" @Field("password") String password);
*/
@DELETE
Observable<Void> unregisterDeviceForNotificationsWithProxy(@Url String url,
@QueryMap Map<String, String> fields);
@FormUrlEncoded @GET
@PUT Observable<CapabilitiesOverall> getCapabilities(@Header("Authorization") String authorization,
Observable<GenericOverall> setPassword(@Header("Authorization") String authorization, @Url String url, @Url String url);
@Field("password") String password);
@GET /*
Observable<CapabilitiesOverall> getCapabilities(@Header("Authorization") String authorization, @Url String url); QueryMap items are as follows:
- "lookIntoFuture": int (0 or 1),
/* - "limit" : int, range 100-200,
QueryMap items are as follows: - "timeout": used with look into future, 30 default, 60 at most
- "lookIntoFuture": int (0 or 1), - "lastKnownMessageId", int, use one from X-Chat-Last-Given
- "limit" : int, range 100-200, */
- "timeout": used with look into future, 30 default, 60 at most @GET
- "lastKnownMessageId", int, use one from X-Chat-Last-Given Observable<Response<ChatOverall>> pullChatMessages(@Header("Authorization") String authorization,
*/ @Url String url,
@GET @QueryMap Map<String, Integer> fields);
Observable<Response<ChatOverall>> pullChatMessages(@Header("Authorization") String authorization, @Url String url,
@QueryMap Map<String, Integer> fields);
/* /*
Fieldmap items are as follows: Fieldmap items are as follows:
@ -288,51 +310,56 @@ public interface NcApi {
- "actorDisplayName" - "actorDisplayName"
*/ */
@FormUrlEncoded @FormUrlEncoded
@POST @POST
Observable<GenericOverall> sendChatMessage(@Header("Authorization") String authorization, @Url String url, Observable<GenericOverall> sendChatMessage(@Header("Authorization") String authorization,
@Field("message") CharSequence message, @Url String url,
@Field("actorDisplayName") String actorDisplayName); @Field("message") CharSequence message,
@Field("actorDisplayName") String actorDisplayName);
@GET @GET
Observable<MentionOverall> getMentionAutocompleteSuggestions(@Header("Authorization") String authorization, Observable<MentionOverall> getMentionAutocompleteSuggestions(
@Url String url, @Query("search") String query, @Header("Authorization") String authorization,
@Nullable @Query("limit") Integer limit); @Url String url, @Query("search") String query,
@Nullable @Query("limit") Integer limit);
// Url is: /api/{apiVersion}/room/{token}/pin // Url is: /api/{apiVersion}/room/{token}/pin
@POST @POST
Observable<GenericOverall> addConversationToFavorites(@Header("Authorization") String authorization, Observable<GenericOverall> addConversationToFavorites(
@Url String url); @Header("Authorization") String authorization,
@Url String url);
// Url is: /api/{apiVersion}/room/{token}/favorites // Url is: /api/{apiVersion}/room/{token}/favorites
@DELETE @DELETE
Observable<GenericOverall> removeConversationFromFavorites(@Header("Authorization") String authorization, Observable<GenericOverall> removeConversationFromFavorites(
@Url String url); @Header("Authorization") String authorization,
@Url String url);
@GET @GET
Observable<NotificationOverall> getNotification(@Header("Authorization") String authorization, Observable<NotificationOverall> getNotification(@Header("Authorization") String authorization,
@Url String url); @Url String url);
@FormUrlEncoded @FormUrlEncoded
@POST @POST
Observable<GenericOverall> setNotificationLevel(@Header("Authorization") String authorization, @Url String url, @Field("level") int level); Observable<GenericOverall> setNotificationLevel(@Header("Authorization") String authorization,
@Url String url, @Field("level") int level);
@FormUrlEncoded @FormUrlEncoded
@PUT @PUT
Observable<GenericOverall> setReadOnlyState(@Header("Authorization") String authorization, @Url String url, @Field("viewState") int state); Observable<GenericOverall> setReadOnlyState(@Header("Authorization") String authorization,
@Url String url, @Field("viewState") int state);
@FormUrlEncoded
@POST
Observable<Void> createRemoteShare(@Nullable @Header("Authorization") String authorization,
@Url String url,
@Field("path") String remotePath,
@Field("shareWith") String roomToken,
@Field("shareType") String shareType);
@FormUrlEncoded @FormUrlEncoded
@POST @PUT
Observable<Void> createRemoteShare(@Nullable @Header("Authorization") String authorization, @Url String url, Observable<GenericOverall> setLobbyForConversation(@Header("Authorization") String authorization,
@Field("path") String remotePath, @Url String url, @Field("viewState") Integer state,
@Field("shareWith") String roomToken, @Field("timer") Long timer);
@Field("shareType") String shareType);
@FormUrlEncoded
@PUT
Observable<GenericOverall> setLobbyForConversation(@Header("Authorization") String authorization,
@Url String url, @Field("viewState") Integer state,
@Field("timer") Long timer);
} }

View File

@ -29,7 +29,6 @@ import androidx.emoji.bundled.BundledEmojiCompatConfig
import androidx.emoji.text.EmojiCompat import androidx.emoji.text.EmojiCompat
import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleObserver
import androidx.multidex.MultiDex import androidx.multidex.MultiDex
import androidx.multidex.MultiDexApplication
import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequest
import androidx.work.PeriodicWorkRequest import androidx.work.PeriodicWorkRequest
@ -54,7 +53,6 @@ import com.nextcloud.talk.newarch.di.module.NetworkModule
import com.nextcloud.talk.newarch.di.module.StorageModule import com.nextcloud.talk.newarch.di.module.StorageModule
import com.nextcloud.talk.newarch.features.conversationsList.di.module.ConversationsListModule import com.nextcloud.talk.newarch.features.conversationsList.di.module.ConversationsListModule
import com.nextcloud.talk.utils.ClosedInterfaceImpl import com.nextcloud.talk.utils.ClosedInterfaceImpl
import com.nextcloud.talk.utils.DeviceUtils
import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.OkHttpNetworkFetcherWithCache import com.nextcloud.talk.utils.OkHttpNetworkFetcherWithCache
import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageModule import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageModule
@ -78,150 +76,174 @@ import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@AutoComponent(modules = [BusModule::class, ContextModule::class, DatabaseModule::class, RestModule::class, UserModule::class, ArbitraryStorageModule::class]) @AutoComponent(
modules = [BusModule::class, ContextModule::class, DatabaseModule::class, RestModule::class, UserModule::class, ArbitraryStorageModule::class]
)
@Singleton @Singleton
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class NextcloudTalkApplication : Application(), LifecycleObserver { class NextcloudTalkApplication : Application(), LifecycleObserver {
//region Fields (components) //region Fields (components)
lateinit var componentApplication: NextcloudTalkApplicationComponent lateinit var componentApplication: NextcloudTalkApplicationComponent
private set private set
//endregion //endregion
//region Getters //region Getters
@Inject @Inject
lateinit var appPreferences: AppPreferences lateinit var appPreferences: AppPreferences
@Inject @Inject
lateinit var okHttpClient: OkHttpClient lateinit var okHttpClient: OkHttpClient
//endregion //endregion
//region private methods //region private methods
private fun initializeWebRtc() { private fun initializeWebRtc() {
try { try {
if (MagicWebRTCUtils.HARDWARE_AEC_BLACKLIST.contains(Build.MODEL)) { if (MagicWebRTCUtils.HARDWARE_AEC_BLACKLIST.contains(Build.MODEL)) {
WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(true) WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(true)
} }
if (!MagicWebRTCUtils.OPEN_SL_ES_WHITELIST.contains(Build.MODEL)) { if (!MagicWebRTCUtils.OPEN_SL_ES_WHITELIST.contains(Build.MODEL)) {
WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true) WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true)
} }
PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(this) PeerConnectionFactory.initialize(
.setEnableVideoHwAcceleration(MagicWebRTCUtils.shouldEnableVideoHardwareAcceleration()) PeerConnectionFactory.InitializationOptions.builder(this)
.createInitializationOptions()) .setEnableVideoHwAcceleration(
} catch (e: UnsatisfiedLinkError) { MagicWebRTCUtils.shouldEnableVideoHardwareAcceleration()
Log.w(TAG, e) )
} .createInitializationOptions()
)
} catch (e: UnsatisfiedLinkError) {
Log.w(TAG, e)
} }
//endregion }
//region Overridden methods //endregion
override fun onCreate() {
sharedApplication = this
val securityKeyManager = SecurityKeyManager.getInstance() //region Overridden methods
val securityKeyConfig = SecurityKeyManagerConfig.Builder() override fun onCreate() {
.setEnableDebugLogging(BuildConfig.DEBUG) sharedApplication = this
val securityKeyManager = SecurityKeyManager.getInstance()
val securityKeyConfig = SecurityKeyManagerConfig.Builder()
.setEnableDebugLogging(BuildConfig.DEBUG)
.build()
securityKeyManager.init(this, securityKeyConfig)
initializeWebRtc()
DisplayUtils.useCompatVectorIfNeeded()
buildComponent()
DavUtils.registerCustomFactories()
componentApplication.inject(this)
setAppTheme(appPreferences.theme)
super.onCreate()
val imagePipelineConfig = ImagePipelineConfig.newBuilder(this)
.setNetworkFetcher(OkHttpNetworkFetcherWithCache(okHttpClient))
.setMainDiskCacheConfig(
DiskCacheConfig.newBuilder(this)
.setMaxCacheSize(0)
.setMaxCacheSizeOnLowDiskSpace(0)
.setMaxCacheSizeOnVeryLowDiskSpace(0)
.build() .build()
securityKeyManager.init(this, securityKeyConfig) )
.build()
initializeWebRtc() Fresco.initialize(this, imagePipelineConfig)
DisplayUtils.useCompatVectorIfNeeded() Security.insertProviderAt(Conscrypt.newProvider(), 1)
buildComponent()
DavUtils.registerCustomFactories()
componentApplication.inject(this) ClosedInterfaceImpl().providerInstallerInstallIfNeededAsync()
setAppTheme(appPreferences.theme) val pushRegistrationWork = OneTimeWorkRequest.Builder(PushRegistrationWorker::class.java)
super.onCreate() .build()
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java)
.build()
val periodicCapabilitiesUpdateWork = PeriodicWorkRequest.Builder(
CapabilitiesWorker::class.java,
12, TimeUnit.HOURS
)
.build()
val capabilitiesUpdateWork = OneTimeWorkRequest.Builder(CapabilitiesWorker::class.java)
.build()
val signalingSettingsWork = OneTimeWorkRequest.Builder(SignalingSettingsWorker::class.java)
.build()
val imagePipelineConfig = ImagePipelineConfig.newBuilder(this) WorkManager.getInstance()
.setNetworkFetcher(OkHttpNetworkFetcherWithCache(okHttpClient)) .enqueue(pushRegistrationWork)
.setMainDiskCacheConfig(DiskCacheConfig.newBuilder(this) WorkManager.getInstance()
.setMaxCacheSize(0) .enqueue(accountRemovalWork)
.setMaxCacheSizeOnLowDiskSpace(0) WorkManager.getInstance()
.setMaxCacheSizeOnVeryLowDiskSpace(0) .enqueue(capabilitiesUpdateWork)
.build()) WorkManager.getInstance()
.build() .enqueue(signalingSettingsWork)
WorkManager.getInstance()
.enqueueUniquePeriodicWork(
"DailyCapabilitiesUpdateWork", ExistingPeriodicWorkPolicy.REPLACE,
periodicCapabilitiesUpdateWork
)
Fresco.initialize(this, imagePipelineConfig) val config = BundledEmojiCompatConfig(this)
Security.insertProviderAt(Conscrypt.newProvider(), 1) config.setReplaceAll(true)
val emojiCompat = EmojiCompat.init(config)
ClosedInterfaceImpl().providerInstallerInstallIfNeededAsync() EmojiManager.install(GoogleCompatEmojiProvider(emojiCompat))
}
val pushRegistrationWork = OneTimeWorkRequest.Builder(PushRegistrationWorker::class.java).build() override fun onTerminate() {
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build() super.onTerminate()
val periodicCapabilitiesUpdateWork = PeriodicWorkRequest.Builder(CapabilitiesWorker::class.java, sharedApplication = null
12, TimeUnit.HOURS).build() }
val capabilitiesUpdateWork = OneTimeWorkRequest.Builder(CapabilitiesWorker::class.java).build() //endregion
val signalingSettingsWork = OneTimeWorkRequest.Builder(SignalingSettingsWorker::class.java).build()
WorkManager.getInstance().enqueue(pushRegistrationWork) //region Protected methods
WorkManager.getInstance().enqueue(accountRemovalWork) protected fun buildComponent() {
WorkManager.getInstance().enqueue(capabilitiesUpdateWork) componentApplication = DaggerNextcloudTalkApplicationComponent.builder()
WorkManager.getInstance().enqueue(signalingSettingsWork) .busModule(BusModule())
WorkManager.getInstance().enqueueUniquePeriodicWork("DailyCapabilitiesUpdateWork", ExistingPeriodicWorkPolicy.REPLACE, periodicCapabilitiesUpdateWork) .contextModule(ContextModule(applicationContext))
.databaseModule(DatabaseModule())
.restModule(RestModule(applicationContext))
.userModule(UserModule())
.arbitraryStorageModule(ArbitraryStorageModule())
.build()
val config = BundledEmojiCompatConfig(this) startKoin {
config.setReplaceAll(true) androidContext(this@NextcloudTalkApplication)
val emojiCompat = EmojiCompat.init(config) androidLogger()
modules(listOf(CommunicationModule, StorageModule, NetworkModule, ConversationsListModule))
EmojiManager.install(GoogleCompatEmojiProvider(emojiCompat))
} }
}
override fun onTerminate() { override fun attachBaseContext(base: Context) {
super.onTerminate() super.attachBaseContext(base)
sharedApplication = null MultiDex.install(this)
} }
companion object {
private val TAG = NextcloudTalkApplication::class.java.simpleName
//region Singleton
//endregion //endregion
var sharedApplication: NextcloudTalkApplication? = null
//region Protected methods protected set
protected fun buildComponent() {
componentApplication = DaggerNextcloudTalkApplicationComponent.builder()
.busModule(BusModule())
.contextModule(ContextModule(applicationContext))
.databaseModule(DatabaseModule())
.restModule(RestModule(applicationContext))
.userModule(UserModule())
.arbitraryStorageModule(ArbitraryStorageModule())
.build()
startKoin {
androidContext(this@NextcloudTalkApplication)
androidLogger()
modules(listOf(CommunicationModule, StorageModule, NetworkModule, ConversationsListModule))
}
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
companion object {
private val TAG = NextcloudTalkApplication::class.java.simpleName
//region Singleton
//endregion
var sharedApplication: NextcloudTalkApplication? = null
protected set
//endregion
//region Setters
fun setAppTheme(theme: String) {
when (theme) {
"night_no" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
"night_yes" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
"battery_saver" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
else ->
// will be "follow_system" only for now
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
}
//endregion //endregion
//region Setters
fun setAppTheme(theme: String) {
when (theme) {
"night_no" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
"night_yes" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
"battery_saver" -> AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY
)
else ->
// will be "follow_system" only for now
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
}
//endregion
} }

View File

@ -25,9 +25,9 @@ import android.text.Editable;
import android.text.Spanned; import android.text.Spanned;
import android.widget.EditText; import android.widget.EditText;
import com.facebook.widget.text.span.BetterImageSpan; import com.facebook.widget.text.span.BetterImageSpan;
import com.nextcloud.talk.models.json.mention.Mention;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.mention.Mention;
import com.nextcloud.talk.utils.DisplayUtils; import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.MagicCharPolicy; import com.nextcloud.talk.utils.MagicCharPolicy;
import com.nextcloud.talk.utils.text.Spans; import com.nextcloud.talk.utils.text.Spans;
@ -36,44 +36,44 @@ import com.vanniktech.emoji.EmojiRange;
import com.vanniktech.emoji.EmojiUtils; import com.vanniktech.emoji.EmojiUtils;
public class MentionAutocompleteCallback implements AutocompleteCallback<Mention> { public class MentionAutocompleteCallback implements AutocompleteCallback<Mention> {
private Context context; private Context context;
private UserEntity conversationUser; private UserEntity conversationUser;
private EditText editText; private EditText editText;
public MentionAutocompleteCallback(Context context, UserEntity conversationUser, public MentionAutocompleteCallback(Context context, UserEntity conversationUser,
EditText editText) { EditText editText) {
this.context = context; this.context = context;
this.conversationUser = conversationUser; this.conversationUser = conversationUser;
this.editText = editText; this.editText = editText;
}
@Override
public boolean onPopupItemClicked(Editable editable, Mention item) {
int[] range = MagicCharPolicy.getQueryRange(editable);
if (range == null) return false;
int start = range[0];
int end = range[1];
String replacement = item.getLabel();
StringBuilder replacementStringBuilder = new StringBuilder(item.getLabel());
for (EmojiRange emojiRange : EmojiUtils.emojis(replacement)) {
replacementStringBuilder.delete(emojiRange.start, emojiRange.end);
} }
@Override editable.replace(start, end, replacementStringBuilder.toString() + " ");
public boolean onPopupItemClicked(Editable editable, Mention item) { Spans.MentionChipSpan mentionChipSpan =
int[] range = MagicCharPolicy.getQueryRange(editable); new Spans.MentionChipSpan(DisplayUtils.getDrawableForMentionChipSpan(context,
if (range == null) return false; item.getId(), item.getLabel(), conversationUser, item.getSource(),
int start = range[0]; R.xml.chip_you, editText),
int end = range[1]; BetterImageSpan.ALIGN_CENTER,
String replacement = item.getLabel(); item.getId(), item.getLabel());
editable.setSpan(mentionChipSpan, start, start + replacementStringBuilder.toString().length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
return true;
}
StringBuilder replacementStringBuilder = new StringBuilder(item.getLabel()); @Override
for(EmojiRange emojiRange : EmojiUtils.emojis(replacement)) { public void onPopupVisibilityChanged(boolean shown) {
replacementStringBuilder.delete(emojiRange.start, emojiRange.end);
}
editable.replace(start, end, replacementStringBuilder.toString() + " "); }
Spans.MentionChipSpan mentionChipSpan =
new Spans.MentionChipSpan(DisplayUtils.getDrawableForMentionChipSpan(context,
item.getId(), item.getLabel(), conversationUser, item.getSource(),
R.xml.chip_you, editText),
BetterImageSpan.ALIGN_CENTER,
item.getId(), item.getLabel());
editable.setSpan(mentionChipSpan, start, start + replacementStringBuilder.toString().length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
return true;
}
@Override
public void onPopupVisibilityChanged(boolean shown) {
}
} }

View File

@ -50,136 +50,143 @@ import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class BrowserFileItem extends AbstractFlexibleItem<BrowserFileItem.ViewHolder> implements IFilterable<String> { public class BrowserFileItem extends AbstractFlexibleItem<BrowserFileItem.ViewHolder>
@Inject implements IFilterable<String> {
Context context; @Inject
private BrowserFile browserFile; Context context;
private UserEntity activeUser; private BrowserFile browserFile;
private SelectionInterface selectionInterface; private UserEntity activeUser;
private boolean selected; private SelectionInterface selectionInterface;
private boolean selected;
public BrowserFileItem(BrowserFile browserFile, UserEntity activeUser, SelectionInterface selectionInterface) { public BrowserFileItem(BrowserFile browserFile, UserEntity activeUser,
this.browserFile = browserFile; SelectionInterface selectionInterface) {
this.activeUser = activeUser; this.browserFile = browserFile;
this.selectionInterface = selectionInterface; this.activeUser = activeUser;
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); this.selectionInterface = selectionInterface;
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
}
@Override
public boolean equals(Object o) {
if (o instanceof BrowserFileItem) {
BrowserFileItem inItem = (BrowserFileItem) o;
return browserFile.getPath().equals(inItem.getModel().getPath());
} }
@Override return false;
public boolean equals(Object o) { }
if (o instanceof BrowserFileItem) {
BrowserFileItem inItem = (BrowserFileItem) o; public BrowserFile getModel() {
return browserFile.getPath().equals(inItem.getModel().getPath()); return browserFile;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_browser_file;
}
@Override
public ViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) {
return new ViewHolder(view, adapter);
}
private boolean isSelected() {
return selected;
}
private void setSelected(boolean selected) {
this.selected = selected;
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ViewHolder holder, int position,
List<Object> payloads) {
holder.fileIconImageView.setController(null);
if (browserFile.isEncrypted()) {
holder.fileEncryptedImageView.setVisibility(View.VISIBLE);
holder.itemView.setEnabled(false);
holder.itemView.setAlpha(0.38f);
} else {
holder.fileEncryptedImageView.setVisibility(View.GONE);
holder.itemView.setEnabled(true);
holder.itemView.setAlpha(1.0f);
}
if (browserFile.isFavorite()) {
holder.fileFavoriteImageView.setVisibility(View.VISIBLE);
} else {
holder.fileFavoriteImageView.setVisibility(View.GONE);
}
holder.fileIconImageView.getHierarchy()
.setPlaceholderImage(context.getDrawable(
DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(browserFile.getMimeType())));
if (browserFile.isHasPreview()) {
String path = ApiUtils.getUrlForFilePreviewWithRemotePath(activeUser.getBaseUrl(),
browserFile.getPath(),
context.getResources().getDimensionPixelSize(R.dimen.small_item_height));
if (path.length() > 0) {
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(path, null))
.build();
holder.fileIconImageView.setController(draweeController);
}
}
holder.filenameTextView.setText(browserFile.getDisplayName());
holder.fileModifiedTextView.setText(String.format(context.getString(R.string.nc_last_modified),
Formatter.formatShortFileSize(context, browserFile.getSize()),
DateUtils.INSTANCE.getLocalDateTimeStringFromTimestamp(
browserFile.getModifiedTimestamp())));
setSelected(selectionInterface.isPathSelected(browserFile.getPath()));
holder.selectFileCheckbox.setChecked(isSelected());
if (!browserFile.isEncrypted()) {
holder.selectFileCheckbox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (((CheckBox) v).isChecked() != isSelected()) {
setSelected(((CheckBox) v).isChecked());
selectionInterface.toggleBrowserItemSelection(browserFile.getPath());
}
} }
});
return false;
} }
public BrowserFile getModel() { holder.filenameTextView.setSelected(true);
return browserFile; holder.fileModifiedTextView.setSelected(true);
} }
@Override @Override
public int getLayoutRes() { public boolean filter(String constraint) {
return R.layout.rv_item_browser_file; return false;
} }
@Override static class ViewHolder extends FlexibleViewHolder {
public ViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) {
return new ViewHolder(view, adapter); @BindView(R.id.file_icon)
public SimpleDraweeView fileIconImageView;
} @BindView(R.id.file_modified_info)
public TextView fileModifiedTextView;
private boolean isSelected() { @BindView(R.id.filename_text_view)
return selected; public TextView filenameTextView;
} @BindView(R.id.select_file_checkbox)
public CheckBox selectFileCheckbox;
private void setSelected(boolean selected) { @BindView(R.id.fileEncryptedImageView)
this.selected = selected; public ImageView fileEncryptedImageView;
} @BindView(R.id.fileFavoriteImageView)
public ImageView fileFavoriteImageView;
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ViewHolder holder, int position, List<Object> payloads) { ViewHolder(View view, FlexibleAdapter adapter) {
holder.fileIconImageView.setController(null); super(view, adapter);
ButterKnife.bind(this, view);
if (browserFile.isEncrypted()) {
holder.fileEncryptedImageView.setVisibility(View.VISIBLE);
holder.itemView.setEnabled(false);
holder.itemView.setAlpha(0.38f);
} else {
holder.fileEncryptedImageView.setVisibility(View.GONE);
holder.itemView.setEnabled(true);
holder.itemView.setAlpha(1.0f);
}
if (browserFile.isFavorite()) {
holder.fileFavoriteImageView.setVisibility(View.VISIBLE);
} else {
holder.fileFavoriteImageView.setVisibility(View.GONE);
}
holder.fileIconImageView.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(browserFile.getMimeType())));
if (browserFile.isHasPreview()) {
String path = ApiUtils.getUrlForFilePreviewWithRemotePath(activeUser.getBaseUrl(),
browserFile.getPath(),
context.getResources().getDimensionPixelSize(R.dimen.small_item_height));
if (path.length() > 0) {
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(path, null))
.build();
holder.fileIconImageView.setController(draweeController);
}
}
holder.filenameTextView.setText(browserFile.getDisplayName());
holder.fileModifiedTextView.setText(String.format(context.getString(R.string.nc_last_modified),
Formatter.formatShortFileSize(context, browserFile.getSize()),
DateUtils.INSTANCE.getLocalDateTimeStringFromTimestamp(browserFile.getModifiedTimestamp())));
setSelected(selectionInterface.isPathSelected(browserFile.getPath()));
holder.selectFileCheckbox.setChecked(isSelected());
if (!browserFile.isEncrypted()) {
holder.selectFileCheckbox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (((CheckBox) v).isChecked() != isSelected()) {
setSelected(((CheckBox) v).isChecked());
selectionInterface.toggleBrowserItemSelection(browserFile.getPath());
}
}
});
}
holder.filenameTextView.setSelected(true);
holder.fileModifiedTextView.setSelected(true);
}
@Override
public boolean filter(String constraint) {
return false;
}
static class ViewHolder extends FlexibleViewHolder {
@BindView(R.id.file_icon)
public SimpleDraweeView fileIconImageView;
@BindView(R.id.file_modified_info)
public TextView fileModifiedTextView;
@BindView(R.id.filename_text_view)
public TextView filenameTextView;
@BindView(R.id.select_file_checkbox)
public CheckBox selectFileCheckbox;
@BindView(R.id.fileEncryptedImageView)
public ImageView fileEncryptedImageView;
@BindView(R.id.fileFavoriteImageView)
public ImageView fileFavoriteImageView;
ViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
}
} }
}
} }

View File

@ -71,278 +71,281 @@ import org.parceler.Parcels;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class BrowserController extends BaseController implements ListingInterface, public class BrowserController extends BaseController implements ListingInterface,
FlexibleAdapter.OnItemClickListener, SelectionInterface { FlexibleAdapter.OnItemClickListener, SelectionInterface {
private final Set<String> selectedPaths; private final Set<String> selectedPaths;
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@BindView(R.id.recyclerView) @BindView(R.id.recyclerView)
RecyclerView recyclerView; RecyclerView recyclerView;
@BindView(R.id.fast_scroller) @BindView(R.id.fast_scroller)
FastScroller fastScroller; FastScroller fastScroller;
@BindView(R.id.action_back) @BindView(R.id.action_back)
BottomNavigationItemView backMenuItem; BottomNavigationItemView backMenuItem;
@BindView(R.id.action_refresh) @BindView(R.id.action_refresh)
BottomNavigationItemView actionRefreshMenuItem; BottomNavigationItemView actionRefreshMenuItem;
@Inject @Inject
Context context; Context context;
@Inject @Inject
OkHttpClient okHttpClient; OkHttpClient okHttpClient;
private MenuItem filesSelectionDoneMenuItem; private MenuItem filesSelectionDoneMenuItem;
private RecyclerView.LayoutManager layoutManager; private RecyclerView.LayoutManager layoutManager;
private FlexibleAdapter<AbstractFlexibleItem> adapter; private FlexibleAdapter<AbstractFlexibleItem> adapter;
private List<AbstractFlexibleItem> recyclerViewItems = new ArrayList<>(); private List<AbstractFlexibleItem> recyclerViewItems = new ArrayList<>();
private ListingAbstractClass listingAbstractClass; private ListingAbstractClass listingAbstractClass;
private BrowserType browserType; private BrowserType browserType;
private String currentPath; private String currentPath;
private UserEntity activeUser; private UserEntity activeUser;
private String roomToken; private String roomToken;
public BrowserController(Bundle args) { public BrowserController(Bundle args) {
super(); super();
setHasOptionsMenu(true); setHasOptionsMenu(true);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication()
browserType = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_BROWSER_TYPE())); .getComponentApplication()
activeUser = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY())); .inject(this);
roomToken = args.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()); browserType = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_BROWSER_TYPE()));
activeUser = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY()));
roomToken = args.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN());
currentPath = "/"; currentPath = "/";
if (BrowserType.DAV_BROWSER.equals(browserType)) { if (BrowserType.DAV_BROWSER.equals(browserType)) {
listingAbstractClass = new DavListing(this); listingAbstractClass = new DavListing(this);
} else { } else {
//listingAbstractClass = new LocalListing(this); //listingAbstractClass = new LocalListing(this);
}
selectedPaths = Collections.synchronizedSet(new TreeSet<>());
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_browser, container, false);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
if (adapter == null) {
adapter = new FlexibleAdapter<>(recyclerViewItems, context, false);
}
changeEnabledStatusForBarItems(true);
prepareViews();
}
private void onFileSelectionDone() {
synchronized (selectedPaths) {
Iterator<String> iterator = selectedPaths.iterator();
List<String> paths = new ArrayList<>();
Data data;
OneTimeWorkRequest shareWorker;
while (iterator.hasNext()) {
String path = iterator.next();
paths.add(path);
iterator.remove();
if (paths.size() == 10 || !iterator.hasNext()) {
data = new Data.Builder()
.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), activeUser.getId())
.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), roomToken)
.putStringArray(BundleKeys.INSTANCE.getKEY_FILE_PATHS(), paths.toArray(new String[0]))
.build();
shareWorker = new OneTimeWorkRequest.Builder(ShareOperationWorker.class)
.setInputData(data)
.build();
WorkManager.getInstance().enqueue(shareWorker);
paths = new ArrayList<>();
} }
}
selectedPaths = Collections.synchronizedSet(new TreeSet<>());
} }
@Override getRouter().popCurrentController();
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { }
return inflater.inflate(R.layout.controller_browser, container, false);
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_share_files, menu);
filesSelectionDoneMenuItem = menu.findItem(R.id.files_selection_done);
filesSelectionDoneMenuItem.setVisible(selectedPaths.size() > 0);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.files_selection_done:
onFileSelectionDone();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
refreshCurrentPath();
}
@Override
public void onDestroy() {
super.onDestroy();
listingAbstractClass.tearDown();
}
@Override
public String getTitle() {
return currentPath;
}
@OnClick(R.id.action_back)
void goBack() {
fetchPath(new File(currentPath).getParent());
}
@OnClick(R.id.action_refresh)
void refreshCurrentPath() {
fetchPath(currentPath);
}
@SuppressLint("RestrictedApi")
private void changeEnabledStatusForBarItems(boolean shouldBeEnabled) {
if (actionRefreshMenuItem != null) {
actionRefreshMenuItem.setEnabled(shouldBeEnabled);
} }
@Override if (backMenuItem != null) {
protected void onViewBound(@NonNull View view) { backMenuItem.setEnabled(shouldBeEnabled && !currentPath.equals("/"));
super.onViewBound(view); }
if (adapter == null) { }
adapter = new FlexibleAdapter<>(recyclerViewItems, context, false);
}
changeEnabledStatusForBarItems(true); private void fetchPath(String path) {
prepareViews(); listingAbstractClass.cancelAllJobs();
changeEnabledStatusForBarItems(false);
listingAbstractClass.getFiles(path, activeUser,
BrowserType.DAV_BROWSER.equals(browserType) ? okHttpClient : null);
}
@Override
public void listingResult(DavResponse davResponse) {
adapter.clear();
List<AbstractFlexibleItem> fileBrowserItems = new ArrayList<>();
if (davResponse.getData() != null) {
final List<BrowserFile> objectList = (List<BrowserFile>) davResponse.getData();
currentPath = objectList.get(0).getPath();
if (getActivity() != null) {
getActivity().runOnUiThread(() -> setTitle());
}
for (int i = 1; i < objectList.size(); i++) {
fileBrowserItems.add(new BrowserFileItem(objectList.get(i), activeUser, this));
}
} }
private void onFileSelectionDone() { adapter.addItems(0, fileBrowserItems);
synchronized (selectedPaths) {
Iterator<String> iterator = selectedPaths.iterator();
List<String> paths = new ArrayList<>();
Data data;
OneTimeWorkRequest shareWorker;
while (iterator.hasNext()) {
String path = iterator.next();
paths.add(path);
iterator.remove();
if (paths.size() == 10 || !iterator.hasNext()) {
data = new Data.Builder()
.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), activeUser.getId())
.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), roomToken)
.putStringArray(BundleKeys.INSTANCE.getKEY_FILE_PATHS(), paths.toArray(new String[0]))
.build();
shareWorker = new OneTimeWorkRequest.Builder(ShareOperationWorker.class)
.setInputData(data)
.build();
WorkManager.getInstance().enqueue(shareWorker);
paths = new ArrayList<>();
}
}
}
getRouter().popCurrentController();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_share_files, menu);
filesSelectionDoneMenuItem = menu.findItem(R.id.files_selection_done);
filesSelectionDoneMenuItem.setVisible(selectedPaths.size() > 0);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.files_selection_done:
onFileSelectionDone();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
refreshCurrentPath();
}
@Override
public void onDestroy() {
super.onDestroy();
listingAbstractClass.tearDown();
}
@Override
public String getTitle() {
return currentPath;
}
@OnClick(R.id.action_back)
void goBack() {
fetchPath(new File(currentPath).getParent());
}
@OnClick(R.id.action_refresh)
void refreshCurrentPath() {
fetchPath(currentPath);
}
@SuppressLint("RestrictedApi")
private void changeEnabledStatusForBarItems(boolean shouldBeEnabled) {
if (actionRefreshMenuItem != null) {
actionRefreshMenuItem.setEnabled(shouldBeEnabled);
}
if (backMenuItem != null) {
backMenuItem.setEnabled(shouldBeEnabled && !currentPath.equals("/"));
}
}
private void fetchPath(String path) {
listingAbstractClass.cancelAllJobs();
changeEnabledStatusForBarItems(false);
listingAbstractClass.getFiles(path, activeUser, BrowserType.DAV_BROWSER.equals(browserType) ? okHttpClient : null);
}
@Override
public void listingResult(DavResponse davResponse) {
adapter.clear();
List<AbstractFlexibleItem> fileBrowserItems = new ArrayList<>();
if (davResponse.getData() != null) {
final List<BrowserFile> objectList = (List<BrowserFile>) davResponse.getData();
currentPath = objectList.get(0).getPath();
if (getActivity() != null) {
getActivity().runOnUiThread(() -> setTitle());
}
for (int i = 1; i < objectList.size(); i++) {
fileBrowserItems.add(new BrowserFileItem(objectList.get(i), activeUser, this));
}
}
adapter.addItems(0, fileBrowserItems);
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
adapter.notifyDataSetChanged();
changeEnabledStatusForBarItems(true);
});
}
}
private boolean shouldPathBeSelectedDueToParent(String currentPath) {
if (selectedPaths.size() > 0) {
File file = new File(currentPath);
if (!file.getParent().equals("/")) {
while (file.getParent() != null) {
String parent = file.getParent();
if (new File(file.getParent()).getParent() != null) {
parent += "/";
}
if (selectedPaths.contains(parent)) {
return true;
}
file = new File(file.getParent());
}
}
}
return false;
}
private void checkAndRemoveAnySelectedParents(String currentPath) {
File file = new File(currentPath);
selectedPaths.remove(currentPath);
while (file.getParent() != null) {
selectedPaths.remove(file.getParent() + "/");
file = new File(file.getParent());
}
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
changeEnabledStatusForBarItems(true);
});
} }
}
@Override private boolean shouldPathBeSelectedDueToParent(String currentPath) {
public boolean onItemClick(View view, int position) { if (selectedPaths.size() > 0) {
BrowserFile browserFile = ((BrowserFileItem) adapter.getItem(position)).getModel(); File file = new File(currentPath);
if ("inode/directory".equals((browserFile.getMimeType()))) { if (!file.getParent().equals("/")) {
fetchPath(browserFile.getPath()); while (file.getParent() != null) {
String parent = file.getParent();
if (new File(file.getParent()).getParent() != null) {
parent += "/";
}
if (selectedPaths.contains(parent)) {
return true; return true;
} }
return false; file = new File(file.getParent());
}
}
} }
private void prepareViews() { return false;
if (getActivity() != null) { }
layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
adapter.setFastScroller(fastScroller); private void checkAndRemoveAnySelectedParents(String currentPath) {
adapter.addListener(this); File file = new File(currentPath);
selectedPaths.remove(currentPath);
fastScroller.setBubbleTextCreator(position -> { while (file.getParent() != null) {
IFlexible abstractFlexibleItem = adapter.getItem(position); selectedPaths.remove(file.getParent() + "/");
if (abstractFlexibleItem instanceof BrowserFileItem) { file = new File(file.getParent());
return String.valueOf(((BrowserFileItem) adapter.getItem(position)).getModel().getDisplayName().charAt(0));
} else {
return "";
}
});
}
} }
@SuppressLint("RestrictedApi") adapter.notifyDataSetChanged();
@Override }
public void toggleBrowserItemSelection(String path) {
if (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path)) { @Override
checkAndRemoveAnySelectedParents(path); public boolean onItemClick(View view, int position) {
BrowserFile browserFile = ((BrowserFileItem) adapter.getItem(position)).getModel();
if ("inode/directory".equals((browserFile.getMimeType()))) {
fetchPath(browserFile.getPath());
return true;
}
return false;
}
private void prepareViews() {
if (getActivity() != null) {
layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
adapter.setFastScroller(fastScroller);
adapter.addListener(this);
fastScroller.setBubbleTextCreator(position -> {
IFlexible abstractFlexibleItem = adapter.getItem(position);
if (abstractFlexibleItem instanceof BrowserFileItem) {
return String.valueOf(
((BrowserFileItem) adapter.getItem(position)).getModel().getDisplayName().charAt(0));
} else { } else {
// TOOD: if it's a folder, remove all the children we added manually return "";
selectedPaths.add(path);
} }
});
}
}
filesSelectionDoneMenuItem.setVisible(selectedPaths.size() > 0); @SuppressLint("RestrictedApi")
@Override
public void toggleBrowserItemSelection(String path) {
if (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path)) {
checkAndRemoveAnySelectedParents(path);
} else {
// TOOD: if it's a folder, remove all the children we added manually
selectedPaths.add(path);
} }
@Override filesSelectionDoneMenuItem.setVisible(selectedPaths.size() > 0);
public boolean isPathSelected(String path) { }
return (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path));
}
@Parcel @Override
public enum BrowserType { public boolean isPathSelected(String path) {
FILE_BROWSER, return (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path));
DAV_BROWSER, }
}
@Parcel
public enum BrowserType {
FILE_BROWSER,
DAV_BROWSER,
}
} }

View File

@ -23,5 +23,5 @@ package com.nextcloud.talk.components.filebrowser.interfaces;
import com.nextcloud.talk.components.filebrowser.models.DavResponse; import com.nextcloud.talk.components.filebrowser.models.DavResponse;
public interface ListingInterface { public interface ListingInterface {
void listingResult(DavResponse davResponse); void listingResult(DavResponse davResponse);
} }

View File

@ -43,67 +43,68 @@ import org.parceler.Parcel;
@JsonObject @JsonObject
@Parcel @Parcel
public class BrowserFile { public class BrowserFile {
public String path; public String path;
public String displayName; public String displayName;
public String mimeType; public String mimeType;
public long modifiedTimestamp; public long modifiedTimestamp;
public long size; public long size;
public boolean isFile; public boolean isFile;
// Used for remote files // Used for remote files
public String remoteId; public String remoteId;
public boolean hasPreview; public boolean hasPreview;
public boolean favorite; public boolean favorite;
public boolean encrypted; public boolean encrypted;
public static BrowserFile getModelFromResponse(Response response, String remotePath) { public static BrowserFile getModelFromResponse(Response response, String remotePath) {
BrowserFile browserFile = new BrowserFile(); BrowserFile browserFile = new BrowserFile();
browserFile.setPath(Uri.decode(remotePath)); browserFile.setPath(Uri.decode(remotePath));
browserFile.setDisplayName(Uri.decode(new File(remotePath).getName())); browserFile.setDisplayName(Uri.decode(new File(remotePath).getName()));
final List<Property> properties = response.getProperties(); final List<Property> properties = response.getProperties();
for (Property property : properties) { for (Property property : properties) {
if (property instanceof OCId) { if (property instanceof OCId) {
browserFile.setRemoteId(((OCId) property).getOcId()); browserFile.setRemoteId(((OCId) property).getOcId());
} }
if (property instanceof ResourceType) { if (property instanceof ResourceType) {
browserFile.isFile = browserFile.isFile =
!(((ResourceType) property).getTypes().contains(ResourceType.Companion.getCOLLECTION())); !(((ResourceType) property).getTypes()
} .contains(ResourceType.Companion.getCOLLECTION()));
}
if (property instanceof GetLastModified) { if (property instanceof GetLastModified) {
browserFile.setModifiedTimestamp(((GetLastModified) property).getLastModified()); browserFile.setModifiedTimestamp(((GetLastModified) property).getLastModified());
} }
if (property instanceof GetContentType) { if (property instanceof GetContentType) {
browserFile.setMimeType(((GetContentType) property).getType()); browserFile.setMimeType(((GetContentType) property).getType());
} }
if (property instanceof OCSize) { if (property instanceof OCSize) {
browserFile.setSize(((OCSize) property).getOcSize()); browserFile.setSize(((OCSize) property).getOcSize());
} }
if (property instanceof NCPreview) { if (property instanceof NCPreview) {
browserFile.setHasPreview(((NCPreview) property).isNcPreview()); browserFile.setHasPreview(((NCPreview) property).isNcPreview());
} }
if (property instanceof OCFavorite) { if (property instanceof OCFavorite) {
browserFile.setFavorite(((OCFavorite) property).isOcFavorite()); browserFile.setFavorite(((OCFavorite) property).isOcFavorite());
} }
if (property instanceof DisplayName) { if (property instanceof DisplayName) {
browserFile.setDisplayName(((DisplayName) property).getDisplayName()); browserFile.setDisplayName(((DisplayName) property).getDisplayName());
} }
if (property instanceof NCEncrypted) { if (property instanceof NCEncrypted) {
browserFile.setEncrypted(((NCEncrypted) property).isNcEncrypted()); browserFile.setEncrypted(((NCEncrypted) property).isNcEncrypted());
} }
}
if (TextUtils.isEmpty(browserFile.getMimeType()) && !browserFile.isFile()) {
browserFile.setMimeType("inode/directory");
}
return browserFile;
} }
if (TextUtils.isEmpty(browserFile.getMimeType()) && !browserFile.isFile()) {
browserFile.setMimeType("inode/directory");
}
return browserFile;
}
} }

View File

@ -25,6 +25,6 @@ import lombok.Data;
@Data @Data
public class DavResponse { public class DavResponse {
Response response; Response response;
Object data; Object data;
} }

View File

@ -34,39 +34,40 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
public class NCEncrypted implements Property { public class NCEncrypted implements Property {
public static final Name NAME = new Name(DavUtils.NC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_IS_ENCRYPTED); public static final Name NAME =
new Name(DavUtils.NC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_IS_ENCRYPTED);
@Getter @Getter
@Setter @Setter
private boolean ncEncrypted; private boolean ncEncrypted;
private NCEncrypted(boolean isEncrypted) { private NCEncrypted(boolean isEncrypted) {
ncEncrypted = isEncrypted; ncEncrypted = isEncrypted;
}
public static class Factory implements PropertyFactory {
@Nullable
@Override
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new NCEncrypted(Boolean.parseBoolean(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new NCEncrypted(false);
} }
public static class Factory implements PropertyFactory { @NotNull
@Override
@Nullable public Name getName() {
@Override return NAME;
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new NCEncrypted(Boolean.parseBoolean(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new NCEncrypted(false);
}
@NotNull
@Override
public Name getName() {
return NAME;
}
} }
}
} }

View File

@ -34,39 +34,40 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
public class NCPreview implements Property { public class NCPreview implements Property {
public static final Property.Name NAME = new Property.Name(DavUtils.NC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_HAS_PREVIEW); public static final Property.Name NAME =
new Property.Name(DavUtils.NC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_HAS_PREVIEW);
@Getter @Getter
@Setter @Setter
private boolean ncPreview; private boolean ncPreview;
private NCPreview(boolean hasPreview) { private NCPreview(boolean hasPreview) {
ncPreview = hasPreview; ncPreview = hasPreview;
}
public static class Factory implements PropertyFactory {
@Nullable
@Override
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new NCPreview(Boolean.parseBoolean(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCFavorite(false);
} }
public static class Factory implements PropertyFactory { @NotNull
@Override
@Nullable public Property.Name getName() {
@Override return NAME;
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new NCPreview(Boolean.parseBoolean(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCFavorite(false);
}
@NotNull
@Override
public Property.Name getName() {
return NAME;
}
} }
}
} }

View File

@ -34,39 +34,40 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
public class OCFavorite implements Property { public class OCFavorite implements Property {
public static final Property.Name NAME = new Property.Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_FAVORITE); public static final Property.Name NAME =
new Property.Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_FAVORITE);
@Getter @Getter
@Setter @Setter
private boolean ocFavorite; private boolean ocFavorite;
OCFavorite(boolean isFavorite) { OCFavorite(boolean isFavorite) {
ocFavorite = isFavorite; ocFavorite = isFavorite;
}
public static class Factory implements PropertyFactory {
@Nullable
@Override
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new OCFavorite(Boolean.parseBoolean(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCFavorite(false);
} }
public static class Factory implements PropertyFactory { @NotNull
@Override
@Nullable public Property.Name getName() {
@Override return NAME;
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new OCFavorite(Boolean.parseBoolean(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCFavorite(false);
}
@NotNull
@Override
public Property.Name getName() {
return NAME;
}
} }
}
} }

View File

@ -34,39 +34,40 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
public class OCId implements Property { public class OCId implements Property {
public static final Name NAME = new Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_NAME_REMOTE_ID); public static final Name NAME =
new Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_NAME_REMOTE_ID);
@Getter @Getter
@Setter @Setter
private String ocId; private String ocId;
private OCId(String id) { private OCId(String id) {
ocId = id; ocId = id;
}
public static class Factory implements PropertyFactory {
@Nullable
@Override
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new OCId(text);
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCId("");
} }
public static class Factory implements PropertyFactory { @NotNull
@Override
@Nullable public Name getName() {
@Override return NAME;
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new OCId(text);
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCId("");
}
@NotNull
@Override
public Name getName() {
return NAME;
}
} }
}
} }

View File

@ -34,39 +34,40 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
public class OCSize implements Property { public class OCSize implements Property {
public static final Property.Name NAME = new Property.Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_NAME_SIZE); public static final Property.Name NAME =
new Property.Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_NAME_SIZE);
@Getter @Getter
@Setter @Setter
private long ocSize; private long ocSize;
private OCSize(long size) { private OCSize(long size) {
ocSize = size; ocSize = size;
}
public static class Factory implements PropertyFactory {
@Nullable
@Override
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new OCSize(Long.parseLong(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCSize(-1);
} }
public static class Factory implements PropertyFactory { @NotNull
@Override
@Nullable public Name getName() {
@Override return NAME;
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new OCSize(Long.parseLong(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCSize(-1);
}
@NotNull
@Override
public Name getName() {
return NAME;
}
} }
}
} }

View File

@ -33,36 +33,36 @@ import java.util.concurrent.Callable;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
public class DavListing extends ListingAbstractClass { public class DavListing extends ListingAbstractClass {
private DavResponse davResponse = new DavResponse(); private DavResponse davResponse = new DavResponse();
public DavListing(ListingInterface listingInterface) { public DavListing(ListingInterface listingInterface) {
super(listingInterface); super(listingInterface);
} }
@Override @Override
public void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient) { public void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient) {
Single.fromCallable(new Callable<ReadFilesystemOperation>() { Single.fromCallable(new Callable<ReadFilesystemOperation>() {
@Override @Override
public ReadFilesystemOperation call() { public ReadFilesystemOperation call() {
return new ReadFilesystemOperation(okHttpClient, currentUser, path, 1); return new ReadFilesystemOperation(okHttpClient, currentUser, path, 1);
} }
}).subscribeOn(Schedulers.io()) }).subscribeOn(Schedulers.io())
.subscribe(new SingleObserver<ReadFilesystemOperation>() { .subscribe(new SingleObserver<ReadFilesystemOperation>() {
@Override @Override
public void onSubscribe(Disposable d) { public void onSubscribe(Disposable d) {
} }
@Override @Override
public void onSuccess(ReadFilesystemOperation readFilesystemOperation) { public void onSuccess(ReadFilesystemOperation readFilesystemOperation) {
davResponse = readFilesystemOperation.readRemotePath(); davResponse = readFilesystemOperation.readRemotePath();
listingInterface.listingResult(davResponse); listingInterface.listingResult(davResponse);
} }
@Override @Override
public void onError(Throwable e) { public void onError(Throwable e) {
listingInterface.listingResult(davResponse); listingInterface.listingResult(davResponse);
} }
}); });
} }
} }

View File

@ -27,22 +27,23 @@ import com.nextcloud.talk.models.database.UserEntity;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
public abstract class ListingAbstractClass { public abstract class ListingAbstractClass {
Handler handler; Handler handler;
ListingInterface listingInterface; ListingInterface listingInterface;
ListingAbstractClass(ListingInterface listingInterface) { ListingAbstractClass(ListingInterface listingInterface) {
handler = new Handler(); handler = new Handler();
this.listingInterface = listingInterface; this.listingInterface = listingInterface;
} }
public abstract void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient); public abstract void getFiles(String path, UserEntity currentUser,
@Nullable OkHttpClient okHttpClient);
public void cancelAllJobs() { public void cancelAllJobs() {
handler.removeCallbacksAndMessages(null); handler.removeCallbacksAndMessages(null);
} }
public void tearDown() { public void tearDown() {
cancelAllJobs(); cancelAllJobs();
handler = null; handler = null;
} }
} }

View File

@ -42,78 +42,76 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public class DavUtils { public class DavUtils {
public static final String OC_NAMESPACE = "http://owncloud.org/ns"; public static final String OC_NAMESPACE = "http://owncloud.org/ns";
public static final String NC_NAMESPACE = "http://nextcloud.org/ns"; public static final String NC_NAMESPACE = "http://nextcloud.org/ns";
public static final String DAV_PATH = "/remote.php/dav/files/"; public static final String DAV_PATH = "/remote.php/dav/files/";
public static final String EXTENDED_PROPERTY_NAME_PERMISSIONS = "permissions"; public static final String EXTENDED_PROPERTY_NAME_PERMISSIONS = "permissions";
public static final String EXTENDED_PROPERTY_NAME_REMOTE_ID = "id"; public static final String EXTENDED_PROPERTY_NAME_REMOTE_ID = "id";
public static final String EXTENDED_PROPERTY_NAME_SIZE = "size"; public static final String EXTENDED_PROPERTY_NAME_SIZE = "size";
public static final String EXTENDED_PROPERTY_FAVORITE = "favorite"; public static final String EXTENDED_PROPERTY_FAVORITE = "favorite";
public static final String EXTENDED_PROPERTY_IS_ENCRYPTED = "is-encrypted"; public static final String EXTENDED_PROPERTY_IS_ENCRYPTED = "is-encrypted";
public static final String EXTENDED_PROPERTY_MOUNT_TYPE = "mount-type"; public static final String EXTENDED_PROPERTY_MOUNT_TYPE = "mount-type";
public static final String EXTENDED_PROPERTY_OWNER_ID = "owner-id"; public static final String EXTENDED_PROPERTY_OWNER_ID = "owner-id";
public static final String EXTENDED_PROPERTY_OWNER_DISPLAY_NAME = "owner-display-name"; public static final String EXTENDED_PROPERTY_OWNER_DISPLAY_NAME = "owner-display-name";
public static final String EXTENDED_PROPERTY_UNREAD_COMMENTS = "comments-unread"; public static final String EXTENDED_PROPERTY_UNREAD_COMMENTS = "comments-unread";
public static final String EXTENDED_PROPERTY_HAS_PREVIEW = "has-preview"; public static final String EXTENDED_PROPERTY_HAS_PREVIEW = "has-preview";
public static final String EXTENDED_PROPERTY_NOTE = "note"; public static final String EXTENDED_PROPERTY_NOTE = "note";
public static final String TRASHBIN_FILENAME = "trashbin-filename"; public static final String TRASHBIN_FILENAME = "trashbin-filename";
public static final String TRASHBIN_ORIGINAL_LOCATION = "trashbin-original-location"; public static final String TRASHBIN_ORIGINAL_LOCATION = "trashbin-original-location";
public static final String TRASHBIN_DELETION_TIME = "trashbin-deletion-time"; public static final String TRASHBIN_DELETION_TIME = "trashbin-deletion-time";
public static final String PROPERTY_QUOTA_USED_BYTES = "quota-used-bytes"; public static final String PROPERTY_QUOTA_USED_BYTES = "quota-used-bytes";
public static final String PROPERTY_QUOTA_AVAILABLE_BYTES = "quota-available-bytes"; public static final String PROPERTY_QUOTA_AVAILABLE_BYTES = "quota-available-bytes";
static Property.Name[] getAllPropSet() { static Property.Name[] getAllPropSet() {
List<Property.Name> propSet = new ArrayList<>(); List<Property.Name> propSet = new ArrayList<>();
propSet.add(DisplayName.NAME); propSet.add(DisplayName.NAME);
propSet.add(GetContentType.NAME); propSet.add(GetContentType.NAME);
propSet.add(GetContentLength.NAME); propSet.add(GetContentLength.NAME);
propSet.add(GetContentType.NAME); propSet.add(GetContentType.NAME);
propSet.add(GetContentLength.NAME); propSet.add(GetContentLength.NAME);
propSet.add(GetLastModified.NAME); propSet.add(GetLastModified.NAME);
propSet.add(CreationDate.NAME); propSet.add(CreationDate.NAME);
propSet.add(GetETag.NAME); propSet.add(GetETag.NAME);
propSet.add(ResourceType.NAME); propSet.add(ResourceType.NAME);
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_NAME_PERMISSIONS)); propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_NAME_PERMISSIONS));
propSet.add(OCId.NAME); propSet.add(OCId.NAME);
propSet.add(OCSize.NAME); propSet.add(OCSize.NAME);
propSet.add(OCFavorite.NAME); propSet.add(OCFavorite.NAME);
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_ID)); propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_ID));
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_DISPLAY_NAME)); propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_DISPLAY_NAME));
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_UNREAD_COMMENTS)); propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_UNREAD_COMMENTS));
propSet.add(NCEncrypted.NAME); propSet.add(NCEncrypted.NAME);
propSet.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_MOUNT_TYPE)); propSet.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_MOUNT_TYPE));
propSet.add(NCPreview.NAME); propSet.add(NCPreview.NAME);
propSet.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_NOTE)); propSet.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_NOTE));
return propSet.toArray(new Property.Name[0]); return propSet.toArray(new Property.Name[0]);
}
public static void registerCustomFactories() {
PropertyRegistry propertyRegistry = PropertyRegistry.INSTANCE;
try {
Field factories = propertyRegistry.getClass().getDeclaredField("factories");
factories.setAccessible(true);
Map<Property.Name, PropertyFactory> reflectionMap = (HashMap<Property.Name,
PropertyFactory>) factories.get(propertyRegistry);
reflectionMap.put(OCId.NAME, new OCId.Factory());
reflectionMap.put(NCPreview.NAME, new NCPreview.Factory());
reflectionMap.put(NCEncrypted.NAME, new NCEncrypted.Factory());
reflectionMap.put(OCFavorite.NAME, new OCFavorite.Factory());
reflectionMap.put(OCSize.NAME, new OCSize.Factory());
factories.set(propertyRegistry, reflectionMap);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} }
}
public static void registerCustomFactories() {
PropertyRegistry propertyRegistry = PropertyRegistry.INSTANCE;
try {
Field factories = propertyRegistry.getClass().getDeclaredField("factories");
factories.setAccessible(true);
Map<Property.Name, PropertyFactory> reflectionMap = (HashMap<Property.Name,
PropertyFactory>) factories.get(propertyRegistry);
reflectionMap.put(OCId.NAME, new OCId.Factory());
reflectionMap.put(NCPreview.NAME, new NCPreview.Factory());
reflectionMap.put(NCEncrypted.NAME, new NCEncrypted.Factory());
reflectionMap.put(OCFavorite.NAME, new OCFavorite.Factory());
reflectionMap.put(OCSize.NAME, new OCSize.Factory());
factories.set(propertyRegistry, reflectionMap);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
} }

View File

@ -37,63 +37,64 @@ import okhttp3.HttpUrl;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
public class ReadFilesystemOperation { public class ReadFilesystemOperation {
private final OkHttpClient okHttpClient; private final OkHttpClient okHttpClient;
private final String url; private final String url;
private final int depth; private final int depth;
private final String basePath; private final String basePath;
public ReadFilesystemOperation(OkHttpClient okHttpClient, UserEntity currentUser, String path, int depth) { public ReadFilesystemOperation(OkHttpClient okHttpClient, UserEntity currentUser, String path,
OkHttpClient.Builder okHttpClientBuilder = okHttpClient.newBuilder(); int depth) {
okHttpClientBuilder.followRedirects(false); OkHttpClient.Builder okHttpClientBuilder = okHttpClient.newBuilder();
okHttpClientBuilder.followSslRedirects(false); okHttpClientBuilder.followRedirects(false);
okHttpClientBuilder.authenticator(new RestModule.MagicAuthenticator(ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()), "Authorization")); okHttpClientBuilder.followSslRedirects(false);
this.okHttpClient = okHttpClientBuilder.build(); okHttpClientBuilder.authenticator(new RestModule.MagicAuthenticator(
this.basePath = currentUser.getBaseUrl() + DavUtils.DAV_PATH + currentUser.getUserId(); ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()),
this.url = basePath + path; "Authorization"));
this.depth = depth; this.okHttpClient = okHttpClientBuilder.build();
this.basePath = currentUser.getBaseUrl() + DavUtils.DAV_PATH + currentUser.getUserId();
this.url = basePath + path;
this.depth = depth;
}
public DavResponse readRemotePath() {
DavResponse davResponse = new DavResponse();
final List<Response> memberElements = new ArrayList<>();
final Response[] rootElement = new Response[1];
final List<BrowserFile> remoteFiles = new ArrayList<>();
try {
new DavResource(okHttpClient, HttpUrl.parse(url)).propfind(depth, DavUtils.getAllPropSet(),
new Function2<Response, Response.HrefRelation, Unit>() {
@Override
public Unit invoke(Response response, Response.HrefRelation hrefRelation) {
davResponse.setResponse(response);
switch (hrefRelation) {
case MEMBER:
memberElements.add(response);
break;
case SELF:
rootElement[0] = response;
break;
case OTHER:
default:
}
return Unit.INSTANCE;
}
});
} catch (IOException e) {
e.printStackTrace();
} catch (DavException e) {
e.printStackTrace();
} }
public DavResponse readRemotePath() { remoteFiles.add(BrowserFile.getModelFromResponse(rootElement[0],
DavResponse davResponse = new DavResponse(); rootElement[0].getHref().toString().substring(basePath.length())));
final List<Response> memberElements = new ArrayList<>(); for (Response memberElement : memberElements) {
final Response[] rootElement = new Response[1]; remoteFiles.add(BrowserFile.getModelFromResponse(memberElement,
final List<BrowserFile> remoteFiles = new ArrayList<>(); memberElement.getHref().toString().substring(basePath.length())));
try {
new DavResource(okHttpClient, HttpUrl.parse(url)).propfind(depth, DavUtils.getAllPropSet(),
new Function2<Response, Response.HrefRelation, Unit>() {
@Override
public Unit invoke(Response response, Response.HrefRelation hrefRelation) {
davResponse.setResponse(response);
switch (hrefRelation) {
case MEMBER:
memberElements.add(response);
break;
case SELF:
rootElement[0] = response;
break;
case OTHER:
default:
}
return Unit.INSTANCE;
}
});
} catch (IOException e) {
e.printStackTrace();
} catch (DavException e) {
e.printStackTrace();
}
remoteFiles.add(BrowserFile.getModelFromResponse(rootElement[0],
rootElement[0].getHref().toString().substring(basePath.length())));
for (Response memberElement : memberElements) {
remoteFiles.add(BrowserFile.getModelFromResponse(memberElement,
memberElement.getHref().toString().substring(basePath.length())));
}
davResponse.setData(remoteFiles);
return davResponse;
} }
davResponse.setData(remoteFiles);
return davResponse;
}
} }

View File

@ -36,9 +36,6 @@ import autodagger.AutoInjector;
import butterknife.BindView; import butterknife.BindView;
import com.bluelinelabs.conductor.RouterTransaction; import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.nextcloud.talk.models.json.conversations.RoomsOverall;
import com.nextcloud.talk.models.json.generic.Status;
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
@ -48,6 +45,9 @@ import com.nextcloud.talk.jobs.CapabilitiesWorker;
import com.nextcloud.talk.jobs.PushRegistrationWorker; import com.nextcloud.talk.jobs.PushRegistrationWorker;
import com.nextcloud.talk.jobs.SignalingSettingsWorker; import com.nextcloud.talk.jobs.SignalingSettingsWorker;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.conversations.RoomsOverall;
import com.nextcloud.talk.models.json.generic.Status;
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall;
import com.nextcloud.talk.newarch.features.conversationsList.ConversationsListView; import com.nextcloud.talk.newarch.features.conversationsList.ConversationsListView;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.ClosedInterfaceImpl; import com.nextcloud.talk.utils.ClosedInterfaceImpl;
@ -67,426 +67,435 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode; import org.greenrobot.eventbus.ThreadMode;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class AccountVerificationController extends BaseController { public class AccountVerificationController extends BaseController {
public static final String TAG = "AccountVerificationController"; public static final String TAG = "AccountVerificationController";
@Inject @Inject
NcApi ncApi; NcApi ncApi;
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
CookieManager cookieManager; CookieManager cookieManager;
@Inject @Inject
AppPreferences appPreferences; AppPreferences appPreferences;
@Inject @Inject
EventBus eventBus; EventBus eventBus;
@BindView(R.id.progress_text) @BindView(R.id.progress_text)
TextView progressText; TextView progressText;
private long internalAccountId = -1; private long internalAccountId = -1;
private String baseUrl; private String baseUrl;
private String username; private String username;
private String token; private String token;
private boolean isAccountImport; private boolean isAccountImport;
private String originalProtocol; private String originalProtocol;
public AccountVerificationController(Bundle args) { public AccountVerificationController(Bundle args) {
super(); super();
if (args != null) { if (args != null) {
baseUrl = args.getString(BundleKeys.INSTANCE.getKEY_BASE_URL()); baseUrl = args.getString(BundleKeys.INSTANCE.getKEY_BASE_URL());
username = args.getString(BundleKeys.INSTANCE.getKEY_USERNAME()); username = args.getString(BundleKeys.INSTANCE.getKEY_USERNAME());
token = args.getString(BundleKeys.INSTANCE.getKEY_TOKEN()); token = args.getString(BundleKeys.INSTANCE.getKEY_TOKEN());
if (args.containsKey(BundleKeys.INSTANCE.getKEY_IS_ACCOUNT_IMPORT())) { if (args.containsKey(BundleKeys.INSTANCE.getKEY_IS_ACCOUNT_IMPORT())) {
isAccountImport = true; isAccountImport = true;
} }
if (args.containsKey(BundleKeys.INSTANCE.getKEY_ORIGINAL_PROTOCOL())) { if (args.containsKey(BundleKeys.INSTANCE.getKEY_ORIGINAL_PROTOCOL())) {
originalProtocol = args.getString(BundleKeys.INSTANCE.getKEY_ORIGINAL_PROTOCOL()); originalProtocol = args.getString(BundleKeys.INSTANCE.getKEY_ORIGINAL_PROTOCOL());
} }
} }
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_account_verification, container, false);
}
@Override
protected void onDetach(@NonNull View view) {
eventBus.unregister(this);
super.onDetach(view);
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
eventBus.register(this);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} }
@Override if (getActionBar() != null) {
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { getActionBar().hide();
return inflater.inflate(R.layout.controller_account_verification, container, false);
} }
@Override if (isAccountImport && !baseUrl.startsWith("http://") && !baseUrl.startsWith("https://")
protected void onDetach(@NonNull View view) { || (!TextUtils
eventBus.unregister(this); .isEmpty(originalProtocol) && !baseUrl.startsWith(originalProtocol))) {
super.onDetach(view); determineBaseUrlProtocol(true);
} else {
checkEverything();
}
}
private void checkEverything() {
String credentials = ApiUtils.getCredentials(username, token);
cookieManager.getCookieStore().removeAll();
findServerTalkApp(credentials);
}
private void determineBaseUrlProtocol(boolean checkForcedHttps) {
cookieManager.getCookieStore().removeAll();
String queryUrl;
baseUrl = baseUrl.replace("http://", "").replace("https://", "");
if (checkForcedHttps) {
queryUrl = "https://" + baseUrl + ApiUtils.getUrlPostfixForStatus();
} else {
queryUrl = "http://" + baseUrl + ApiUtils.getUrlPostfixForStatus();
} }
@Override ncApi.getServerStatus(queryUrl)
protected void onAttach(@NonNull View view) { .subscribeOn(Schedulers.io())
super.onAttach(view); .observeOn(AndroidSchedulers.mainThread())
eventBus.register(this); .as(AutoDispose.autoDisposable(getScopeProvider()))
} .subscribe(new Observer<Status>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override @Override
protected void onViewBound(@NonNull View view) { public void onNext(Status status) {
super.onViewBound(view); if (checkForcedHttps) {
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); baseUrl = "https://" + baseUrl;
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
if (getActionBar() != null) {
getActionBar().hide();
}
if (isAccountImport && !baseUrl.startsWith("http://") && !baseUrl.startsWith("https://") || (!TextUtils
.isEmpty(originalProtocol) && !baseUrl.startsWith(originalProtocol))) {
determineBaseUrlProtocol(true);
} else {
checkEverything();
}
}
private void checkEverything() {
String credentials = ApiUtils.getCredentials(username, token);
cookieManager.getCookieStore().removeAll();
findServerTalkApp(credentials);
}
private void determineBaseUrlProtocol(boolean checkForcedHttps) {
cookieManager.getCookieStore().removeAll();
String queryUrl;
baseUrl = baseUrl.replace("http://", "").replace("https://", "");
if (checkForcedHttps) {
queryUrl = "https://" + baseUrl + ApiUtils.getUrlPostfixForStatus();
} else {
queryUrl = "http://" + baseUrl + ApiUtils.getUrlPostfixForStatus();
}
ncApi.getServerStatus(queryUrl)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<Status>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Status status) {
if (checkForcedHttps) {
baseUrl = "https://" + baseUrl;
} else {
baseUrl = "http://" + baseUrl;
}
if (isAccountImport) {
getRouter().replaceTopController(RouterTransaction.with(new WebViewLoginController(baseUrl,
false, username, ""))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
checkEverything();
}
}
@Override
public void onError(Throwable e) {
if (checkForcedHttps) {
determineBaseUrlProtocol(false);
} else {
abortVerification();
}
}
@Override
public void onComplete() {
}
});
}
private void findServerTalkApp(String credentials) {
ncApi.getRooms(credentials, ApiUtils.getUrlForGetRooms(baseUrl))
.subscribeOn(Schedulers.io())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<RoomsOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(RoomsOverall roomsOverall) {
fetchProfile(credentials);
}
@Override
public void onError(Throwable e) {
if (getActivity() != null && getResources() != null) {
getActivity().runOnUiThread(() -> progressText.setText(String.format(getResources().getString(
R.string.nc_nextcloud_talk_app_not_installed), getResources().getString(R.string.nc_app_name))));
}
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK);
abortVerification();
}
@Override
public void onComplete() {
}
});
}
private void storeProfile(String displayName, String userId) {
userUtils.createOrUpdateUser(username, token,
baseUrl, displayName, null, true,
userId, null, null,
appPreferences.getTemporaryClientCertAlias(), null)
.subscribeOn(Schedulers.io())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<UserEntity>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(UserEntity userEntity) {
internalAccountId = userEntity.getId();
if (new ClosedInterfaceImpl().isGooglePlayServicesAvailable()) {
registerForPush();
} else {
getActivity().runOnUiThread(() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_push_disabled)));
fetchAndStoreCapabilities();
}
}
@Override
public void onError(Throwable e) {
progressText.setText(progressText.getText().toString() +
"\n" +
getResources().getString(
R.string.nc_display_name_not_stored));
abortVerification();
}
@Override
public void onComplete() {
}
});
}
private void fetchProfile(String credentials) {
ncApi.getUserProfile(credentials,
ApiUtils.getUrlForUserProfile(baseUrl))
.subscribeOn(Schedulers.io())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<UserProfileOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(UserProfileOverall userProfileOverall) {
String displayName = null;
if (!TextUtils.isEmpty(userProfileOverall.getOcs().getData()
.getDisplayName())) {
displayName = userProfileOverall.getOcs().getData()
.getDisplayName();
} else if (!TextUtils.isEmpty(userProfileOverall.getOcs().getData()
.getDisplayNameAlt())) {
displayName = userProfileOverall.getOcs().getData()
.getDisplayNameAlt();
}
if (!TextUtils.isEmpty(displayName)) {
storeProfile(displayName, userProfileOverall.getOcs().getData().getUserId());
} else {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_display_name_not_fetched)));
}
abortVerification();
}
}
@Override
public void onError(Throwable e) {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_display_name_not_fetched)));
}
abortVerification();
}
@Override
public void onComplete() {
}
});
}
private void registerForPush() {
OneTimeWorkRequest pushRegistrationWork = new OneTimeWorkRequest.Builder(PushRegistrationWorker.class).build();
WorkManager.getInstance().enqueue(pushRegistrationWork);
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEvent(EventStatus eventStatus) {
if (eventStatus.getEventType().equals(EventStatus.EventType.PUSH_REGISTRATION)) {
if (internalAccountId == eventStatus.getUserId() && !eventStatus.isAllGood() && getActivity() != null) {
getActivity().runOnUiThread(() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_push_disabled)));
}
fetchAndStoreCapabilities();
} else if (eventStatus.getEventType().equals(EventStatus.EventType.CAPABILITIES_FETCH)) {
if (internalAccountId == eventStatus.getUserId() && !eventStatus.isAllGood()) {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_capabilities_failed)));
}
abortVerification();
} else if (internalAccountId == eventStatus.getUserId() && eventStatus.isAllGood()) {
fetchAndStoreExternalSignalingSettings();
}
} else if (eventStatus.getEventType().equals(EventStatus.EventType.SIGNALING_SETTINGS)) {
if (internalAccountId == eventStatus.getUserId() && !eventStatus.isAllGood()) {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_external_server_failed)));
}
}
proceedWithLogin();
}
}
private void fetchAndStoreCapabilities() {
Data userData = new Data.Builder()
.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), internalAccountId)
.build();
OneTimeWorkRequest pushNotificationWork = new OneTimeWorkRequest.Builder(CapabilitiesWorker.class)
.setInputData(userData)
.build();
WorkManager.getInstance().enqueue(pushNotificationWork);
}
private void fetchAndStoreExternalSignalingSettings() {
Data userData = new Data.Builder()
.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), internalAccountId)
.build();
OneTimeWorkRequest signalingSettings = new OneTimeWorkRequest.Builder(SignalingSettingsWorker.class)
.setInputData(userData)
.build();
WorkManager.getInstance().enqueue(signalingSettings);
}
private void proceedWithLogin() {
cookieManager.getCookieStore().removeAll();
userUtils.disableAllUsersWithoutId(internalAccountId);
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
if (userUtils.getUsers().size() == 1) {
getRouter().setRoot(RouterTransaction.with(new
ConversationsListView())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
if (isAccountImport) {
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.ACCOUNT_WAS_IMPORTED);
}
getRouter().popToRoot();
}
});
}
}
@Override
protected void onDestroyView(@NonNull View view) {
super.onDestroyView(view);
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
}
}
private void abortVerification() {
if (!isAccountImport) {
if (internalAccountId != -1) {
userUtils.deleteUserWithId(internalAccountId).subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
new Handler().postDelayed(() -> getRouter().popToRoot(), 7500);
});
}
}
@Override
public void onError(Throwable e) {
}
});
} else { } else {
if (getActivity() != null) { baseUrl = "http://" + baseUrl;
getActivity().runOnUiThread(() -> {
new Handler().postDelayed(() -> getRouter().popToRoot(), 7500);
});
}
} }
} else {
if (isAccountImport) {
getRouter().replaceTopController(
RouterTransaction.with(new WebViewLoginController(baseUrl,
false, username, ""))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
checkEverything();
}
}
@Override
public void onError(Throwable e) {
if (checkForcedHttps) {
determineBaseUrlProtocol(false);
} else {
abortVerification();
}
}
@Override
public void onComplete() {
}
});
}
private void findServerTalkApp(String credentials) {
ncApi.getRooms(credentials, ApiUtils.getUrlForGetRooms(baseUrl))
.subscribeOn(Schedulers.io())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<RoomsOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(RoomsOverall roomsOverall) {
fetchProfile(credentials);
}
@Override
public void onError(Throwable e) {
if (getActivity() != null && getResources() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(String.format(getResources().getString(
R.string.nc_nextcloud_talk_app_not_installed),
getResources().getString(R.string.nc_app_name))));
}
ApplicationWideMessageHolder.getInstance().setMessageType( ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT); ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK);
if (getActivity() != null) {
getActivity().runOnUiThread(() -> new Handler().postDelayed(() -> {
if (getRouter().hasRootController()) {
if (getActivity() != null) {
getRouter().popToRoot();
}
abortVerification();
}
} else { @Override
if (userUtils.anyUserExists()) { public void onComplete() {
getRouter().setRoot(RouterTransaction.with(new ConversationsListView())
.pushChangeHandler(new HorizontalChangeHandler()) }
.popChangeHandler(new HorizontalChangeHandler())); });
} else { }
getRouter().setRoot(RouterTransaction.with(new ServerSelectionController())
.pushChangeHandler(new HorizontalChangeHandler()) private void storeProfile(String displayName, String userId) {
.popChangeHandler(new HorizontalChangeHandler())); userUtils.createOrUpdateUser(username, token,
} baseUrl, displayName, null, true,
} userId, null, null,
}, 7500)); appPreferences.getTemporaryClientCertAlias(), null)
.subscribeOn(Schedulers.io())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<UserEntity>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(UserEntity userEntity) {
internalAccountId = userEntity.getId();
if (new ClosedInterfaceImpl().isGooglePlayServicesAvailable()) {
registerForPush();
} else {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_push_disabled)));
fetchAndStoreCapabilities();
} }
} }
}
@Override
public void onError(Throwable e) {
progressText.setText(progressText.getText().toString() +
"\n" +
getResources().getString(
R.string.nc_display_name_not_stored));
abortVerification();
}
@Override
public void onComplete() {
}
});
}
private void fetchProfile(String credentials) {
ncApi.getUserProfile(credentials,
ApiUtils.getUrlForUserProfile(baseUrl))
.subscribeOn(Schedulers.io())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<UserProfileOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(UserProfileOverall userProfileOverall) {
String displayName = null;
if (!TextUtils.isEmpty(userProfileOverall.getOcs().getData()
.getDisplayName())) {
displayName = userProfileOverall.getOcs().getData()
.getDisplayName();
} else if (!TextUtils.isEmpty(userProfileOverall.getOcs().getData()
.getDisplayNameAlt())) {
displayName = userProfileOverall.getOcs().getData()
.getDisplayNameAlt();
}
if (!TextUtils.isEmpty(displayName)) {
storeProfile(displayName, userProfileOverall.getOcs().getData().getUserId());
} else {
if (getActivity() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_display_name_not_fetched)));
}
abortVerification();
}
}
@Override
public void onError(Throwable e) {
if (getActivity() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_display_name_not_fetched)));
}
abortVerification();
}
@Override
public void onComplete() {
}
});
}
private void registerForPush() {
OneTimeWorkRequest pushRegistrationWork =
new OneTimeWorkRequest.Builder(PushRegistrationWorker.class).build();
WorkManager.getInstance().enqueue(pushRegistrationWork);
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEvent(EventStatus eventStatus) {
if (eventStatus.getEventType().equals(EventStatus.EventType.PUSH_REGISTRATION)) {
if (internalAccountId == eventStatus.getUserId()
&& !eventStatus.isAllGood()
&& getActivity() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_push_disabled)));
}
fetchAndStoreCapabilities();
} else if (eventStatus.getEventType().equals(EventStatus.EventType.CAPABILITIES_FETCH)) {
if (internalAccountId == eventStatus.getUserId() && !eventStatus.isAllGood()) {
if (getActivity() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_capabilities_failed)));
}
abortVerification();
} else if (internalAccountId == eventStatus.getUserId() && eventStatus.isAllGood()) {
fetchAndStoreExternalSignalingSettings();
}
} else if (eventStatus.getEventType().equals(EventStatus.EventType.SIGNALING_SETTINGS)) {
if (internalAccountId == eventStatus.getUserId() && !eventStatus.isAllGood()) {
if (getActivity() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_external_server_failed)));
}
}
proceedWithLogin();
}
}
private void fetchAndStoreCapabilities() {
Data userData = new Data.Builder()
.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), internalAccountId)
.build();
OneTimeWorkRequest pushNotificationWork =
new OneTimeWorkRequest.Builder(CapabilitiesWorker.class)
.setInputData(userData)
.build();
WorkManager.getInstance().enqueue(pushNotificationWork);
}
private void fetchAndStoreExternalSignalingSettings() {
Data userData = new Data.Builder()
.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), internalAccountId)
.build();
OneTimeWorkRequest signalingSettings =
new OneTimeWorkRequest.Builder(SignalingSettingsWorker.class)
.setInputData(userData)
.build();
WorkManager.getInstance().enqueue(signalingSettings);
}
private void proceedWithLogin() {
cookieManager.getCookieStore().removeAll();
userUtils.disableAllUsersWithoutId(internalAccountId);
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
if (userUtils.getUsers().size() == 1) {
getRouter().setRoot(RouterTransaction.with(new
ConversationsListView())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
if (isAccountImport) {
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.ACCOUNT_WAS_IMPORTED);
}
getRouter().popToRoot();
}
});
}
}
@Override
protected void onDestroyView(@NonNull View view) {
super.onDestroyView(view);
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
}
}
private void abortVerification() {
if (!isAccountImport) {
if (internalAccountId != -1) {
userUtils.deleteUserWithId(internalAccountId).subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
new Handler().postDelayed(() -> getRouter().popToRoot(), 7500);
});
}
}
@Override
public void onError(Throwable e) {
}
});
} else {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
new Handler().postDelayed(() -> getRouter().popToRoot(), 7500);
});
}
}
} else {
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT);
if (getActivity() != null) {
getActivity().runOnUiThread(() -> new Handler().postDelayed(() -> {
if (getRouter().hasRootController()) {
if (getActivity() != null) {
getRouter().popToRoot();
}
} else {
if (userUtils.anyUserExists()) {
getRouter().setRoot(RouterTransaction.with(new ConversationsListView())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
getRouter().setRoot(RouterTransaction.with(new ServerSelectionController())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
}
}
}, 7500));
}
}
}
} }

View File

@ -61,17 +61,17 @@ import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableImage; import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.postprocessors.BlurPostProcessor; import com.facebook.imagepipeline.postprocessors.BlurPostProcessor;
import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequest;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.models.json.conversations.Conversation;
import com.nextcloud.talk.models.json.conversations.RoomsOverall;
import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.events.ConfigurationChangeEvent; import com.nextcloud.talk.events.ConfigurationChangeEvent;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.conversations.Conversation;
import com.nextcloud.talk.models.json.conversations.RoomsOverall;
import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils; import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.DoNotDisturbUtils; import com.nextcloud.talk.utils.DoNotDisturbUtils;
@ -97,397 +97,411 @@ import org.parceler.Parcels;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class CallNotificationController extends BaseController { public class CallNotificationController extends BaseController {
private static final String TAG = "CallNotificationController"; private static final String TAG = "CallNotificationController";
@Inject @Inject
NcApi ncApi; NcApi ncApi;
@Inject @Inject
AppPreferences appPreferences; AppPreferences appPreferences;
@Inject @Inject
Cache cache; Cache cache;
@Inject @Inject
EventBus eventBus; EventBus eventBus;
@Inject @Inject
Context context; Context context;
@BindView(R.id.conversationNameTextView) @BindView(R.id.conversationNameTextView)
TextView conversationNameTextView; TextView conversationNameTextView;
@BindView(R.id.avatarImageView) @BindView(R.id.avatarImageView)
SimpleDraweeView avatarImageView; SimpleDraweeView avatarImageView;
@BindView(R.id.callAnswerVoiceOnlyView) @BindView(R.id.callAnswerVoiceOnlyView)
SimpleDraweeView callAnswerVoiceOnlyView; SimpleDraweeView callAnswerVoiceOnlyView;
@BindView(R.id.callAnswerCameraView) @BindView(R.id.callAnswerCameraView)
SimpleDraweeView callAnswerCameraView; SimpleDraweeView callAnswerCameraView;
@BindView(R.id.backgroundImageView) @BindView(R.id.backgroundImageView)
ImageView backgroundImageView; ImageView backgroundImageView;
@BindView(R.id.incomingTextRelativeLayout) @BindView(R.id.incomingTextRelativeLayout)
RelativeLayout incomingTextRelativeLayout; RelativeLayout incomingTextRelativeLayout;
private Bundle originalBundle; private Bundle originalBundle;
private String roomId; private String roomId;
private UserEntity userBeingCalled; private UserEntity userBeingCalled;
private String credentials; private String credentials;
private Conversation currentConversation; private Conversation currentConversation;
private MediaPlayer mediaPlayer; private MediaPlayer mediaPlayer;
private boolean leavingScreen = false; private boolean leavingScreen = false;
private RenderScript renderScript; private RenderScript renderScript;
private Vibrator vibrator; private Vibrator vibrator;
private Handler handler; private Handler handler;
public CallNotificationController(Bundle args) { public CallNotificationController(Bundle args) {
super(); super();
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
this.roomId = args.getString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), ""); this.roomId = args.getString(BundleKeys.INSTANCE.getKEY_ROOM_ID(), "");
this.currentConversation = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM())); this.currentConversation =
this.userBeingCalled = args.getParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY()); Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM()));
this.userBeingCalled = args.getParcelable(BundleKeys.INSTANCE.getKEY_USER_ENTITY());
this.originalBundle = args; this.originalBundle = args;
credentials = ApiUtils.getCredentials(userBeingCalled.getUsername(), userBeingCalled.getToken()); credentials =
ApiUtils.getCredentials(userBeingCalled.getUsername(), userBeingCalled.getToken());
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_call_notification, container, false);
}
@Override
protected void onDetach(@NonNull View view) {
eventBus.unregister(this);
super.onDetach(view);
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
eventBus.register(this);
}
private void showAnswerControls() {
callAnswerCameraView.setVisibility(View.VISIBLE);
callAnswerVoiceOnlyView.setVisibility(View.VISIBLE);
}
@OnClick(R.id.callControlHangupView)
void hangup() {
leavingScreen = true;
if (getActivity() != null) {
getActivity().finish();
} }
}
@Override @OnClick(R.id.callAnswerCameraView)
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { void answerWithCamera() {
return inflater.inflate(R.layout.controller_call_notification, container, false); originalBundle.putBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), false);
} proceedToCall();
}
@Override @OnClick(R.id.callAnswerVoiceOnlyView)
protected void onDetach(@NonNull View view) { void answerVoiceOnly() {
eventBus.unregister(this); originalBundle.putBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), true);
super.onDetach(view); proceedToCall();
} }
@Override private void proceedToCall() {
protected void onAttach(@NonNull View view) { originalBundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(),
super.onAttach(view); currentConversation.getToken());
eventBus.register(this);
}
private void showAnswerControls() { getRouter().replaceTopController(RouterTransaction.with(new CallController(originalBundle))
callAnswerCameraView.setVisibility(View.VISIBLE); .popChangeHandler(new HorizontalChangeHandler())
callAnswerVoiceOnlyView.setVisibility(View.VISIBLE); .pushChangeHandler(new HorizontalChangeHandler()));
} }
@OnClick(R.id.callControlHangupView) private void checkIfAnyParticipantsRemainInRoom() {
void hangup() { ncApi.getPeersForCall(credentials, ApiUtils.getUrlForParticipants(userBeingCalled.getBaseUrl(),
leavingScreen = true; currentConversation.getToken()))
.subscribeOn(Schedulers.io())
.takeWhile(observable -> !leavingScreen)
.retry(3)
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<ParticipantsOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
if (getActivity() != null) { @Override
getActivity().finish(); public void onNext(ParticipantsOverall participantsOverall) {
} boolean hasParticipantsInCall = false;
} boolean inCallOnDifferentDevice = false;
List<Participant> participantList = participantsOverall.getOcs().getData();
for (Participant participant : participantList) {
if (participant.getParticipantFlags() != Participant.ParticipantFlags.NOT_IN_CALL) {
hasParticipantsInCall = true;
@OnClick(R.id.callAnswerCameraView) if (participant.getUserId().equals(userBeingCalled.getUserId())) {
void answerWithCamera() { inCallOnDifferentDevice = true;
originalBundle.putBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), false); break;
proceedToCall(); }
} }
@OnClick(R.id.callAnswerVoiceOnlyView)
void answerVoiceOnly() {
originalBundle.putBoolean(BundleKeys.INSTANCE.getKEY_CALL_VOICE_ONLY(), true);
proceedToCall();
}
private void proceedToCall() {
originalBundle.putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), currentConversation.getToken());
getRouter().replaceTopController(RouterTransaction.with(new CallController(originalBundle))
.popChangeHandler(new HorizontalChangeHandler())
.pushChangeHandler(new HorizontalChangeHandler()));
}
private void checkIfAnyParticipantsRemainInRoom() {
ncApi.getPeersForCall(credentials, ApiUtils.getUrlForParticipants(userBeingCalled.getBaseUrl(),
currentConversation.getToken()))
.subscribeOn(Schedulers.io())
.takeWhile(observable -> !leavingScreen)
.retry(3)
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<ParticipantsOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ParticipantsOverall participantsOverall) {
boolean hasParticipantsInCall = false;
boolean inCallOnDifferentDevice = false;
List<Participant> participantList = participantsOverall.getOcs().getData();
for (Participant participant : participantList) {
if (participant.getParticipantFlags() != Participant.ParticipantFlags.NOT_IN_CALL) {
hasParticipantsInCall = true;
if (participant.getUserId().equals(userBeingCalled.getUserId())) {
inCallOnDifferentDevice = true;
break;
}
}
}
if (!hasParticipantsInCall || inCallOnDifferentDevice) {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> hangup());
}
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
if (!leavingScreen) {
checkIfAnyParticipantsRemainInRoom();
}
}
});
}
private void handleFromNotification() {
ncApi.getRooms(credentials, ApiUtils.getUrlForGetRooms(userBeingCalled.getBaseUrl()))
.subscribeOn(Schedulers.io())
.retry(3)
.observeOn(AndroidSchedulers.mainThread())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<RoomsOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(RoomsOverall roomsOverall) {
for (Conversation conversation : roomsOverall.getOcs().getData()) {
if (roomId.equals(conversation.getRoomId())) {
currentConversation = conversation;
runAllThings();
break;
}
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
private void runAllThings() {
if (conversationNameTextView != null) {
conversationNameTextView.setText(currentConversation.getDisplayName());
}
loadAvatar();
checkIfAnyParticipantsRemainInRoom();
showAnswerControls();
}
@SuppressLint("LongLogTag")
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
renderScript = RenderScript.create(getActivity());
if (handler == null) {
handler = new Handler();
try {
cache.evictAll();
} catch (IOException e) {
Log.e(TAG, "Failed to evict cache");
} }
}
if (currentConversation == null) { if (!hasParticipantsInCall || inCallOnDifferentDevice) {
handleFromNotification(); if (getActivity() != null) {
getActivity().runOnUiThread(() -> hangup());
}
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
if (!leavingScreen) {
checkIfAnyParticipantsRemainInRoom();
}
}
});
}
private void handleFromNotification() {
ncApi.getRooms(credentials, ApiUtils.getUrlForGetRooms(userBeingCalled.getBaseUrl()))
.subscribeOn(Schedulers.io())
.retry(3)
.observeOn(AndroidSchedulers.mainThread())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<RoomsOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(RoomsOverall roomsOverall) {
for (Conversation conversation : roomsOverall.getOcs().getData()) {
if (roomId.equals(conversation.getRoomId())) {
currentConversation = conversation;
runAllThings();
break;
}
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
private void runAllThings() {
if (conversationNameTextView != null) {
conversationNameTextView.setText(currentConversation.getDisplayName());
}
loadAvatar();
checkIfAnyParticipantsRemainInRoom();
showAnswerControls();
}
@SuppressLint("LongLogTag")
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
renderScript = RenderScript.create(getActivity());
if (handler == null) {
handler = new Handler();
try {
cache.evictAll();
} catch (IOException e) {
Log.e(TAG, "Failed to evict cache");
}
}
if (currentConversation == null) {
handleFromNotification();
} else {
runAllThings();
}
if (DoNotDisturbUtils.INSTANCE.shouldPlaySound()) {
String callRingtonePreferenceString = appPreferences.getCallRingtoneUri();
Uri ringtoneUri;
if (TextUtils.isEmpty(callRingtonePreferenceString)) {
// play default sound
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
} else {
try {
RingtoneSettings ringtoneSettings =
LoganSquare.parse(callRingtonePreferenceString, RingtoneSettings.class);
ringtoneUri = ringtoneSettings.getRingtoneUri();
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone settings");
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
}
}
if (ringtoneUri != null && getActivity() != null) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(getActivity(), ringtoneUri);
mediaPlayer.setLooping(true);
AudioAttributes audioAttributes =
new AudioAttributes.Builder().setContentType(AudioAttributes
.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.build();
mediaPlayer.setAudioAttributes(audioAttributes);
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());
mediaPlayer.prepareAsync();
} catch (IOException e) {
Log.e(TAG, "Failed to set data source");
}
}
}
if (DoNotDisturbUtils.INSTANCE.shouldVibrate(appPreferences.getShouldVibrateSetting())) {
vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null) {
long[] vibratePattern = new long[] { 0, 400, 800, 600, 800, 800, 800, 1000 };
int[] amplitudes = new int[] { 0, 255, 0, 255, 0, 255, 0, 255 };
VibrationEffect vibrationEffect;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (vibrator.hasAmplitudeControl()) {
vibrationEffect = VibrationEffect.createWaveform(vibratePattern, amplitudes, -1);
vibrator.vibrate(vibrationEffect);
} else {
vibrationEffect = VibrationEffect.createWaveform(vibratePattern, -1);
vibrator.vibrate(vibrationEffect);
}
} else { } else {
runAllThings(); vibrator.vibrate(vibratePattern, -1);
}
if (DoNotDisturbUtils.INSTANCE.shouldPlaySound()) {
String callRingtonePreferenceString = appPreferences.getCallRingtoneUri();
Uri ringtoneUri;
if (TextUtils.isEmpty(callRingtonePreferenceString)) {
// play default sound
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
} else {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse(callRingtonePreferenceString, RingtoneSettings.class);
ringtoneUri = ringtoneSettings.getRingtoneUri();
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone settings");
ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call");
}
}
if (ringtoneUri != null && getActivity() != null) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(getActivity(), ringtoneUri);
mediaPlayer.setLooping(true);
AudioAttributes audioAttributes = new AudioAttributes.Builder().setContentType(AudioAttributes
.CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build();
mediaPlayer.setAudioAttributes(audioAttributes);
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());
mediaPlayer.prepareAsync();
} catch (IOException e) {
Log.e(TAG, "Failed to set data source");
}
}
}
if (DoNotDisturbUtils.INSTANCE.shouldVibrate(appPreferences.getShouldVibrateSetting())) {
vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null) {
long[] vibratePattern = new long[]{0, 400, 800, 600, 800, 800, 800, 1000};
int[] amplitudes = new int[]{0, 255, 0, 255, 0, 255, 0, 255};
VibrationEffect vibrationEffect;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (vibrator.hasAmplitudeControl()) {
vibrationEffect = VibrationEffect.createWaveform(vibratePattern, amplitudes, -1);
vibrator.vibrate(vibrationEffect);
} else {
vibrationEffect = VibrationEffect.createWaveform(vibratePattern, -1);
vibrator.vibrate(vibrationEffect);
}
} else {
vibrator.vibrate(vibratePattern, -1);
}
}
handler.postDelayed(() -> {
if (vibrator != null) {
vibrator.cancel();
}
}, 10000);
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(ConfigurationChangeEvent configurationChangeEvent) {
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) avatarImageView.getLayoutParams();
int dimen = (int) getResources().getDimension(R.dimen.avatar_size_very_big);
layoutParams.width = dimen;
layoutParams.height = dimen;
avatarImageView.setLayoutParams(layoutParams);
}
private void loadAvatar() {
switch (currentConversation.getType()) {
case ROOM_TYPE_ONE_TO_ONE_CALL:
avatarImageView.setVisibility(View.VISIBLE);
ImageRequest imageRequest =
DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
currentConversation.getName(), R.dimen.avatar_size_very_big), null);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
protected void onNewResultImpl(@Nullable Bitmap bitmap) {
if (avatarImageView != null) {
avatarImageView.getHierarchy().setImage(new BitmapDrawable(bitmap), 100,
true);
if (getResources() != null) {
incomingTextRelativeLayout.setBackground(getResources().getDrawable(R.drawable
.incoming_gradient));
}
if ((AvatarStatusCodeHolder.getInstance().getStatusCode() == 200 || AvatarStatusCodeHolder.getInstance().getStatusCode() == 0) &&
userBeingCalled.hasSpreedFeatureCapability("no-ping")) {
if (getActivity() != null) {
Bitmap backgroundBitmap = bitmap.copy(bitmap.getConfig(), true);
new BlurPostProcessor(5, getActivity()).process(backgroundBitmap);
backgroundImageView.setImageDrawable(new BitmapDrawable(backgroundBitmap));
}
} else if (AvatarStatusCodeHolder.getInstance().getStatusCode() == 201) {
ColorArt colorArt = new ColorArt(bitmap);
int color = colorArt.getBackgroundColor();
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= 0.75f;
color = Color.HSVToColor(hsv);
backgroundImageView.setImageDrawable(new ColorDrawable(color));
}
}
}
@Override
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
}
}, UiThreadImmediateExecutorService.getInstance());
break;
case ROOM_GROUP_CALL:
avatarImageView.getHierarchy().setImage(DisplayUtils.getRoundedDrawable(context.getDrawable(R.drawable.ic_people_group_white_24px))
, 100, true);
case ROOM_PUBLIC_CALL:
avatarImageView.getHierarchy().setImage(DisplayUtils.getRoundedDrawable(context.getDrawable(R.drawable.ic_people_group_white_24px))
, 100, true);
break;
default:
}
}
private void endMediaAndVibratorNotifications() {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayer = null;
} }
}
handler.postDelayed(() -> {
if (vibrator != null) { if (vibrator != null) {
vibrator.cancel(); vibrator.cancel();
} }
}, 10000);
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(ConfigurationChangeEvent configurationChangeEvent) {
ConstraintLayout.LayoutParams layoutParams =
(ConstraintLayout.LayoutParams) avatarImageView.getLayoutParams();
int dimen = (int) getResources().getDimension(R.dimen.avatar_size_very_big);
layoutParams.width = dimen;
layoutParams.height = dimen;
avatarImageView.setLayoutParams(layoutParams);
}
private void loadAvatar() {
switch (currentConversation.getType()) {
case ROOM_TYPE_ONE_TO_ONE_CALL:
avatarImageView.setVisibility(View.VISIBLE);
ImageRequest imageRequest =
DisplayUtils.getImageRequestForUrl(
ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
currentConversation.getName(), R.dimen.avatar_size_very_big), null);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>> dataSource =
imagePipeline.fetchDecodedImage(imageRequest, null);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
protected void onNewResultImpl(@Nullable Bitmap bitmap) {
if (avatarImageView != null) {
avatarImageView.getHierarchy().setImage(new BitmapDrawable(bitmap), 100,
true);
if (getResources() != null) {
incomingTextRelativeLayout.setBackground(getResources().getDrawable(R.drawable
.incoming_gradient));
}
if ((AvatarStatusCodeHolder.getInstance().getStatusCode() == 200
|| AvatarStatusCodeHolder.getInstance().getStatusCode() == 0) &&
userBeingCalled.hasSpreedFeatureCapability("no-ping")) {
if (getActivity() != null) {
Bitmap backgroundBitmap = bitmap.copy(bitmap.getConfig(), true);
new BlurPostProcessor(5, getActivity()).process(backgroundBitmap);
backgroundImageView.setImageDrawable(new BitmapDrawable(backgroundBitmap));
}
} else if (AvatarStatusCodeHolder.getInstance().getStatusCode() == 201) {
ColorArt colorArt = new ColorArt(bitmap);
int color = colorArt.getBackgroundColor();
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= 0.75f;
color = Color.HSVToColor(hsv);
backgroundImageView.setImageDrawable(new ColorDrawable(color));
}
}
}
@Override
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
}
}, UiThreadImmediateExecutorService.getInstance());
break;
case ROOM_GROUP_CALL:
avatarImageView.getHierarchy()
.setImage(DisplayUtils.getRoundedDrawable(
context.getDrawable(R.drawable.ic_people_group_white_24px))
, 100, true);
case ROOM_PUBLIC_CALL:
avatarImageView.getHierarchy()
.setImage(DisplayUtils.getRoundedDrawable(
context.getDrawable(R.drawable.ic_people_group_white_24px))
, 100, true);
break;
default:
}
}
private void endMediaAndVibratorNotifications() {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayer = null;
} }
@Override if (vibrator != null) {
public void onDestroy() { vibrator.cancel();
AvatarStatusCodeHolder.getInstance().setStatusCode(0);
leavingScreen = true;
if (handler != null) {
handler.removeCallbacksAndMessages(null);
handler = null;
}
endMediaAndVibratorNotifications();
super.onDestroy();
} }
}
@Override
public void onDestroy() {
AvatarStatusCodeHolder.getInstance().setStatusCode(0);
leavingScreen = true;
if (handler != null) {
handler.removeCallbacksAndMessages(null);
handler = null;
}
endMediaAndVibratorNotifications();
super.onDestroy();
}
} }

View File

@ -48,122 +48,132 @@ import javax.inject.Inject;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class LockedController extends BaseController { public class LockedController extends BaseController {
public static final String TAG = "LockedController"; public static final String TAG = "LockedController";
private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 112; private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 112;
@Inject @Inject
AppPreferences appPreferences; AppPreferences appPreferences;
@Override @Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_locked, container, false); return inflater.inflate(R.layout.controller_locked, container, false);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
if (getActionBar() != null) {
getActionBar().hide();
} }
}
@Override @RequiresApi(api = Build.VERSION_CODES.M)
protected void onViewBound(@NonNull View view) { @Override
super.onViewBound(view); protected void onAttach(@NonNull View view) {
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); super.onAttach(view);
if (getActionBar() != null) { checkIfWeAreSecure();
getActionBar().hide(); }
}
}
@RequiresApi(api = Build.VERSION_CODES.M) @RequiresApi(api = Build.VERSION_CODES.M)
@Override @OnClick(R.id.unlockTextView)
protected void onAttach(@NonNull View view) { void unlock() {
super.onAttach(view); checkIfWeAreSecure();
checkIfWeAreSecure(); }
}
@RequiresApi(api = Build.VERSION_CODES.M) @RequiresApi(api = Build.VERSION_CODES.M)
@OnClick(R.id.unlockTextView) private void showBiometricDialog() {
void unlock() { Context context = getActivity();
checkIfWeAreSecure();
}
@RequiresApi(api = Build.VERSION_CODES.M) if (context != null) {
private void showBiometricDialog() { final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
Context context = getActivity(); .setTitle(String.format(context.getString(R.string.nc_biometric_unlock),
context.getString(R.string.nc_app_name)))
.setNegativeButtonText(context.getString(R.string.nc_cancel))
.build();
if (context != null) { Executor executor = Executors.newSingleThreadExecutor();
final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setTitle(String.format(context.getString(R.string.nc_biometric_unlock), context.getString(R.string.nc_app_name)))
.setNegativeButtonText(context.getString(R.string.nc_cancel))
.build();
Executor executor = Executors.newSingleThreadExecutor(); final BiometricPrompt biometricPrompt =
new BiometricPrompt((FragmentActivity) context, executor,
final BiometricPrompt biometricPrompt = new BiometricPrompt((FragmentActivity) context, executor, new BiometricPrompt.AuthenticationCallback() {
new BiometricPrompt.AuthenticationCallback() { @Override
@Override public void onAuthenticationSucceeded(
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { @NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result); super.onAuthenticationSucceeded(result);
Log.d(TAG, "Fingerprint recognised successfully"); Log.d(TAG, "Fingerprint recognised successfully");
new Handler(Looper.getMainLooper()).post(() -> getRouter().popCurrentController()); new Handler(Looper.getMainLooper()).post(
} () -> getRouter().popCurrentController());
@Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
Log.d(TAG, "Fingerprint not recognised");
}
@Override
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
showAuthenticationScreen();
}
}
);
BiometricPrompt.CryptoObject cryptoObject = SecurityUtils.getCryptoObject();
if (cryptoObject != null) {
biometricPrompt.authenticate(promptInfo, cryptoObject);
} else {
biometricPrompt.authenticate(promptInfo);
}
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void checkIfWeAreSecure() {
if (getActivity() != null) {
KeyguardManager keyguardManager = (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE);
if (keyguardManager != null && keyguardManager.isKeyguardSecure() && appPreferences.getIsScreenLocked()) {
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
showBiometricDialog();
} else {
getRouter().popCurrentController();
} }
}
}
}
private void showAuthenticationScreen() { @Override
if (getActivity() != null) { public void onAuthenticationFailed() {
KeyguardManager keyguardManager = (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE); super.onAuthenticationFailed();
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(null, null); Log.d(TAG, "Fingerprint not recognised");
if (intent != null) {
startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
}
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
if (resultCode == Activity.RESULT_OK) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
Log.d(TAG, "All went well, dismiss locked controller");
getRouter().popCurrentController();
}
} }
} else {
Log.d(TAG, "Authorization failed"); @Override
} public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
} super.onAuthenticationError(errorCode, errString);
showAuthenticationScreen();
}
}
);
BiometricPrompt.CryptoObject cryptoObject = SecurityUtils.getCryptoObject();
if (cryptoObject != null) {
biometricPrompt.authenticate(promptInfo, cryptoObject);
} else {
biometricPrompt.authenticate(promptInfo);
}
} }
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void checkIfWeAreSecure() {
if (getActivity() != null) {
KeyguardManager keyguardManager =
(KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE);
if (keyguardManager != null
&& keyguardManager.isKeyguardSecure()
&& appPreferences.getIsScreenLocked()) {
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
showBiometricDialog();
} else {
getRouter().popCurrentController();
}
}
}
}
private void showAuthenticationScreen() {
if (getActivity() != null) {
KeyguardManager keyguardManager =
(KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE);
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(null, null);
if (intent != null) {
startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
}
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
if (resultCode == Activity.RESULT_OK) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
Log.d(TAG, "All went well, dismiss locked controller");
getRouter().popCurrentController();
}
}
} else {
Log.d(TAG, "Authorization failed");
}
}
}
} }

View File

@ -40,11 +40,11 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import butterknife.BindView; import butterknife.BindView;
import com.bluelinelabs.logansquare.LoganSquare; import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.adapters.items.NotificationSoundItem; import com.nextcloud.talk.adapters.items.NotificationSoundItem;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.models.RingtoneSettings;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.preferences.AppPreferences; import com.nextcloud.talk.utils.preferences.AppPreferences;
import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.FlexibleAdapter;
@ -57,247 +57,255 @@ import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class RingtoneSelectionController extends BaseController implements FlexibleAdapter.OnItemClickListener { public class RingtoneSelectionController extends BaseController
implements FlexibleAdapter.OnItemClickListener {
private static final String TAG = "RingtoneSelectionController"; private static final String TAG = "RingtoneSelectionController";
@BindView(R.id.recyclerView) @BindView(R.id.recyclerView)
RecyclerView recyclerView; RecyclerView recyclerView;
@BindView(R.id.swipe_refresh_layout) @BindView(R.id.swipe_refresh_layout)
SwipeRefreshLayout swipeRefreshLayout; SwipeRefreshLayout swipeRefreshLayout;
@Inject @Inject
AppPreferences appPreferences; AppPreferences appPreferences;
@Inject @Inject
Context context; Context context;
private FlexibleAdapter adapter; private FlexibleAdapter adapter;
private RecyclerView.AdapterDataObserver adapterDataObserver; private RecyclerView.AdapterDataObserver adapterDataObserver;
private List<AbstractFlexibleItem> abstractFlexibleItemList = new ArrayList<>(); private List<AbstractFlexibleItem> abstractFlexibleItemList = new ArrayList<>();
private boolean callNotificationSounds; private boolean callNotificationSounds;
private MediaPlayer mediaPlayer; private MediaPlayer mediaPlayer;
private Handler cancelMediaPlayerHandler; private Handler cancelMediaPlayerHandler;
public RingtoneSelectionController(Bundle args) { public RingtoneSelectionController(Bundle args) {
super(); super();
setHasOptionsMenu(true); setHasOptionsMenu(true);
this.callNotificationSounds = args.getBoolean(BundleKeys.INSTANCE.getKEY_ARE_CALL_SOUNDS(), false); this.callNotificationSounds =
args.getBoolean(BundleKeys.INSTANCE.getKEY_ARE_CALL_SOUNDS(), false);
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_generic_rv, container, false);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
if (adapter == null) {
adapter = new FlexibleAdapter<>(abstractFlexibleItemList, getActivity(), false);
adapter.setNotifyChangeOfUnfilteredItems(true)
.setMode(SelectableAdapter.Mode.SINGLE);
adapter.addListener(this);
cancelMediaPlayerHandler = new Handler();
} }
@Override adapter.addListener(this);
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { prepareViews();
return inflater.inflate(R.layout.controller_generic_rv, container, false); fetchNotificationSounds();
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
return getRouter().popCurrentController();
default:
return super.onOptionsItemSelected(item);
}
}
private void prepareViews() {
RecyclerView.LayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
adapterDataObserver = new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
findSelectedSound();
}
};
adapter.registerAdapterDataObserver(adapterDataObserver);
swipeRefreshLayout.setEnabled(false);
}
@SuppressLint("LongLogTag")
private void findSelectedSound() {
boolean foundDefault = false;
String preferencesString = null;
if ((callNotificationSounds && TextUtils.isEmpty(
(preferencesString = appPreferences.getCallRingtoneUri())))
|| (!callNotificationSounds && TextUtils.isEmpty((preferencesString = appPreferences
.getMessageRingtoneUri())))) {
adapter.toggleSelection(1);
foundDefault = true;
} }
@Override if (!TextUtils.isEmpty(preferencesString) && !foundDefault) {
protected void onViewBound(@NonNull View view) { try {
super.onViewBound(view); RingtoneSettings ringtoneSettings =
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); LoganSquare.parse(preferencesString, RingtoneSettings.class);
if (ringtoneSettings.getRingtoneUri() == null) {
if (adapter == null) { adapter.toggleSelection(0);
adapter = new FlexibleAdapter<>(abstractFlexibleItemList, getActivity(), false); } else if (ringtoneSettings.getRingtoneUri().toString().equals(getRingtoneString())) {
adapter.toggleSelection(1);
adapter.setNotifyChangeOfUnfilteredItems(true)
.setMode(SelectableAdapter.Mode.SINGLE);
adapter.addListener(this);
cancelMediaPlayerHandler = new Handler();
}
adapter.addListener(this);
prepareViews();
fetchNotificationSounds();
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
return getRouter().popCurrentController();
default:
return super.onOptionsItemSelected(item);
}
}
private void prepareViews() {
RecyclerView.LayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
adapterDataObserver = new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
findSelectedSound();
}
};
adapter.registerAdapterDataObserver(adapterDataObserver);
swipeRefreshLayout.setEnabled(false);
}
@SuppressLint("LongLogTag")
private void findSelectedSound() {
boolean foundDefault = false;
String preferencesString = null;
if ((callNotificationSounds && TextUtils.isEmpty((preferencesString = appPreferences.getCallRingtoneUri())))
|| (!callNotificationSounds && TextUtils.isEmpty((preferencesString = appPreferences
.getMessageRingtoneUri())))) {
adapter.toggleSelection(1);
foundDefault = true;
}
if (!TextUtils.isEmpty(preferencesString) && !foundDefault) {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse(preferencesString, RingtoneSettings.class);
if (ringtoneSettings.getRingtoneUri() == null) {
adapter.toggleSelection(0);
} else if (ringtoneSettings.getRingtoneUri().toString().equals(getRingtoneString())) {
adapter.toggleSelection(1);
} else {
NotificationSoundItem notificationSoundItem;
for (int i = 2; i < adapter.getItemCount(); i++) {
notificationSoundItem = (NotificationSoundItem) adapter.getItem(i);
if (notificationSoundItem.getNotificationSoundUri().equals(ringtoneSettings.getRingtoneUri().toString())) {
adapter.toggleSelection(i);
break;
}
}
}
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone settings");
}
}
adapter.unregisterAdapterDataObserver(adapterDataObserver);
adapterDataObserver = null;
}
private String getRingtoneString() {
if (callNotificationSounds) {
return ("android.resource://" + context.getPackageName() +
"/raw/librem_by_feandesign_call");
} else { } else {
return ("android.resource://" + context.getPackageName() + "/raw" + NotificationSoundItem notificationSoundItem;
"/librem_by_feandesign_message"); for (int i = 2; i < adapter.getItemCount(); i++) {
} notificationSoundItem = (NotificationSoundItem) adapter.getItem(i);
if (notificationSoundItem.getNotificationSoundUri()
} .equals(ringtoneSettings.getRingtoneUri().toString())) {
adapter.toggleSelection(i);
private void fetchNotificationSounds() { break;
abstractFlexibleItemList.add(new NotificationSoundItem(getResources().getString(R.string.nc_settings_no_ringtone), null));
abstractFlexibleItemList.add(new NotificationSoundItem(getResources()
.getString(R.string.nc_settings_default_ringtone), getRingtoneString()));
if (getActivity() != null) {
RingtoneManager manager = new RingtoneManager(getActivity());
if (callNotificationSounds) {
manager.setType(RingtoneManager.TYPE_RINGTONE);
} else {
manager.setType(RingtoneManager.TYPE_NOTIFICATION);
}
Cursor cursor = manager.getCursor();
NotificationSoundItem notificationSoundItem;
while (cursor.moveToNext()) {
String notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
String notificationUri = cursor.getString(RingtoneManager.URI_COLUMN_INDEX);
String completeNotificationUri = notificationUri + "/" + cursor.getString(RingtoneManager
.ID_COLUMN_INDEX);
notificationSoundItem = new NotificationSoundItem(notificationTitle, completeNotificationUri);
abstractFlexibleItemList.add(notificationSoundItem);
} }
}
} }
} catch (IOException e) {
adapter.updateDataSet(abstractFlexibleItemList, false); Log.e(TAG, "Failed to parse ringtone settings");
}
} }
@Override adapter.unregisterAdapterDataObserver(adapterDataObserver);
public String getTitle() { adapterDataObserver = null;
return getResources().getString(R.string.nc_settings_notification_sounds); }
private String getRingtoneString() {
if (callNotificationSounds) {
return ("android.resource://" + context.getPackageName() +
"/raw/librem_by_feandesign_call");
} else {
return ("android.resource://" + context.getPackageName() + "/raw" +
"/librem_by_feandesign_message");
}
}
private void fetchNotificationSounds() {
abstractFlexibleItemList.add(
new NotificationSoundItem(getResources().getString(R.string.nc_settings_no_ringtone),
null));
abstractFlexibleItemList.add(new NotificationSoundItem(getResources()
.getString(R.string.nc_settings_default_ringtone), getRingtoneString()));
if (getActivity() != null) {
RingtoneManager manager = new RingtoneManager(getActivity());
if (callNotificationSounds) {
manager.setType(RingtoneManager.TYPE_RINGTONE);
} else {
manager.setType(RingtoneManager.TYPE_NOTIFICATION);
}
Cursor cursor = manager.getCursor();
NotificationSoundItem notificationSoundItem;
while (cursor.moveToNext()) {
String notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
String notificationUri = cursor.getString(RingtoneManager.URI_COLUMN_INDEX);
String completeNotificationUri = notificationUri + "/" + cursor.getString(RingtoneManager
.ID_COLUMN_INDEX);
notificationSoundItem =
new NotificationSoundItem(notificationTitle, completeNotificationUri);
abstractFlexibleItemList.add(notificationSoundItem);
}
} }
@SuppressLint("LongLogTag") adapter.updateDataSet(abstractFlexibleItemList, false);
@Override }
public boolean onItemClick(View view, int position) {
NotificationSoundItem notificationSoundItem = (NotificationSoundItem) adapter.getItem(position);
Uri ringtoneUri = null; @Override
public String getTitle() {
return getResources().getString(R.string.nc_settings_notification_sounds);
}
if (!TextUtils.isEmpty(notificationSoundItem.getNotificationSoundUri())) { @SuppressLint("LongLogTag")
ringtoneUri = Uri.parse(notificationSoundItem.getNotificationSoundUri()); @Override
public boolean onItemClick(View view, int position) {
NotificationSoundItem notificationSoundItem = (NotificationSoundItem) adapter.getItem(position);
endMediaPlayer(); Uri ringtoneUri = null;
mediaPlayer = MediaPlayer.create(getActivity(), ringtoneUri);
cancelMediaPlayerHandler = new Handler(); if (!TextUtils.isEmpty(notificationSoundItem.getNotificationSoundUri())) {
cancelMediaPlayerHandler.postDelayed(new Runnable() { ringtoneUri = Uri.parse(notificationSoundItem.getNotificationSoundUri());
@Override
public void run() { endMediaPlayer();
endMediaPlayer(); mediaPlayer = MediaPlayer.create(getActivity(), ringtoneUri);
}
}, mediaPlayer.getDuration() + 25); cancelMediaPlayerHandler = new Handler();
mediaPlayer.start(); cancelMediaPlayerHandler.postDelayed(new Runnable() {
@Override
public void run() {
endMediaPlayer();
} }
}, mediaPlayer.getDuration() + 25);
if (adapter.getSelectedPositions().size() == 0 || adapter.getSelectedPositions().get(0) != position) { mediaPlayer.start();
RingtoneSettings ringtoneSettings = new RingtoneSettings();
ringtoneSettings.setRingtoneName(notificationSoundItem.getNotificationSoundName());
ringtoneSettings.setRingtoneUri(ringtoneUri);
if (callNotificationSounds) {
try {
appPreferences.setCallRingtoneUri(LoganSquare.serialize(ringtoneSettings));
adapter.toggleSelection(position);
adapter.notifyDataSetChanged();
} catch (IOException e) {
Log.e(TAG, "Failed to store selected ringtone for calls");
}
} else {
try {
appPreferences.setMessageRingtoneUri(LoganSquare.serialize(ringtoneSettings));
adapter.toggleSelection(position);
adapter.notifyDataSetChanged();
} catch (IOException e) {
Log.e(TAG, "Failed to store selected ringtone for calls");
}
}
}
return true;
} }
private void endMediaPlayer() { if (adapter.getSelectedPositions().size() == 0
if (cancelMediaPlayerHandler != null) { || adapter.getSelectedPositions().get(0) != position) {
cancelMediaPlayerHandler.removeCallbacksAndMessages(null); RingtoneSettings ringtoneSettings = new RingtoneSettings();
} ringtoneSettings.setRingtoneName(notificationSoundItem.getNotificationSoundName());
ringtoneSettings.setRingtoneUri(ringtoneUri);
if (mediaPlayer != null) { if (callNotificationSounds) {
if (mediaPlayer.isPlaying()) { try {
mediaPlayer.stop(); appPreferences.setCallRingtoneUri(LoganSquare.serialize(ringtoneSettings));
} adapter.toggleSelection(position);
adapter.notifyDataSetChanged();
mediaPlayer.release(); } catch (IOException e) {
mediaPlayer = null; Log.e(TAG, "Failed to store selected ringtone for calls");
} }
} else {
try {
appPreferences.setMessageRingtoneUri(LoganSquare.serialize(ringtoneSettings));
adapter.toggleSelection(position);
adapter.notifyDataSetChanged();
} catch (IOException e) {
Log.e(TAG, "Failed to store selected ringtone for calls");
}
}
} }
@Override return true;
public void onDestroy() { }
endMediaPlayer();
super.onDestroy(); private void endMediaPlayer() {
if (cancelMediaPlayerHandler != null) {
cancelMediaPlayerHandler.removeCallbacksAndMessages(null);
} }
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayer = null;
}
}
@Override
public void onDestroy() {
endMediaPlayer();
super.onDestroy();
}
} }

View File

@ -62,301 +62,309 @@ import studio.carbonylgroup.textfieldboxes.TextFieldBoxes;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class ServerSelectionController extends BaseController { public class ServerSelectionController extends BaseController {
public static final String TAG = "ServerSelectionController"; public static final String TAG = "ServerSelectionController";
@BindView(R.id.extended_edit_text) @BindView(R.id.extended_edit_text)
ExtendedEditText serverEntry; ExtendedEditText serverEntry;
@BindView(R.id.text_field_boxes) @BindView(R.id.text_field_boxes)
TextFieldBoxes textFieldBoxes; TextFieldBoxes textFieldBoxes;
@BindView(R.id.progress_bar) @BindView(R.id.progress_bar)
ProgressBar progressBar; ProgressBar progressBar;
@BindView(R.id.helper_text_view) @BindView(R.id.helper_text_view)
TextView providersTextView; TextView providersTextView;
@BindView(R.id.cert_text_view) @BindView(R.id.cert_text_view)
TextView certTextView; TextView certTextView;
@Inject @Inject
NcApi ncApi; NcApi ncApi;
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
AppPreferences appPreferences; AppPreferences appPreferences;
@Override @Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_server_selection, container, false); return inflater.inflate(R.layout.controller_server_selection, container, false);
} }
@SuppressLint("LongLogTag") @SuppressLint("LongLogTag")
@OnClick(R.id.cert_text_view) @OnClick(R.id.cert_text_view)
public void onCertClick() { public void onCertClick() {
if (getActivity() != null) { if (getActivity() != null) {
KeyChain.choosePrivateKeyAlias(getActivity(), alias -> { KeyChain.choosePrivateKeyAlias(getActivity(), alias -> {
if (alias != null) { if (alias != null) {
appPreferences.setTemporaryClientCertAlias(alias); appPreferences.setTemporaryClientCertAlias(alias);
} else {
appPreferences.removeTemporaryClientCertAlias();
}
setCertTextView();
}, new String[]{"RSA", "EC"}, null, null, -1, null);
}
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
if (getActionBar() != null) {
getActionBar().hide();
}
textFieldBoxes.getEndIconImageButton().setBackgroundDrawable(getResources().getDrawable(R.drawable
.ic_arrow_forward_white_24px));
textFieldBoxes.getEndIconImageButton().setAlpha(0.5f);
textFieldBoxes.getEndIconImageButton().setEnabled(false);
textFieldBoxes.getEndIconImageButton().setVisibility(View.VISIBLE);
textFieldBoxes.getEndIconImageButton().setOnClickListener(view1 -> checkServerAndProceed());
if (TextUtils.isEmpty(getResources().getString(R.string.nc_providers_url)) && (TextUtils.isEmpty(getResources
().getString(R.string.nc_import_account_type)))) {
providersTextView.setVisibility(View.INVISIBLE);
} else { } else {
if ((TextUtils.isEmpty(getResources appPreferences.removeTemporaryClientCertAlias();
().getString(R.string.nc_import_account_type)) ||
AccountUtils.INSTANCE.findAccounts(userUtils.getUsers()).size() == 0) &&
userUtils.getUsers().size() == 0) {
providersTextView.setText(R.string.nc_get_from_provider);
providersTextView.setOnClickListener(view12 -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources()
.getString(R.string.nc_providers_url)));
startActivity(browserIntent);
});
} else if (AccountUtils.INSTANCE.findAccounts(userUtils.getUsers()).size() > 0) {
if (!TextUtils.isEmpty(AccountUtils.INSTANCE.getAppNameBasedOnPackage(getResources()
.getString(R.string.nc_import_accounts_from)))) {
if (AccountUtils.INSTANCE.findAccounts(userUtils.getUsers()).size() > 1) {
providersTextView.setText(String.format(getResources().getString(R.string
.nc_server_import_accounts), AccountUtils.INSTANCE.getAppNameBasedOnPackage(getResources()
.getString(R.string.nc_import_accounts_from))));
} else {
providersTextView.setText(String.format(getResources().getString(R.string
.nc_server_import_account), AccountUtils.INSTANCE.getAppNameBasedOnPackage(getResources()
.getString(R.string.nc_import_accounts_from))));
}
} else {
if (AccountUtils.INSTANCE.findAccounts(userUtils.getUsers()).size() > 1) {
providersTextView.setText(getResources().getString(R.string.nc_server_import_accounts_plain));
} else {
providersTextView.setText(getResources().getString(R.string
.nc_server_import_account_plain));
}
}
providersTextView.setOnClickListener(view13 -> {
Bundle bundle = new Bundle();
bundle.putBoolean(BundleKeys.INSTANCE.getKEY_IS_ACCOUNT_IMPORT(), true);
getRouter().pushController(RouterTransaction.with(
new SwitchAccountController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
});
} else {
providersTextView.setVisibility(View.INVISIBLE);
}
}
serverEntry.requestFocus();
serverEntry.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (!textFieldBoxes.isOnError() && !TextUtils.isEmpty(serverEntry.getText())) {
toggleProceedButton(true);
} else {
toggleProceedButton(false);
}
}
});
serverEntry.setOnEditorActionListener((textView, i, keyEvent) -> {
if (i == EditorInfo.IME_ACTION_DONE) {
checkServerAndProceed();
}
return false;
});
}
private void toggleProceedButton(boolean show) {
textFieldBoxes.getEndIconImageButton().setEnabled(show);
if (show) {
textFieldBoxes.getEndIconImageButton().setAlpha(1f);
} else {
textFieldBoxes.getEndIconImageButton().setAlpha(0.5f);
}
}
private void checkServerAndProceed() {
String url = serverEntry.getText().toString().trim();
serverEntry.setEnabled(false);
progressBar.setVisibility(View.VISIBLE);
if (providersTextView.getVisibility() != View.INVISIBLE) {
providersTextView.setVisibility(View.INVISIBLE);
certTextView.setVisibility(View.INVISIBLE);
}
if (url.endsWith("/")) {
url = url.substring(0, url.length() - 1);
}
String queryUrl = url + ApiUtils.getUrlPostfixForStatus();
if (url.startsWith("http://") || url.startsWith("https://")) {
checkServer(queryUrl, false);
} else {
checkServer("https://" + queryUrl, true);
}
}
private void checkServer(String queryUrl, boolean checkForcedHttps) {
ncApi.getServerStatus(queryUrl)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(status -> {
String productName = getResources().getString(R.string.nc_server_product_name);
String versionString = status.getVersion().substring(0, status.getVersion().indexOf("."));
int version = Integer.parseInt(versionString);
if (status.isInstalled() && !status.isMaintenance() &&
!status.isNeedsUpgrade() &&
version >= 13) {
getRouter().pushController(RouterTransaction.with(
new WebViewLoginController(queryUrl.replace("/status.php", ""),
false))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else if (!status.isInstalled()) {
textFieldBoxes.setError(String.format(
getResources().getString(R.string.nc_server_not_installed), productName),
true);
toggleProceedButton(false);
} else if (status.isNeedsUpgrade()) {
textFieldBoxes.setError(String.format(getResources().
getString(R.string.nc_server_db_upgrade_needed),
productName), true);
toggleProceedButton(false);
} else if (status.isMaintenance()) {
textFieldBoxes.setError(String.format(getResources().
getString(R.string.nc_server_maintenance),
productName),
true);
toggleProceedButton(false);
} else if (!status.getVersion().startsWith("13.")) {
textFieldBoxes.setError(String.format(getResources().
getString(R.string.nc_server_version),
getResources().getString(R.string.nc_app_name)
, productName), true);
toggleProceedButton(false);
}
}, throwable -> {
if (checkForcedHttps) {
checkServer(queryUrl.replace("https://", "http://"), false);
} else {
if (throwable.getLocalizedMessage() != null) {
textFieldBoxes.setError(throwable.getLocalizedMessage(), true);
} else if (throwable.getCause() instanceof CertificateException) {
textFieldBoxes.setError(getResources().getString(R.string.nc_certificate_error),
false);
}
if (serverEntry != null) {
serverEntry.setEnabled(true);
}
progressBar.setVisibility(View.INVISIBLE);
if (providersTextView.getVisibility() != View.INVISIBLE) {
providersTextView.setVisibility(View.VISIBLE);
certTextView.setVisibility(View.VISIBLE);
}
toggleProceedButton(false);
}
}, () -> {
progressBar.setVisibility(View.INVISIBLE);
if (providersTextView.getVisibility() != View.INVISIBLE) {
providersTextView.setVisibility(View.VISIBLE);
certTextView.setVisibility(View.VISIBLE);
}
});
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
if (ApplicationWideMessageHolder.getInstance().getMessageType() != null) {
if (ApplicationWideMessageHolder.getInstance().getMessageType()
.equals(ApplicationWideMessageHolder.MessageType.ACCOUNT_SCHEDULED_FOR_DELETION)) {
textFieldBoxes.setError(getResources().getString(R.string.nc_account_scheduled_for_deletion),
false);
ApplicationWideMessageHolder.getInstance().setMessageType(null);
} else if (ApplicationWideMessageHolder.getInstance().getMessageType()
.equals(ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK)) {
textFieldBoxes.setError(getResources().getString(R.string.nc_settings_no_talk_installed),
false);
} else if (ApplicationWideMessageHolder.getInstance().getMessageType()
.equals(ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT)) {
textFieldBoxes.setError(getResources().getString(R.string.nc_server_failed_to_import_account),
false);
}
ApplicationWideMessageHolder.getInstance().setMessageType(null);
} }
setCertTextView(); setCertTextView();
}, new String[] { "RSA", "EC" }, null, null, -1, null);
}
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} }
private void setCertTextView() { if (getActionBar() != null) {
if (getActivity() != null) { getActionBar().hide();
getActivity().runOnUiThread(() -> { }
if (!TextUtils.isEmpty(appPreferences.getTemporaryClientCertAlias())) {
certTextView.setText(R.string.nc_change_cert_auth);
} else {
certTextView.setText(R.string.nc_configure_cert_auth);
}
textFieldBoxes.setError("", true); textFieldBoxes.getEndIconImageButton()
toggleProceedButton(true); .setBackgroundDrawable(getResources().getDrawable(R.drawable
}); .ic_arrow_forward_white_24px));
textFieldBoxes.getEndIconImageButton().setAlpha(0.5f);
textFieldBoxes.getEndIconImageButton().setEnabled(false);
textFieldBoxes.getEndIconImageButton().setVisibility(View.VISIBLE);
textFieldBoxes.getEndIconImageButton().setOnClickListener(view1 -> checkServerAndProceed());
if (TextUtils.isEmpty(getResources().getString(R.string.nc_providers_url))
&& (TextUtils.isEmpty(getResources
().getString(R.string.nc_import_account_type)))) {
providersTextView.setVisibility(View.INVISIBLE);
} else {
if ((TextUtils.isEmpty(getResources
().getString(R.string.nc_import_account_type)) ||
AccountUtils.INSTANCE.findAccounts(userUtils.getUsers()).size() == 0) &&
userUtils.getUsers().size() == 0) {
providersTextView.setText(R.string.nc_get_from_provider);
providersTextView.setOnClickListener(view12 -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources()
.getString(R.string.nc_providers_url)));
startActivity(browserIntent);
});
} else if (AccountUtils.INSTANCE.findAccounts(userUtils.getUsers()).size() > 0) {
if (!TextUtils.isEmpty(AccountUtils.INSTANCE.getAppNameBasedOnPackage(getResources()
.getString(R.string.nc_import_accounts_from)))) {
if (AccountUtils.INSTANCE.findAccounts(userUtils.getUsers()).size() > 1) {
providersTextView.setText(String.format(getResources().getString(R.string
.nc_server_import_accounts),
AccountUtils.INSTANCE.getAppNameBasedOnPackage(getResources()
.getString(R.string.nc_import_accounts_from))));
} else {
providersTextView.setText(String.format(getResources().getString(R.string
.nc_server_import_account),
AccountUtils.INSTANCE.getAppNameBasedOnPackage(getResources()
.getString(R.string.nc_import_accounts_from))));
}
} else {
if (AccountUtils.INSTANCE.findAccounts(userUtils.getUsers()).size() > 1) {
providersTextView.setText(
getResources().getString(R.string.nc_server_import_accounts_plain));
} else {
providersTextView.setText(getResources().getString(R.string
.nc_server_import_account_plain));
}
} }
providersTextView.setOnClickListener(view13 -> {
Bundle bundle = new Bundle();
bundle.putBoolean(BundleKeys.INSTANCE.getKEY_IS_ACCOUNT_IMPORT(), true);
getRouter().pushController(RouterTransaction.with(
new SwitchAccountController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
});
} else {
providersTextView.setVisibility(View.INVISIBLE);
}
} }
@Override serverEntry.requestFocus();
protected void onDestroyView(@NonNull View view) {
super.onDestroyView(view); serverEntry.addTextChangedListener(new TextWatcher() {
if (getActivity() != null) { @Override
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (!textFieldBoxes.isOnError() && !TextUtils.isEmpty(serverEntry.getText())) {
toggleProceedButton(true);
} else {
toggleProceedButton(false);
} }
}
});
serverEntry.setOnEditorActionListener((textView, i, keyEvent) -> {
if (i == EditorInfo.IME_ACTION_DONE) {
checkServerAndProceed();
}
return false;
});
}
private void toggleProceedButton(boolean show) {
textFieldBoxes.getEndIconImageButton().setEnabled(show);
if (show) {
textFieldBoxes.getEndIconImageButton().setAlpha(1f);
} else {
textFieldBoxes.getEndIconImageButton().setAlpha(0.5f);
} }
}
private void checkServerAndProceed() {
String url = serverEntry.getText().toString().trim();
serverEntry.setEnabled(false);
progressBar.setVisibility(View.VISIBLE);
if (providersTextView.getVisibility() != View.INVISIBLE) {
providersTextView.setVisibility(View.INVISIBLE);
certTextView.setVisibility(View.INVISIBLE);
}
if (url.endsWith("/")) {
url = url.substring(0, url.length() - 1);
}
String queryUrl = url + ApiUtils.getUrlPostfixForStatus();
if (url.startsWith("http://") || url.startsWith("https://")) {
checkServer(queryUrl, false);
} else {
checkServer("https://" + queryUrl, true);
}
}
private void checkServer(String queryUrl, boolean checkForcedHttps) {
ncApi.getServerStatus(queryUrl)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(status -> {
String productName = getResources().getString(R.string.nc_server_product_name);
String versionString = status.getVersion().substring(0, status.getVersion().indexOf("."));
int version = Integer.parseInt(versionString);
if (status.isInstalled() && !status.isMaintenance() &&
!status.isNeedsUpgrade() &&
version >= 13) {
getRouter().pushController(RouterTransaction.with(
new WebViewLoginController(queryUrl.replace("/status.php", ""),
false))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else if (!status.isInstalled()) {
textFieldBoxes.setError(String.format(
getResources().getString(R.string.nc_server_not_installed), productName),
true);
toggleProceedButton(false);
} else if (status.isNeedsUpgrade()) {
textFieldBoxes.setError(String.format(getResources().
getString(R.string.nc_server_db_upgrade_needed),
productName), true);
toggleProceedButton(false);
} else if (status.isMaintenance()) {
textFieldBoxes.setError(String.format(getResources().
getString(R.string.nc_server_maintenance),
productName),
true);
toggleProceedButton(false);
} else if (!status.getVersion().startsWith("13.")) {
textFieldBoxes.setError(String.format(getResources().
getString(R.string.nc_server_version),
getResources().getString(R.string.nc_app_name)
, productName), true);
toggleProceedButton(false);
}
}, throwable -> {
if (checkForcedHttps) {
checkServer(queryUrl.replace("https://", "http://"), false);
} else {
if (throwable.getLocalizedMessage() != null) {
textFieldBoxes.setError(throwable.getLocalizedMessage(), true);
} else if (throwable.getCause() instanceof CertificateException) {
textFieldBoxes.setError(getResources().getString(R.string.nc_certificate_error),
false);
}
if (serverEntry != null) {
serverEntry.setEnabled(true);
}
progressBar.setVisibility(View.INVISIBLE);
if (providersTextView.getVisibility() != View.INVISIBLE) {
providersTextView.setVisibility(View.VISIBLE);
certTextView.setVisibility(View.VISIBLE);
}
toggleProceedButton(false);
}
}, () -> {
progressBar.setVisibility(View.INVISIBLE);
if (providersTextView.getVisibility() != View.INVISIBLE) {
providersTextView.setVisibility(View.VISIBLE);
certTextView.setVisibility(View.VISIBLE);
}
});
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
if (ApplicationWideMessageHolder.getInstance().getMessageType() != null) {
if (ApplicationWideMessageHolder.getInstance().getMessageType()
.equals(ApplicationWideMessageHolder.MessageType.ACCOUNT_SCHEDULED_FOR_DELETION)) {
textFieldBoxes.setError(
getResources().getString(R.string.nc_account_scheduled_for_deletion),
false);
ApplicationWideMessageHolder.getInstance().setMessageType(null);
} else if (ApplicationWideMessageHolder.getInstance().getMessageType()
.equals(ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK)) {
textFieldBoxes.setError(getResources().getString(R.string.nc_settings_no_talk_installed),
false);
} else if (ApplicationWideMessageHolder.getInstance().getMessageType()
.equals(ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT)) {
textFieldBoxes.setError(
getResources().getString(R.string.nc_server_failed_to_import_account),
false);
}
ApplicationWideMessageHolder.getInstance().setMessageType(null);
}
setCertTextView();
}
private void setCertTextView() {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
if (!TextUtils.isEmpty(appPreferences.getTemporaryClientCertAlias())) {
certTextView.setText(R.string.nc_change_cert_auth);
} else {
certTextView.setText(R.string.nc_configure_cert_auth);
}
textFieldBoxes.setError("", true);
toggleProceedButton(true);
});
}
}
@Override
protected void onDestroyView(@NonNull View view) {
super.onDestroyView(view);
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
}
}
} }

View File

@ -37,13 +37,13 @@ import autodagger.AutoInjector;
import butterknife.BindView; import butterknife.BindView;
import com.bluelinelabs.conductor.RouterTransaction; import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.nextcloud.talk.models.ImportAccount;
import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.adapters.items.AdvancedUserItem; import com.nextcloud.talk.adapters.items.AdvancedUserItem;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.models.ImportAccount;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.utils.AccountUtils; import com.nextcloud.talk.utils.AccountUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;
@ -61,189 +61,191 @@ import javax.inject.Inject;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class SwitchAccountController extends BaseController { public class SwitchAccountController extends BaseController {
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@BindView(R.id.recyclerView) @BindView(R.id.recyclerView)
RecyclerView recyclerView; RecyclerView recyclerView;
@Inject @Inject
CookieManager cookieManager; CookieManager cookieManager;
@BindView(R.id.swipe_refresh_layout) @BindView(R.id.swipe_refresh_layout)
SwipeRefreshLayout swipeRefreshLayout; SwipeRefreshLayout swipeRefreshLayout;
private FlexibleAdapter<AbstractFlexibleItem> adapter; private FlexibleAdapter<AbstractFlexibleItem> adapter;
private List<AbstractFlexibleItem> userItems = new ArrayList<>(); private List<AbstractFlexibleItem> userItems = new ArrayList<>();
private boolean isAccountImport = false; private boolean isAccountImport = false;
private FlexibleAdapter.OnItemClickListener onImportItemClickListener = new FlexibleAdapter.OnItemClickListener() { private FlexibleAdapter.OnItemClickListener onImportItemClickListener =
new FlexibleAdapter.OnItemClickListener() {
@Override @Override
public boolean onItemClick(View view, int position) { public boolean onItemClick(View view, int position) {
if (userItems.size() > position) { if (userItems.size() > position) {
Account account = ((AdvancedUserItem) userItems.get(position)).getAccount(); Account account = ((AdvancedUserItem) userItems.get(position)).getAccount();
reauthorizeFromImport(account); reauthorizeFromImport(account);
} }
return true; return true;
} }
}; };
private FlexibleAdapter.OnItemClickListener onSwitchItemClickListener = new FlexibleAdapter.OnItemClickListener() { private FlexibleAdapter.OnItemClickListener onSwitchItemClickListener =
new FlexibleAdapter.OnItemClickListener() {
@Override @Override
public boolean onItemClick(View view, int position) { public boolean onItemClick(View view, int position) {
if (userItems.size() > position) { if (userItems.size() > position) {
UserEntity userEntity = ((AdvancedUserItem) userItems.get(position)).getEntity(); UserEntity userEntity = ((AdvancedUserItem) userItems.get(position)).getEntity();
userUtils.createOrUpdateUser(null, userUtils.createOrUpdateUser(null,
null, null, null, null, null, null,
null, true, null, userEntity.getId(), null, null, null) null, true, null, userEntity.getId(), null, null, null)
.as(AutoDispose.autoDisposable(getScopeProvider())) .as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<UserEntity>() { .subscribe(new Observer<UserEntity>() {
@Override @Override
public void onSubscribe(Disposable d) { public void onSubscribe(Disposable d) {
} }
@Override @Override
public void onNext(UserEntity userEntity) { public void onNext(UserEntity userEntity) {
cookieManager.getCookieStore().removeAll(); cookieManager.getCookieStore().removeAll();
userUtils.disableAllUsersWithoutId(userEntity.getId()); userUtils.disableAllUsersWithoutId(userEntity.getId());
if (getActivity() != null) { if (getActivity() != null) {
getActivity().runOnUiThread(() -> getRouter().popCurrentController()); getActivity().runOnUiThread(() -> getRouter().popCurrentController());
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
return true;
}
};
public SwitchAccountController() {
setHasOptionsMenu(true);
}
public SwitchAccountController(Bundle args) {
super();
setHasOptionsMenu(true);
if (args.containsKey(BundleKeys.INSTANCE.getKEY_IS_ACCOUNT_IMPORT())) {
isAccountImport = true;
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getRouter().popCurrentController();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_generic_rv, container, false);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
swipeRefreshLayout.setEnabled(false);
if (getActionBar() != null) {
getActionBar().show();
}
if (adapter == null) {
adapter = new FlexibleAdapter<>(userItems, getActivity(), false);
UserEntity userEntity;
Participant participant;
if (!isAccountImport) {
for (Object userEntityObject : userUtils.getUsers()) {
userEntity = (UserEntity) userEntityObject;
if (!userEntity.getCurrent()) {
participant = new Participant();
participant.setName(userEntity.getDisplayName());
String userId;
if (userEntity.getUserId() != null) {
userId = userEntity.getUserId();
} else {
userId = userEntity.getUsername();
}
participant.setUserId(userId);
userItems.add(new AdvancedUserItem(participant, userEntity, null));
} }
} }
adapter.addListener(onSwitchItemClickListener); @Override
adapter.updateDataSet(userItems, false); public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
return true;
}
};
public SwitchAccountController() {
setHasOptionsMenu(true);
}
public SwitchAccountController(Bundle args) {
super();
setHasOptionsMenu(true);
if (args.containsKey(BundleKeys.INSTANCE.getKEY_IS_ACCOUNT_IMPORT())) {
isAccountImport = true;
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getRouter().popCurrentController();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_generic_rv, container, false);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
swipeRefreshLayout.setEnabled(false);
if (getActionBar() != null) {
getActionBar().show();
}
if (adapter == null) {
adapter = new FlexibleAdapter<>(userItems, getActivity(), false);
UserEntity userEntity;
Participant participant;
if (!isAccountImport) {
for (Object userEntityObject : userUtils.getUsers()) {
userEntity = (UserEntity) userEntityObject;
if (!userEntity.getCurrent()) {
participant = new Participant();
participant.setName(userEntity.getDisplayName());
String userId;
if (userEntity.getUserId() != null) {
userId = userEntity.getUserId();
} else { } else {
Account account; userId = userEntity.getUsername();
ImportAccount importAccount;
for (Object accountObject : AccountUtils.INSTANCE.findAccounts(userUtils.getUsers())) {
account = (Account) accountObject;
importAccount = AccountUtils.INSTANCE.getInformationFromAccount(account);
participant = new Participant();
participant.setName(importAccount.getUsername());
participant.setUserId(importAccount.getUsername());
userEntity = new UserEntity();
userEntity.setBaseUrl(importAccount.getBaseUrl());
userItems.add(new AdvancedUserItem(participant, userEntity, account));
}
adapter.addListener(onImportItemClickListener);
adapter.updateDataSet(userItems, false);
} }
participant.setUserId(userId);
userItems.add(new AdvancedUserItem(participant, userEntity, null));
}
} }
prepareViews(); adapter.addListener(onSwitchItemClickListener);
adapter.updateDataSet(userItems, false);
} else {
Account account;
ImportAccount importAccount;
for (Object accountObject : AccountUtils.INSTANCE.findAccounts(userUtils.getUsers())) {
account = (Account) accountObject;
importAccount = AccountUtils.INSTANCE.getInformationFromAccount(account);
participant = new Participant();
participant.setName(importAccount.getUsername());
participant.setUserId(importAccount.getUsername());
userEntity = new UserEntity();
userEntity.setBaseUrl(importAccount.getBaseUrl());
userItems.add(new AdvancedUserItem(participant, userEntity, account));
}
adapter.addListener(onImportItemClickListener);
adapter.updateDataSet(userItems, false);
}
} }
prepareViews();
}
private void prepareViews() { private void prepareViews() {
LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity()); LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true); recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
swipeRefreshLayout.setEnabled(false); swipeRefreshLayout.setEnabled(false);
} }
private void reauthorizeFromImport(Account account) { private void reauthorizeFromImport(Account account) {
ImportAccount importAccount = AccountUtils.INSTANCE.getInformationFromAccount(account); ImportAccount importAccount = AccountUtils.INSTANCE.getInformationFromAccount(account);
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(BundleKeys.INSTANCE.getKEY_BASE_URL(), importAccount.getBaseUrl()); bundle.putString(BundleKeys.INSTANCE.getKEY_BASE_URL(), importAccount.getBaseUrl());
bundle.putString(BundleKeys.INSTANCE.getKEY_USERNAME(), importAccount.getUsername()); bundle.putString(BundleKeys.INSTANCE.getKEY_USERNAME(), importAccount.getUsername());
bundle.putString(BundleKeys.INSTANCE.getKEY_TOKEN(), importAccount.getToken()); bundle.putString(BundleKeys.INSTANCE.getKEY_TOKEN(), importAccount.getToken());
bundle.putBoolean(BundleKeys.INSTANCE.getKEY_IS_ACCOUNT_IMPORT(), true); bundle.putBoolean(BundleKeys.INSTANCE.getKEY_IS_ACCOUNT_IMPORT(), true);
getRouter().pushController(RouterTransaction.with(new AccountVerificationController(bundle)) getRouter().pushController(RouterTransaction.with(new AccountVerificationController(bundle))
.pushChangeHandler(new HorizontalChangeHandler()) .pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler())); .popChangeHandler(new HorizontalChangeHandler()));
} }
@Override @Override
public String getTitle() { public String getTitle() {
return getResources().getString(R.string.nc_select_an_account); return getResources().getString(R.string.nc_select_an_account);
} }
} }

View File

@ -50,12 +50,12 @@ import autodagger.AutoInjector;
import butterknife.BindView; import butterknife.BindView;
import com.bluelinelabs.conductor.RouterTransaction; import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.nextcloud.talk.models.LoginData;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.events.CertificateEvent; import com.nextcloud.talk.events.CertificateEvent;
import com.nextcloud.talk.jobs.PushRegistrationWorker; import com.nextcloud.talk.jobs.PushRegistrationWorker;
import com.nextcloud.talk.models.LoginData;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;
@ -84,388 +84,400 @@ import org.greenrobot.eventbus.EventBus;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class WebViewLoginController extends BaseController { public class WebViewLoginController extends BaseController {
public static final String TAG = "WebViewLoginController"; public static final String TAG = "WebViewLoginController";
private final String PROTOCOL_SUFFIX = "://"; private final String PROTOCOL_SUFFIX = "://";
private final String LOGIN_URL_DATA_KEY_VALUE_SEPARATOR = ":"; private final String LOGIN_URL_DATA_KEY_VALUE_SEPARATOR = ":";
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
AppPreferences appPreferences; AppPreferences appPreferences;
@Inject @Inject
ReactiveEntityStore<Persistable> dataStore; ReactiveEntityStore<Persistable> dataStore;
@Inject @Inject
MagicTrustManager magicTrustManager; MagicTrustManager magicTrustManager;
@Inject @Inject
EventBus eventBus; EventBus eventBus;
@Inject @Inject
CookieManager cookieManager; CookieManager cookieManager;
@BindView(R.id.webview)
WebView webView;
@BindView(R.id.webview) @BindView(R.id.progress_bar)
WebView webView; ProgressBar progressBar;
@BindView(R.id.progress_bar) private String assembledPrefix;
ProgressBar progressBar;
private String assembledPrefix; private Disposable userQueryDisposable;
private Disposable userQueryDisposable; private String baseUrl;
private boolean isPasswordUpdate;
private String baseUrl; private String username;
private boolean isPasswordUpdate; private String password;
private int loginStep = 0;
private String username; private boolean automatedLoginAttempted = false;
private String password;
private int loginStep = 0;
private boolean automatedLoginAttempted = false; private WebViewFidoBridge webViewFidoBridge;
private WebViewFidoBridge webViewFidoBridge; public WebViewLoginController(String baseUrl, boolean isPasswordUpdate) {
this.baseUrl = baseUrl;
this.isPasswordUpdate = isPasswordUpdate;
}
public WebViewLoginController(String baseUrl, boolean isPasswordUpdate) { public WebViewLoginController(String baseUrl, boolean isPasswordUpdate, String username,
this.baseUrl = baseUrl; String password) {
this.isPasswordUpdate = isPasswordUpdate; this.baseUrl = baseUrl;
this.isPasswordUpdate = isPasswordUpdate;
this.username = username;
this.password = password;
}
private String getWebLoginUserAgent() {
return Build.MANUFACTURER.substring(0, 1).toUpperCase(Locale.getDefault()) +
Build.MANUFACTURER.substring(1).toLowerCase(Locale.getDefault()) + " " + Build.MODEL + " ("
+ getResources().getString(R.string.nc_app_name) + ")";
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_web_view_login, container, false);
}
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} }
public WebViewLoginController(String baseUrl, boolean isPasswordUpdate, String username, String password) { if (getActionBar() != null) {
this.baseUrl = baseUrl; getActionBar().hide();
this.isPasswordUpdate = isPasswordUpdate;
this.username = username;
this.password = password;
} }
private String getWebLoginUserAgent() { assembledPrefix =
return Build.MANUFACTURER.substring(0, 1).toUpperCase(Locale.getDefault()) + getResources().getString(R.string.nc_talk_login_scheme) + PROTOCOL_SUFFIX + "login/";
Build.MANUFACTURER.substring(1).toLowerCase(Locale.getDefault()) + " " + Build.MODEL + " ("
+ getResources().getString(R.string.nc_app_name) + ")";
}
@Override webView.getSettings().setAllowFileAccess(false);
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { webView.getSettings().setAllowFileAccessFromFileURLs(false);
return inflater.inflate(R.layout.controller_web_view_login, container, false); webView.getSettings().setJavaScriptEnabled(true);
} webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setUserAgentString(getWebLoginUserAgent());
webView.getSettings().setSaveFormData(false);
webView.getSettings().setSavePassword(false);
webView.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH);
webView.clearCache(true);
webView.clearFormData();
webView.clearHistory();
WebView.clearClientCertPreferences(null);
@SuppressLint("SetJavaScriptEnabled") webViewFidoBridge =
@Override WebViewFidoBridge.createInstanceForWebView((AppCompatActivity) getActivity(), webView);
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
if (getActivity() != null) { CookieSyncManager.createInstance(getActivity());
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); android.webkit.CookieManager.getInstance().removeAllCookies(null);
Map<String, String> headers = new HashMap<>();
headers.put("OCS-APIRequest", "true");
webView.setWebViewClient(new WebViewClient() {
private boolean basePageLoaded;
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
webViewFidoBridge.delegateShouldInterceptRequest(view, request);
return super.shouldInterceptRequest(view, request);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
webViewFidoBridge.delegateOnPageStarted(view, url, favicon);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith(assembledPrefix)) {
parseAndLoginFromWebView(url);
return true;
}
return false;
}
@Override
public void onPageFinished(WebView view, String url) {
loginStep++;
if (!basePageLoaded) {
if (progressBar != null) {
progressBar.setVisibility(View.GONE);
}
if (webView != null) {
webView.setVisibility(View.VISIBLE);
}
basePageLoaded = true;
} }
if (getActionBar() != null) { if (!TextUtils.isEmpty(username) && webView != null) {
getActionBar().hide(); if (loginStep == 1) {
} webView.loadUrl("javascript: {document.getElementsByClassName('login')[0].click(); };");
} else if (!automatedLoginAttempted) {
assembledPrefix = getResources().getString(R.string.nc_talk_login_scheme) + PROTOCOL_SUFFIX + "login/"; automatedLoginAttempted = true;
if (TextUtils.isEmpty(password)) {
webView.getSettings().setAllowFileAccess(false); webView.loadUrl("javascript:var justStore = document.getElementById('user').value = '"
webView.getSettings().setAllowFileAccessFromFileURLs(false); + username
webView.getSettings().setJavaScriptEnabled(true); + "';");
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setUserAgentString(getWebLoginUserAgent());
webView.getSettings().setSaveFormData(false);
webView.getSettings().setSavePassword(false);
webView.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH);
webView.clearCache(true);
webView.clearFormData();
webView.clearHistory();
WebView.clearClientCertPreferences(null);
webViewFidoBridge = WebViewFidoBridge.createInstanceForWebView((AppCompatActivity) getActivity(), webView);
CookieSyncManager.createInstance(getActivity());
android.webkit.CookieManager.getInstance().removeAllCookies(null);
Map<String, String> headers = new HashMap<>();
headers.put("OCS-APIRequest", "true");
webView.setWebViewClient(new WebViewClient() {
private boolean basePageLoaded;
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
webViewFidoBridge.delegateShouldInterceptRequest(view, request);
return super.shouldInterceptRequest(view, request);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
webViewFidoBridge.delegateOnPageStarted(view, url, favicon);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith(assembledPrefix)) {
parseAndLoginFromWebView(url);
return true;
}
return false;
}
@Override
public void onPageFinished(WebView view, String url) {
loginStep++;
if (!basePageLoaded) {
if (progressBar != null) {
progressBar.setVisibility(View.GONE);
}
if (webView != null) {
webView.setVisibility(View.VISIBLE);
}
basePageLoaded = true;
}
if (!TextUtils.isEmpty(username) && webView != null) {
if (loginStep == 1) {
webView.loadUrl("javascript: {document.getElementsByClassName('login')[0].click(); };");
} else if (!automatedLoginAttempted) {
automatedLoginAttempted = true;
if (TextUtils.isEmpty(password)) {
webView.loadUrl("javascript:var justStore = document.getElementById('user').value = '" + username + "';");
} else {
webView.loadUrl("javascript: {" +
"document.getElementById('user').value = '" + username + "';" +
"document.getElementById('password').value = '" + password + "';" +
"document.getElementById('submit').click(); };");
}
}
}
super.onPageFinished(view, url);
}
@Override
public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
UserEntity userEntity = userUtils.getCurrentUser();
String alias = null;
if (!isPasswordUpdate) {
alias = appPreferences.getTemporaryClientCertAlias();
}
if (TextUtils.isEmpty(alias) && (userEntity != null)) {
alias = userEntity.getClientCertificate();
}
if (!TextUtils.isEmpty(alias)) {
String finalAlias = alias;
new Thread(() -> {
try {
PrivateKey privateKey = KeyChain.getPrivateKey(getActivity(), finalAlias);
X509Certificate[] certificates = KeyChain.getCertificateChain(getActivity(), finalAlias);
if (privateKey != null && certificates != null) {
request.proceed(privateKey, certificates);
} else {
request.cancel();
}
} catch (KeyChainException | InterruptedException e) {
request.cancel();
}
}).start();
} else {
KeyChain.choosePrivateKeyAlias(getActivity(), chosenAlias -> {
if (chosenAlias != null) {
appPreferences.setTemporaryClientCertAlias(chosenAlias);
new Thread(() -> {
PrivateKey privateKey = null;
try {
privateKey = KeyChain.getPrivateKey(getActivity(), chosenAlias);
X509Certificate[] certificates = KeyChain.getCertificateChain(getActivity(), chosenAlias);
if (privateKey != null && certificates != null) {
request.proceed(privateKey, certificates);
} else {
request.cancel();
}
} catch (KeyChainException | InterruptedException e) {
request.cancel();
}
}).start();
} else {
request.cancel();
}
}, new String[]{"RSA", "EC"}, null, request.getHost(), request.getPort(), null);
}
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
try {
SslCertificate sslCertificate = error.getCertificate();
Field f = sslCertificate.getClass().getDeclaredField("mX509Certificate");
f.setAccessible(true);
X509Certificate cert = (X509Certificate) f.get(sslCertificate);
if (cert == null) {
handler.cancel();
} else {
try {
magicTrustManager.checkServerTrusted(new X509Certificate[]{cert}, "generic");
handler.proceed();
} catch (CertificateException exception) {
eventBus.post(new CertificateEvent(cert, magicTrustManager, handler));
}
}
} catch (Exception exception) {
handler.cancel();
}
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
}
});
webView.loadUrl(baseUrl + "/index.php/login/flow", headers);
}
private void dispose() {
if (userQueryDisposable != null && !userQueryDisposable.isDisposed()) {
userQueryDisposable.dispose();
}
userQueryDisposable = null;
}
private void parseAndLoginFromWebView(String dataString) {
LoginData loginData = parseLoginData(assembledPrefix, dataString);
if (loginData != null) {
dispose();
UserEntity currentUser = userUtils.getCurrentUser();
ApplicationWideMessageHolder.MessageType messageType = null;
if (!isPasswordUpdate && userUtils.getIfUserWithUsernameAndServer(loginData.getUsername(), baseUrl)) {
messageType = ApplicationWideMessageHolder.MessageType.ACCOUNT_UPDATED_NOT_ADDED;
}
if (userUtils.checkIfUserIsScheduledForDeletion(loginData.getUsername(), baseUrl)) {
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.ACCOUNT_SCHEDULED_FOR_DELETION);
if (!isPasswordUpdate) {
getRouter().popToRoot();
} else {
getRouter().popCurrentController();
}
}
ApplicationWideMessageHolder.MessageType finalMessageType = messageType;
cookieManager.getCookieStore().removeAll();
if (!isPasswordUpdate && finalMessageType == null) {
Bundle bundle = new Bundle();
bundle.putString(BundleKeys.INSTANCE.getKEY_USERNAME(), loginData.getUsername());
bundle.putString(BundleKeys.INSTANCE.getKEY_TOKEN(), loginData.getToken());
bundle.putString(BundleKeys.INSTANCE.getKEY_BASE_URL(), loginData.getServerUrl());
String protocol = "";
if (baseUrl.startsWith("http://")) {
protocol = "http://";
} else if (baseUrl.startsWith("https://")) {
protocol = "https://";
}
if (!TextUtils.isEmpty(protocol)) {
bundle.putString(BundleKeys.INSTANCE.getKEY_ORIGINAL_PROTOCOL(), protocol);
}
getRouter().pushController(RouterTransaction.with(new AccountVerificationController
(bundle)).pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else { } else {
if (isPasswordUpdate) { webView.loadUrl("javascript: {" +
if (currentUser != null) { "document.getElementById('user').value = '" + username + "';" +
userQueryDisposable = userUtils.createOrUpdateUser(null, loginData.getToken(), "document.getElementById('password').value = '" + password + "';" +
null, null, "", true, "document.getElementById('submit').click(); };");
null, currentUser.getId(), null, appPreferences.getTemporaryClientCertAlias(), null)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(userEntity -> {
if (finalMessageType != null) {
ApplicationWideMessageHolder.getInstance().setMessageType(finalMessageType);
}
OneTimeWorkRequest pushRegistrationWork = new OneTimeWorkRequest.Builder(PushRegistrationWorker.class).build();
WorkManager.getInstance().enqueue(pushRegistrationWork);
getRouter().popCurrentController();
}, throwable -> dispose(),
this::dispose);
}
} else {
if (finalMessageType != null) {
ApplicationWideMessageHolder.getInstance().setMessageType(finalMessageType);
}
getRouter().popToRoot();
}
} }
} }
}
private LoginData parseLoginData(String prefix, String dataString) {
if (dataString.length() < prefix.length()) {
return null;
} }
LoginData loginData = new LoginData(); super.onPageFinished(view, url);
}
// format is xxx://login/server:xxx&user:xxx&password:xxx @Override
String data = dataString.substring(prefix.length()); public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
UserEntity userEntity = userUtils.getCurrentUser();
String[] values = data.split("&"); String alias = null;
if (!isPasswordUpdate) {
if (values.length != 3) { alias = appPreferences.getTemporaryClientCertAlias();
return null;
} }
for (String value : values) { if (TextUtils.isEmpty(alias) && (userEntity != null)) {
if (value.startsWith("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) { alias = userEntity.getClientCertificate();
loginData.setUsername(URLDecoder.decode( }
value.substring(("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length())));
} else if (value.startsWith("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) { if (!TextUtils.isEmpty(alias)) {
loginData.setToken(URLDecoder.decode( String finalAlias = alias;
value.substring(("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length()))); new Thread(() -> {
} else if (value.startsWith("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) { try {
loginData.setServerUrl(URLDecoder.decode( PrivateKey privateKey = KeyChain.getPrivateKey(getActivity(), finalAlias);
value.substring(("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length()))); X509Certificate[] certificates =
} else { KeyChain.getCertificateChain(getActivity(), finalAlias);
return null; if (privateKey != null && certificates != null) {
request.proceed(privateKey, certificates);
} else {
request.cancel();
}
} catch (KeyChainException | InterruptedException e) {
request.cancel();
} }
} }).start();
if (!TextUtils.isEmpty(loginData.getServerUrl()) && !TextUtils.isEmpty(loginData.getUsername()) &&
!TextUtils.isEmpty(loginData.getToken())) {
return loginData;
} else { } else {
return null; KeyChain.choosePrivateKeyAlias(getActivity(), chosenAlias -> {
if (chosenAlias != null) {
appPreferences.setTemporaryClientCertAlias(chosenAlias);
new Thread(() -> {
PrivateKey privateKey = null;
try {
privateKey = KeyChain.getPrivateKey(getActivity(), chosenAlias);
X509Certificate[] certificates =
KeyChain.getCertificateChain(getActivity(), chosenAlias);
if (privateKey != null && certificates != null) {
request.proceed(privateKey, certificates);
} else {
request.cancel();
}
} catch (KeyChainException | InterruptedException e) {
request.cancel();
}
}).start();
} else {
request.cancel();
}
}, new String[] { "RSA", "EC" }, null, request.getHost(), request.getPort(), null);
} }
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
try {
SslCertificate sslCertificate = error.getCertificate();
Field f = sslCertificate.getClass().getDeclaredField("mX509Certificate");
f.setAccessible(true);
X509Certificate cert = (X509Certificate) f.get(sslCertificate);
if (cert == null) {
handler.cancel();
} else {
try {
magicTrustManager.checkServerTrusted(new X509Certificate[] { cert }, "generic");
handler.proceed();
} catch (CertificateException exception) {
eventBus.post(new CertificateEvent(cert, magicTrustManager, handler));
}
}
} catch (Exception exception) {
handler.cancel();
}
}
@Override
public void onReceivedError(WebView view, int errorCode, String description,
String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
}
});
webView.loadUrl(baseUrl + "/index.php/login/flow", headers);
}
private void dispose() {
if (userQueryDisposable != null && !userQueryDisposable.isDisposed()) {
userQueryDisposable.dispose();
} }
@Override userQueryDisposable = null;
public void onDestroy() { }
super.onDestroy();
dispose(); private void parseAndLoginFromWebView(String dataString) {
LoginData loginData = parseLoginData(assembledPrefix, dataString);
if (loginData != null) {
dispose();
UserEntity currentUser = userUtils.getCurrentUser();
ApplicationWideMessageHolder.MessageType messageType = null;
if (!isPasswordUpdate && userUtils.getIfUserWithUsernameAndServer(loginData.getUsername(),
baseUrl)) {
messageType = ApplicationWideMessageHolder.MessageType.ACCOUNT_UPDATED_NOT_ADDED;
}
if (userUtils.checkIfUserIsScheduledForDeletion(loginData.getUsername(), baseUrl)) {
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.ACCOUNT_SCHEDULED_FOR_DELETION);
if (!isPasswordUpdate) {
getRouter().popToRoot();
} else {
getRouter().popCurrentController();
}
}
ApplicationWideMessageHolder.MessageType finalMessageType = messageType;
cookieManager.getCookieStore().removeAll();
if (!isPasswordUpdate && finalMessageType == null) {
Bundle bundle = new Bundle();
bundle.putString(BundleKeys.INSTANCE.getKEY_USERNAME(), loginData.getUsername());
bundle.putString(BundleKeys.INSTANCE.getKEY_TOKEN(), loginData.getToken());
bundle.putString(BundleKeys.INSTANCE.getKEY_BASE_URL(), loginData.getServerUrl());
String protocol = "";
if (baseUrl.startsWith("http://")) {
protocol = "http://";
} else if (baseUrl.startsWith("https://")) {
protocol = "https://";
}
if (!TextUtils.isEmpty(protocol)) {
bundle.putString(BundleKeys.INSTANCE.getKEY_ORIGINAL_PROTOCOL(), protocol);
}
getRouter().pushController(RouterTransaction.with(new AccountVerificationController
(bundle)).pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
if (isPasswordUpdate) {
if (currentUser != null) {
userQueryDisposable = userUtils.createOrUpdateUser(null, loginData.getToken(),
null, null, "", true,
null, currentUser.getId(), null, appPreferences.getTemporaryClientCertAlias(), null)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(userEntity -> {
if (finalMessageType != null) {
ApplicationWideMessageHolder.getInstance().setMessageType(finalMessageType);
}
OneTimeWorkRequest pushRegistrationWork =
new OneTimeWorkRequest.Builder(PushRegistrationWorker.class).build();
WorkManager.getInstance().enqueue(pushRegistrationWork);
getRouter().popCurrentController();
}, throwable -> dispose(),
this::dispose);
}
} else {
if (finalMessageType != null) {
ApplicationWideMessageHolder.getInstance().setMessageType(finalMessageType);
}
getRouter().popToRoot();
}
}
}
}
private LoginData parseLoginData(String prefix, String dataString) {
if (dataString.length() < prefix.length()) {
return null;
} }
@Override LoginData loginData = new LoginData();
protected void onDestroyView(@NonNull View view) {
super.onDestroyView(view); // format is xxx://login/server:xxx&user:xxx&password:xxx
if (getActivity() != null) { String data = dataString.substring(prefix.length());
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
} String[] values = data.split("&");
if (values.length != 3) {
return null;
} }
for (String value : values) {
if (value.startsWith("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) {
loginData.setUsername(URLDecoder.decode(
value.substring(("user" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length())));
} else if (value.startsWith("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) {
loginData.setToken(URLDecoder.decode(
value.substring(("password" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length())));
} else if (value.startsWith("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR)) {
loginData.setServerUrl(URLDecoder.decode(
value.substring(("server" + LOGIN_URL_DATA_KEY_VALUE_SEPARATOR).length())));
} else {
return null;
}
}
if (!TextUtils.isEmpty(loginData.getServerUrl())
&& !TextUtils.isEmpty(loginData.getUsername())
&&
!TextUtils.isEmpty(loginData.getToken())) {
return loginData;
} else {
return null;
}
}
@Override
public void onDestroy() {
super.onDestroy();
dispose();
}
@Override
protected void onDestroyView(@NonNull View view) {
super.onDestroyView(view);
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
}
}
} }

View File

@ -31,27 +31,33 @@ import com.bluelinelabs.conductor.Controller
abstract class ButterKnifeController : Controller { abstract class ButterKnifeController : Controller {
protected var unbinder: Unbinder? = null protected var unbinder: Unbinder? = null
constructor() constructor()
constructor(args: Bundle) : super(args) constructor(args: Bundle) : super(args)
protected abstract fun inflateView(inflater: LayoutInflater, container: ViewGroup): View protected abstract fun inflateView(
inflater: LayoutInflater,
container: ViewGroup
): View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View { override fun onCreateView(
val view = inflateView(inflater, container) inflater: LayoutInflater,
unbinder = ButterKnife.bind(this, view) container: ViewGroup
onViewBound(view) ): View {
return view val view = inflateView(inflater, container)
} unbinder = ButterKnife.bind(this, view)
onViewBound(view)
return view
}
protected open fun onViewBound(view: View) {} protected open fun onViewBound(view: View) {}
override fun onDestroyView(view: View) { override fun onDestroyView(view: View) {
super.onDestroyView(view) super.onDestroyView(view)
unbinder!!.unbind() unbinder!!.unbind()
unbinder = null unbinder = null
} }
} }

View File

@ -21,5 +21,5 @@ package com.nextcloud.talk.controllers.base.providers;
import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBar;
public interface ActionBarProvider { public interface ActionBarProvider {
ActionBar getSupportActionBar(); ActionBar getSupportActionBar();
} }

View File

@ -64,266 +64,279 @@ import org.parceler.Parcels;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class EntryMenuController extends BaseController { public class EntryMenuController extends BaseController {
@BindView(R.id.ok_button) @BindView(R.id.ok_button)
Button proceedButton; Button proceedButton;
@BindView(R.id.text_edit) @BindView(R.id.text_edit)
EmojiTextInputEditText editText; EmojiTextInputEditText editText;
@BindView(R.id.text_input_layout) @BindView(R.id.text_input_layout)
TextInputLayout textInputLayout; TextInputLayout textInputLayout;
@BindView(R.id.smileyButton) @BindView(R.id.smileyButton)
ImageView smileyButton; ImageView smileyButton;
@Inject @Inject
EventBus eventBus; EventBus eventBus;
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
private int operationCode; private int operationCode;
private Conversation conversation; private Conversation conversation;
private Intent shareIntent; private Intent shareIntent;
private String packageName; private String packageName;
private String name; private String name;
private String callUrl; private String callUrl;
private EmojiPopup emojiPopup; private EmojiPopup emojiPopup;
private Bundle originalBundle;
private Bundle originalBundle; public EntryMenuController(Bundle args) {
super();
originalBundle = args;
public EntryMenuController(Bundle args) { this.operationCode = args.getInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE());
super(); if (args.containsKey(BundleKeys.INSTANCE.getKEY_ROOM())) {
originalBundle = args; this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM()));
this.operationCode = args.getInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE());
if (args.containsKey(BundleKeys.INSTANCE.getKEY_ROOM())) {
this.conversation = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_ROOM()));
}
if (args.containsKey(BundleKeys.INSTANCE.getKEY_SHARE_INTENT())) {
this.shareIntent = Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_SHARE_INTENT()));
}
this.name = args.getString(BundleKeys.INSTANCE.getKEY_APP_ITEM_NAME(), "");
this.packageName = args.getString(BundleKeys.INSTANCE.getKEY_APP_ITEM_PACKAGE_NAME(), "");
this.callUrl = args.getString(BundleKeys.INSTANCE.getKEY_CALL_URL(), "");
} }
@Override if (args.containsKey(BundleKeys.INSTANCE.getKEY_SHARE_INTENT())) {
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) { this.shareIntent =
return inflater.inflate(R.layout.controller_entry_menu, container, false); Parcels.unwrap(args.getParcelable(BundleKeys.INSTANCE.getKEY_SHARE_INTENT()));
} }
@OnClick(R.id.smileyButton) this.name = args.getString(BundleKeys.INSTANCE.getKEY_APP_ITEM_NAME(), "");
void onSmileyClick() { this.packageName = args.getString(BundleKeys.INSTANCE.getKEY_APP_ITEM_PACKAGE_NAME(), "");
emojiPopup.toggle(); this.callUrl = args.getString(BundleKeys.INSTANCE.getKEY_CALL_URL(), "");
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_entry_menu, container, false);
}
@OnClick(R.id.smileyButton)
void onSmileyClick() {
emojiPopup.toggle();
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
if (ApplicationWideMessageHolder.getInstance().getMessageType() != null &&
ApplicationWideMessageHolder.getInstance()
.getMessageType()
.equals(ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG)) {
textInputLayout.setError(getResources().getString(R.string.nc_wrong_password));
ApplicationWideMessageHolder.getInstance().setMessageType(null);
if (proceedButton.isEnabled()) {
proceedButton.setEnabled(false);
proceedButton.setAlpha(0.7f);
}
}
}
@OnClick(R.id.ok_button)
public void onProceedButtonClick() {
Bundle bundle;
if (operationCode == 99) {
eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
bundle = new Bundle();
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation));
bundle.putString(BundleKeys.INSTANCE.getKEY_CALL_URL(), callUrl);
bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(),
editText.getText().toString());
bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operationCode);
if (originalBundle.containsKey(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES())) {
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES(),
originalBundle.getParcelable(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES()));
}
getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else if (operationCode != 7 && operationCode != 10 && operationCode != 11) {
eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
bundle = new Bundle();
if (operationCode == 4 || operationCode == 6) {
conversation.setPassword(editText.getText().toString());
} else {
conversation.setName(editText.getText().toString());
}
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation));
bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operationCode);
getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else if (operationCode == 7) {
if (getActivity() != null) {
shareIntent.putExtra(Intent.EXTRA_TEXT, ShareUtils.getStringForIntent(getActivity(),
editText.getText().toString(), userUtils, conversation));
Intent intent = new Intent(shareIntent);
intent.setComponent(new ComponentName(packageName, name));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getActivity().startActivity(intent);
eventBus.post(new BottomSheetLockEvent(true, 0, false, true));
}
} else if (operationCode != 11) {
eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
bundle = new Bundle();
bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operationCode);
bundle.putString(BundleKeys.INSTANCE.getKEY_CALL_URL(), editText.getText().toString());
getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else if (operationCode == 11) {
eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(),
editText.getText().toString());
getRouter().pushController(
RouterTransaction.with(new OperationsMenuController(originalBundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
}
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
if (conversation != null && operationCode == 2) {
editText.setText(conversation.getName());
} }
@Override editText.setOnEditorActionListener((v, actionId, event) -> {
protected void onAttach(@NonNull View view) { if (actionId == EditorInfo.IME_ACTION_DONE
super.onAttach(view); && proceedButton != null
if (ApplicationWideMessageHolder.getInstance().getMessageType() != null && && proceedButton.isEnabled()) {
ApplicationWideMessageHolder.getInstance().getMessageType().equals(ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG)) { proceedButton.callOnClick();
textInputLayout.setError(getResources().getString(R.string.nc_wrong_password)); return true;
ApplicationWideMessageHolder.getInstance().setMessageType(null); }
if (proceedButton.isEnabled()) { return false;
proceedButton.setEnabled(false); });
proceedButton.setAlpha(0.7f);
}
}
}
@OnClick(R.id.ok_button) editText.addTextChangedListener(new TextWatcher() {
public void onProceedButtonClick() { @Override
Bundle bundle; public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (operationCode == 99) {
eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
bundle = new Bundle();
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation));
bundle.putString(BundleKeys.INSTANCE.getKEY_CALL_URL(), callUrl);
bundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_PASSWORD(), editText.getText().toString());
bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operationCode);
if (originalBundle.containsKey(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES())) {
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES(), originalBundle.getParcelable(BundleKeys.INSTANCE.getKEY_SERVER_CAPABILITIES()));
}
getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) }
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler())); @Override
} else if (operationCode != 7 && operationCode != 10 && operationCode != 11) { public void onTextChanged(CharSequence s, int start, int before, int count) {
eventBus.post(new BottomSheetLockEvent(false, 0, false, false));
bundle = new Bundle(); }
if (operationCode == 4 || operationCode == 6) {
conversation.setPassword(editText.getText().toString()); @Override
public void afterTextChanged(Editable s) {
if (!TextUtils.isEmpty(s)) {
if (operationCode == 2) {
if (conversation.getName() == null || !conversation.getName().equals(s.toString())) {
if (!proceedButton.isEnabled()) {
proceedButton.setEnabled(true);
proceedButton.setAlpha(1.0f);
}
textInputLayout.setErrorEnabled(false);
} else { } else {
conversation.setName(editText.getText().toString()); if (proceedButton.isEnabled()) {
proceedButton.setEnabled(false);
proceedButton.setAlpha(0.38f);
}
textInputLayout.setError(getResources().getString(R.string.nc_call_name_is_same));
} }
bundle.putParcelable(BundleKeys.INSTANCE.getKEY_ROOM(), Parcels.wrap(conversation)); } else if (operationCode != 10) {
bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operationCode); if (!proceedButton.isEnabled()) {
getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) proceedButton.setEnabled(true);
.pushChangeHandler(new HorizontalChangeHandler()) proceedButton.setAlpha(1.0f);
.popChangeHandler(new HorizontalChangeHandler()));
} else if (operationCode == 7) {
if (getActivity() != null) {
shareIntent.putExtra(Intent.EXTRA_TEXT, ShareUtils.getStringForIntent(getActivity(),
editText.getText().toString(), userUtils, conversation));
Intent intent = new Intent(shareIntent);
intent.setComponent(new ComponentName(packageName, name));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getActivity().startActivity(intent);
eventBus.post(new BottomSheetLockEvent(true, 0, false, true));
} }
} else if (operationCode != 11) { textInputLayout.setErrorEnabled(false);
eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); } else if ((editText.getText().toString().startsWith("http://") ||
bundle = new Bundle(); editText.getText().toString().startsWith("https://")) &&
bundle.putInt(BundleKeys.INSTANCE.getKEY_OPERATION_CODE(), operationCode); editText.getText().toString().contains("/call/")) {
bundle.putString(BundleKeys.INSTANCE.getKEY_CALL_URL(), editText.getText().toString()); // operation code 10
getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) if (!proceedButton.isEnabled()) {
.pushChangeHandler(new HorizontalChangeHandler()) proceedButton.setEnabled(true);
.popChangeHandler(new HorizontalChangeHandler())); proceedButton.setAlpha(1.0f);
}
} else if (operationCode == 11) { textInputLayout.setErrorEnabled(false);
eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); } else {
originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), editText.getText().toString()); if (proceedButton.isEnabled()) {
getRouter().pushController(RouterTransaction.with(new OperationsMenuController(originalBundle)) proceedButton.setEnabled(false);
.pushChangeHandler(new HorizontalChangeHandler()) proceedButton.setAlpha(0.38f);
.popChangeHandler(new HorizontalChangeHandler())); }
textInputLayout.setError(getResources().getString(R.string.nc_wrong_link));
}
} else {
if (proceedButton.isEnabled()) {
proceedButton.setEnabled(false);
proceedButton.setAlpha(0.38f);
}
textInputLayout.setErrorEnabled(false);
} }
} }
});
@Override String labelText = "";
protected void onViewBound(@NonNull View view) { switch (operationCode) {
super.onViewBound(view); case 11:
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); case 2:
labelText = getResources().getString(R.string.nc_call_name);
if (conversation != null && operationCode == 2) { editText.setInputType(InputType.TYPE_CLASS_TEXT);
editText.setText(conversation.getName()); smileyButton.setVisibility(View.VISIBLE);
} emojiPopup = EmojiPopup.Builder.fromRootView(view)
.setOnEmojiPopupShownListener(new OnEmojiPopupShownListener() {
editText.setOnEditorActionListener((v, actionId, event) -> { @Override
if (actionId == EditorInfo.IME_ACTION_DONE && proceedButton != null && proceedButton.isEnabled()) { public void onEmojiPopupShown() {
proceedButton.callOnClick(); if (getResources() != null) {
return true; smileyButton.setColorFilter(getResources().getColor(R.color.colorPrimary),
} PorterDuff.Mode.SRC_IN);
return false;
});
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (!TextUtils.isEmpty(s)) {
if (operationCode == 2) {
if (conversation.getName() == null || !conversation.getName().equals(s.toString())) {
if (!proceedButton.isEnabled()) {
proceedButton.setEnabled(true);
proceedButton.setAlpha(1.0f);
}
textInputLayout.setErrorEnabled(false);
} else {
if (proceedButton.isEnabled()) {
proceedButton.setEnabled(false);
proceedButton.setAlpha(0.38f);
}
textInputLayout.setError(getResources().getString(R.string.nc_call_name_is_same));
}
} else if (operationCode != 10) {
if (!proceedButton.isEnabled()) {
proceedButton.setEnabled(true);
proceedButton.setAlpha(1.0f);
}
textInputLayout.setErrorEnabled(false);
} else if ((editText.getText().toString().startsWith("http://") ||
editText.getText().toString().startsWith("https://")) &&
editText.getText().toString().contains("/call/")) {
// operation code 10
if (!proceedButton.isEnabled()) {
proceedButton.setEnabled(true);
proceedButton.setAlpha(1.0f);
}
textInputLayout.setErrorEnabled(false);
} else {
if (proceedButton.isEnabled()) {
proceedButton.setEnabled(false);
proceedButton.setAlpha(0.38f);
}
textInputLayout.setError(getResources().getString(R.string.nc_wrong_link));
}
} else {
if (proceedButton.isEnabled()) {
proceedButton.setEnabled(false);
proceedButton.setAlpha(0.38f);
}
textInputLayout.setErrorEnabled(false);
} }
} }
}); })
.setOnEmojiPopupDismissListener(new OnEmojiPopupDismissListener() {
@Override
public void onEmojiPopupDismiss() {
if (smileyButton != null) {
smileyButton.setColorFilter(getResources().getColor(R.color.emoji_icons),
PorterDuff.Mode.SRC_IN);
}
}
})
.setOnEmojiClickListener(new OnEmojiClickListener() {
@Override
public void onEmojiClick(@NonNull EmojiImageView emoji, @NonNull Emoji imageView) {
editText.getEditableText().append(" ");
}
})
.build(editText);
String labelText = ""; break;
switch (operationCode) { case 4:
case 11: labelText = getResources().getString(R.string.nc_new_password);
case 2: editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
labelText = getResources().getString(R.string.nc_call_name); break;
editText.setInputType(InputType.TYPE_CLASS_TEXT); case 6:
smileyButton.setVisibility(View.VISIBLE); case 7:
emojiPopup = EmojiPopup.Builder.fromRootView(view).setOnEmojiPopupShownListener(new OnEmojiPopupShownListener() { case 99:
@Override // 99 is joining a conversation via password
public void onEmojiPopupShown() { labelText = getResources().getString(R.string.nc_password);
if (getResources() != null) { editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
smileyButton.setColorFilter(getResources().getColor(R.color.colorPrimary), break;
PorterDuff.Mode.SRC_IN); case 10:
} labelText = getResources().getString(R.string.nc_conversation_link);
} editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
}).setOnEmojiPopupDismissListener(new OnEmojiPopupDismissListener() { break;
@Override default:
public void onEmojiPopupDismiss() { break;
if (smileyButton != null) {
smileyButton.setColorFilter(getResources().getColor(R.color.emoji_icons),
PorterDuff.Mode.SRC_IN);
}
}
}).setOnEmojiClickListener(new OnEmojiClickListener() {
@Override
public void onEmojiClick(@NonNull EmojiImageView emoji, @NonNull Emoji imageView) {
editText.getEditableText().append(" ");
}
}).build(editText);
break;
case 4:
labelText = getResources().getString(R.string.nc_new_password);
editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
break;
case 6:
case 7:
case 99:
// 99 is joining a conversation via password
labelText = getResources().getString(R.string.nc_password);
editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
break;
case 10:
labelText = getResources().getString(R.string.nc_conversation_link);
editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
break;
default:
break;
}
textInputLayout.setPasswordVisibilityToggleEnabled(operationCode == 99 || operationCode == 4 || operationCode == 6 || operationCode == 7);
textInputLayout.setHint(labelText);
textInputLayout.requestFocus();
} }
textInputLayout.setPasswordVisibilityToggleEnabled(
operationCode == 99 || operationCode == 4 || operationCode == 6 || operationCode == 7);
textInputLayout.setHint(labelText);
textInputLayout.requestFocus();
}
} }

View File

@ -24,15 +24,16 @@ import android.widget.ImageView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
interface ListItemWithImage { interface ListItemWithImage {
val title: String val title: String
fun populateIcon(imageView: ImageView) fun populateIcon(imageView: ImageView)
} }
data class BasicListItemWithImage( data class BasicListItemWithImage(
@DrawableRes val iconRes: Int, @DrawableRes val iconRes: Int,
override val title: String) : ListItemWithImage { override val title: String
) : ListItemWithImage {
override fun populateIcon(imageView: ImageView) { override fun populateIcon(imageView: ImageView) {
imageView.setImageResource(iconRes) imageView.setImageResource(iconRes)
} }
} }

View File

@ -38,112 +38,117 @@ import com.nextcloud.talk.R
private const val KEY_ACTIVATED_INDEX = "activated_index" private const val KEY_ACTIVATED_INDEX = "activated_index"
internal class ListItemViewHolder( internal class ListItemViewHolder(
itemView: View, itemView: View,
private val adapter: ListIconDialogAdapter<*>) : RecyclerView.ViewHolder(itemView), View.OnClickListener { private val adapter: ListIconDialogAdapter<*>
init { ) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
itemView.setOnClickListener(this) init {
} itemView.setOnClickListener(this)
}
val iconView: ImageView = itemView.findViewById(R.id.icon) val iconView: ImageView = itemView.findViewById(R.id.icon)
val titleView: RtlTextView = itemView.findViewById(R.id.title) val titleView: RtlTextView = itemView.findViewById(R.id.title)
override fun onClick(view: View) = adapter.itemClicked(adapterPosition) override fun onClick(view: View) = adapter.itemClicked(adapterPosition)
} }
internal class ListIconDialogAdapter<IT : ListItemWithImage>( internal class ListIconDialogAdapter<IT : ListItemWithImage>(
private var dialog: MaterialDialog, private var dialog: MaterialDialog,
private var items: List<IT>, private var items: List<IT>,
disabledItems: IntArray?, disabledItems: IntArray?,
private var waitForPositiveButton: Boolean, private var waitForPositiveButton: Boolean,
private var selection: ListItemListener<IT>) : RecyclerView.Adapter<ListItemViewHolder>(), DialogAdapter<IT, ListItemListener<IT>> { private var selection: ListItemListener<IT>
) : RecyclerView.Adapter<ListItemViewHolder>(), DialogAdapter<IT, ListItemListener<IT>> {
private var disabledIndices: IntArray = disabledItems ?: IntArray(0) private var disabledIndices: IntArray = disabledItems ?: IntArray(0)
fun itemClicked(index: Int) { fun itemClicked(index: Int) {
if (waitForPositiveButton && dialog.hasActionButton(WhichButton.POSITIVE)) { if (waitForPositiveButton && dialog.hasActionButton(WhichButton.POSITIVE)) {
// Wait for positive action button, mark clicked item as activated so that we can call the // Wait for positive action button, mark clicked item as activated so that we can call the
// selection listener when the button is pressed. // selection listener when the button is pressed.
val lastActivated = dialog.config[KEY_ACTIVATED_INDEX] as? Int val lastActivated = dialog.config[KEY_ACTIVATED_INDEX] as? Int
dialog.config[KEY_ACTIVATED_INDEX] = index dialog.config[KEY_ACTIVATED_INDEX] = index
if (lastActivated != null) { if (lastActivated != null) {
notifyItemChanged(lastActivated) notifyItemChanged(lastActivated)
} }
notifyItemChanged(index) notifyItemChanged(index)
} else { } else {
// Don't wait for action buttons, call listener and dismiss if auto dismiss is applicable // Don't wait for action buttons, call listener and dismiss if auto dismiss is applicable
this.selection?.invoke(dialog, index, this.items[index]) this.selection?.invoke(dialog, index, this.items[index])
if (dialog.autoDismissEnabled && !dialog.hasActionButtons()) { if (dialog.autoDismissEnabled && !dialog.hasActionButtons()) {
dialog.dismiss() dialog.dismiss()
} }
}
} }
}
override fun onCreateViewHolder( override fun onCreateViewHolder(
parent: ViewGroup, parent: ViewGroup,
viewType: Int): ListItemViewHolder { viewType: Int
val listItemView: View = parent.inflate(dialog.windowContext, R.layout.menu_item_sheet) ): ListItemViewHolder {
val viewHolder = ListItemViewHolder( val listItemView: View = parent.inflate(dialog.windowContext, R.layout.menu_item_sheet)
itemView = listItemView, val viewHolder = ListItemViewHolder(
adapter = this itemView = listItemView,
) adapter = this
viewHolder.titleView.maybeSetTextColor(dialog.windowContext, R.attr.md_color_content) )
return viewHolder viewHolder.titleView.maybeSetTextColor(dialog.windowContext, R.attr.md_color_content)
return viewHolder
}
override fun getItemCount() = items.size
override fun onBindViewHolder(
holder: ListItemViewHolder,
position: Int
) {
holder.itemView.isEnabled = !disabledIndices.contains(position)
val currentItem = items[position]
holder.titleView.text = currentItem.title
holder.itemView.background = dialog.getItemSelector()
currentItem.populateIcon(holder.iconView)
val activatedIndex = dialog.config[KEY_ACTIVATED_INDEX] as? Int
holder.itemView.isActivated = activatedIndex != null && activatedIndex == position
if (dialog.bodyFont != null) {
holder.titleView.typeface = dialog.bodyFont
} }
}
override fun getItemCount() = items.size override fun positiveButtonClicked() {
val activatedIndex = dialog.config[KEY_ACTIVATED_INDEX] as? Int
override fun onBindViewHolder( if (activatedIndex != null) {
holder: ListItemViewHolder, selection?.invoke(dialog, activatedIndex, items[activatedIndex])
position: Int) { dialog.config.remove(KEY_ACTIVATED_INDEX)
holder.itemView.isEnabled = !disabledIndices.contains(position)
val currentItem = items[position]
holder.titleView.text = currentItem.title
holder.itemView.background = dialog.getItemSelector()
currentItem.populateIcon(holder.iconView)
val activatedIndex = dialog.config[KEY_ACTIVATED_INDEX] as? Int
holder.itemView.isActivated = activatedIndex != null && activatedIndex == position
if (dialog.bodyFont != null) {
holder.titleView.typeface = dialog.bodyFont
}
} }
}
override fun positiveButtonClicked() { override fun replaceItems(
val activatedIndex = dialog.config[KEY_ACTIVATED_INDEX] as? Int items: List<IT>,
if (activatedIndex != null) { listener: ListItemListener<IT>
selection?.invoke(dialog, activatedIndex, items[activatedIndex]) ) {
dialog.config.remove(KEY_ACTIVATED_INDEX) this.items = items
} if (listener != null) {
this.selection = listener
} }
this.notifyDataSetChanged()
}
override fun replaceItems( override fun disableItems(indices: IntArray) {
items: List<IT>, this.disabledIndices = indices
listener: ListItemListener<IT>) { notifyDataSetChanged()
this.items = items }
if (listener != null) {
this.selection = listener
}
this.notifyDataSetChanged()
}
override fun disableItems(indices: IntArray) { override fun checkItems(indices: IntArray) = Unit
this.disabledIndices = indices
notifyDataSetChanged()
}
override fun checkItems(indices: IntArray) = Unit override fun uncheckItems(indices: IntArray) = Unit
override fun uncheckItems(indices: IntArray) = Unit override fun toggleItems(indices: IntArray) = Unit
override fun toggleItems(indices: IntArray) = Unit override fun checkAllItems() = Unit
override fun checkAllItems() = Unit override fun uncheckAllItems() = Unit
override fun uncheckAllItems() = Unit override fun toggleAllChecked() = Unit
override fun toggleAllChecked() = Unit override fun isItemChecked(index: Int) = false
override fun isItemChecked(index: Int) = false
} }

View File

@ -28,48 +28,50 @@ import com.afollestad.materialdialogs.list.customListAdapter
import com.afollestad.materialdialogs.list.getListAdapter import com.afollestad.materialdialogs.list.getListAdapter
typealias ListItemListener<IT> = typealias ListItemListener<IT> =
((dialog: MaterialDialog, index: Int, item: IT) -> Unit)? ((dialog: MaterialDialog, index: Int, item: IT) -> Unit)?
@CheckResult fun <IT : ListItemWithImage> MaterialDialog.listItemsWithImage( @CheckResult fun <IT : ListItemWithImage> MaterialDialog.listItemsWithImage(
items: List<IT>, items: List<IT>,
disabledIndices: IntArray? = null, disabledIndices: IntArray? = null,
waitForPositiveButton: Boolean = true, waitForPositiveButton: Boolean = true,
selection: ListItemListener<IT> = null): MaterialDialog { selection: ListItemListener<IT> = null
): MaterialDialog {
if (getListAdapter() != null) { if (getListAdapter() != null) {
return updateListItemsWithImage( return updateListItemsWithImage(
items = items, items = items,
disabledIndices = disabledIndices disabledIndices = disabledIndices
)
}
val layoutManager = LinearLayoutManager(windowContext)
return customListAdapter(
adapter = ListIconDialogAdapter(
dialog = this,
items = items,
disabledItems = disabledIndices,
waitForPositiveButton = waitForPositiveButton,
selection = selection
),
layoutManager = layoutManager
) )
}
val layoutManager = LinearLayoutManager(windowContext)
return customListAdapter(
adapter = ListIconDialogAdapter(
dialog = this,
items = items,
disabledItems = disabledIndices,
waitForPositiveButton = waitForPositiveButton,
selection = selection
),
layoutManager = layoutManager
)
} }
fun MaterialDialog.updateListItemsWithImage( fun MaterialDialog.updateListItemsWithImage(
items: List<ListItemWithImage>, items: List<ListItemWithImage>,
disabledIndices: IntArray? = null): MaterialDialog { disabledIndices: IntArray? = null
val adapter = getListAdapter() ): MaterialDialog {
check(adapter != null) { val adapter = getListAdapter()
"updateGridItems(...) can't be used before you've created a bottom sheet grid dialog." check(adapter != null) {
} "updateGridItems(...) can't be used before you've created a bottom sheet grid dialog."
if (adapter is DialogAdapter<*, *>) { }
@Suppress("UNCHECKED_CAST") if (adapter is DialogAdapter<*, *>) {
(adapter as DialogAdapter<ListItemWithImage, *>).replaceItems(items) @Suppress("UNCHECKED_CAST")
(adapter as DialogAdapter<ListItemWithImage, *>).replaceItems(items)
if (disabledIndices != null) { if (disabledIndices != null) {
adapter.disableItems(disabledIndices) adapter.disableItems(disabledIndices)
}
} }
return this }
return this
} }

View File

@ -28,9 +28,9 @@ import org.greenrobot.eventbus.EventBus;
@Module @Module
public class BusModule { public class BusModule {
@Provides @Provides
@Singleton @Singleton
public EventBus provideEventBus() { public EventBus provideEventBus() {
return EventBus.getDefault(); return EventBus.getDefault();
} }
} }

View File

@ -27,14 +27,14 @@ import dagger.Provides;
@Module @Module
public class ContextModule { public class ContextModule {
private final Context context; private final Context context;
public ContextModule(@NonNull final Context context) { public ContextModule(@NonNull final Context context) {
this.context = context; this.context = context;
} }
@Provides @Provides
public Context provideContext() { public Context provideContext() {
return context; return context;
} }
} }

View File

@ -39,25 +39,26 @@ import net.orange_box.storebox.StoreBox;
@Module @Module
public class DatabaseModule { public class DatabaseModule {
@Provides @Provides
@Singleton @Singleton
public SqlCipherDatabaseSource provideSqlCipherDatabaseSource(@NonNull final Context context) { public SqlCipherDatabaseSource provideSqlCipherDatabaseSource(@NonNull final Context context) {
return new SqlCipherDatabaseSource(context, Models.DEFAULT, return new SqlCipherDatabaseSource(context, Models.DEFAULT,
context.getResources().getString(R.string.nc_app_name).toLowerCase() context.getResources().getString(R.string.nc_app_name).toLowerCase()
.replace(" ", "_").trim() + ".sqlite", .replace(" ", "_").trim() + ".sqlite",
context.getString(R.string.nc_talk_database_encryption_key), 6); context.getString(R.string.nc_talk_database_encryption_key), 6);
} }
@Provides @Provides
@Singleton @Singleton
public ReactiveEntityStore<Persistable> provideDataStore(@NonNull final SqlCipherDatabaseSource sqlCipherDatabaseSource) { public ReactiveEntityStore<Persistable> provideDataStore(
final Configuration configuration = sqlCipherDatabaseSource.getConfiguration(); @NonNull final SqlCipherDatabaseSource sqlCipherDatabaseSource) {
return ReactiveSupport.toReactiveStore(new EntityDataStore<Persistable>(configuration)); final Configuration configuration = sqlCipherDatabaseSource.getConfiguration();
} return ReactiveSupport.toReactiveStore(new EntityDataStore<Persistable>(configuration));
}
@Provides @Provides
@Singleton @Singleton
public AppPreferences providePreferences(@NonNull final Context poContext) { public AppPreferences providePreferences(@NonNull final Context poContext) {
return StoreBox.create(poContext, AppPreferences.class); return StoreBox.create(poContext, AppPreferences.class);
} }
} }

View File

@ -73,250 +73,253 @@ import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
@Module(includes = DatabaseModule.class) @Module(includes = DatabaseModule.class)
public class RestModule { public class RestModule {
private static final String TAG = "RestModule"; private static final String TAG = "RestModule";
private final Context context; private final Context context;
public RestModule(Context context) { public RestModule(Context context) {
this.context = context; this.context = context;
}
@Singleton
@Provides
NcApi provideNcApi(Retrofit retrofit) {
return retrofit.create(NcApi.class);
}
@Singleton
@Provides
Proxy provideProxy(AppPreferences appPreferences) {
if (!TextUtils.isEmpty(appPreferences.getProxyType()) && !"No proxy".equals(
appPreferences.getProxyType())
&& !TextUtils.isEmpty(appPreferences.getProxyHost())) {
GetProxyRunnable getProxyRunnable = new GetProxyRunnable(appPreferences);
Thread getProxyThread = new Thread(getProxyRunnable);
getProxyThread.start();
try {
getProxyThread.join();
return getProxyRunnable.getProxyValue();
} catch (InterruptedException e) {
Log.e(TAG, "Failed to join the thread while getting proxy: " + e.getLocalizedMessage());
return Proxy.NO_PROXY;
}
} else {
return Proxy.NO_PROXY;
}
}
@Singleton
@Provides
Retrofit provideRetrofit(OkHttpClient httpClient) {
Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
.client(httpClient)
.baseUrl("https://nextcloud.com")
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
.addConverterFactory(LoganSquareConverterFactory.create());
return retrofitBuilder.build();
}
@Singleton
@Provides
MagicTrustManager provideMagicTrustManager() {
return new MagicTrustManager();
}
@Singleton
@Provides
MagicKeyManager provideKeyManager(AppPreferences appPreferences, UserUtils userUtils) {
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyManagerFactory kmf =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, null);
X509KeyManager origKm = (X509KeyManager) kmf.getKeyManagers()[0];
return new MagicKeyManager(origKm, userUtils, appPreferences);
} catch (KeyStoreException e) {
Log.e(TAG, "KeyStoreException " + e.getLocalizedMessage());
} catch (CertificateException e) {
Log.e(TAG, "CertificateException " + e.getLocalizedMessage());
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "NoSuchAlgorithmException " + e.getLocalizedMessage());
} catch (IOException e) {
Log.e(TAG, "IOException " + e.getLocalizedMessage());
} catch (UnrecoverableKeyException e) {
Log.e(TAG, "UnrecoverableKeyException " + e.getLocalizedMessage());
} }
@Singleton return null;
@Provides }
NcApi provideNcApi(Retrofit retrofit) {
return retrofit.create(NcApi.class); @Singleton
@Provides
SSLSocketFactoryCompat provideSslSocketFactoryCompat(MagicKeyManager keyManager, MagicTrustManager
magicTrustManager) {
return new SSLSocketFactoryCompat(keyManager, magicTrustManager);
}
@Singleton
@Provides
CookieManager provideCookieManager() {
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_NONE);
return cookieManager;
}
@Singleton
@Provides
Cache provideCache() {
int cacheSize = 128 * 1024 * 1024; // 128 MB
return new Cache(NextcloudTalkApplication.Companion.getSharedApplication().getCacheDir(),
cacheSize);
}
@Singleton
@Provides
Dispatcher provideDispatcher() {
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequestsPerHost(100);
dispatcher.setMaxRequests(100);
return dispatcher;
}
@Singleton
@Provides
OkHttpClient provideHttpClient(Proxy proxy, AppPreferences appPreferences,
MagicTrustManager magicTrustManager,
SSLSocketFactoryCompat sslSocketFactoryCompat, Cache cache,
CookieManager cookieManager, Dispatcher dispatcher) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.retryOnConnectionFailure(true);
httpClient.connectTimeout(45, TimeUnit.SECONDS);
httpClient.readTimeout(45, TimeUnit.SECONDS);
httpClient.writeTimeout(45, TimeUnit.SECONDS);
httpClient.cookieJar(new JavaNetCookieJar(cookieManager));
httpClient.cache(cache);
// Trust own CA and all self-signed certs
httpClient.sslSocketFactory(sslSocketFactoryCompat, magicTrustManager);
httpClient.retryOnConnectionFailure(true);
httpClient.hostnameVerifier(magicTrustManager.getHostnameVerifier(OkHostnameVerifier.INSTANCE));
httpClient.dispatcher(dispatcher);
if (!Proxy.NO_PROXY.equals(proxy)) {
httpClient.proxy(proxy);
if (appPreferences.getProxyCredentials() &&
!TextUtils.isEmpty(appPreferences.getProxyUsername()) &&
!TextUtils.isEmpty(appPreferences.getProxyPassword())) {
httpClient.proxyAuthenticator(new MagicAuthenticator(Credentials.basic(
appPreferences.getProxyUsername(),
appPreferences.getProxyPassword()), "Proxy-Authorization"));
}
} }
@Singleton httpClient.addInterceptor(new HeadersInterceptor());
@Provides
Proxy provideProxy(AppPreferences appPreferences) { if (BuildConfig.DEBUG && !context.getResources().getBoolean(R.bool.nc_is_debug)) {
if (!TextUtils.isEmpty(appPreferences.getProxyType()) && !"No proxy".equals(appPreferences.getProxyType()) HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
&& !TextUtils.isEmpty(appPreferences.getProxyHost())) { loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
GetProxyRunnable getProxyRunnable = new GetProxyRunnable(appPreferences); loggingInterceptor.redactHeader("Authorization");
Thread getProxyThread = new Thread(getProxyRunnable); loggingInterceptor.redactHeader("Proxy-Authorization");
getProxyThread.start(); httpClient.addInterceptor(loggingInterceptor);
try { } else if (context.getResources().getBoolean(R.bool.nc_is_debug)) {
getProxyThread.join();
return getProxyRunnable.getProxyValue(); HttpLoggingInterceptor.Logger fileLogger =
} catch (InterruptedException e) { s -> LoggingUtils.INSTANCE.writeLogEntryToFile(context, s);
Log.e(TAG, "Failed to join the thread while getting proxy: " + e.getLocalizedMessage()); HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(fileLogger);
return Proxy.NO_PROXY; loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
} loggingInterceptor.redactHeader("Authorization");
} else { loggingInterceptor.redactHeader("Proxy-Authorization");
return Proxy.NO_PROXY; httpClient.addInterceptor(loggingInterceptor);
}
} }
@Singleton return httpClient.build();
@Provides }
Retrofit provideRetrofit(OkHttpClient httpClient) {
Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
.client(httpClient)
.baseUrl("https://nextcloud.com")
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
.addConverterFactory(LoganSquareConverterFactory.create());
return retrofitBuilder.build(); public static class HeadersInterceptor implements Interceptor {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("User-Agent", ApiUtils.getUserAgent())
.header("Accept", "application/json")
.header("OCS-APIRequest", "true")
.method(original.method(), original.body())
.build();
Response response = chain.proceed(request);
if (request.url().encodedPath().contains("/avatar/")) {
AvatarStatusCodeHolder.getInstance().setStatusCode(response.code());
}
return response;
}
}
public static class MagicAuthenticator implements Authenticator {
private String credentials;
private String authenticatorType;
public MagicAuthenticator(@NonNull String credentials, @NonNull String authenticatorType) {
this.credentials = credentials;
this.authenticatorType = authenticatorType;
} }
@Singleton @Nullable
@Provides @Override
MagicTrustManager provideMagicTrustManager() { public Request authenticate(@Nullable Route route, @NonNull Response response) {
return new MagicTrustManager(); if (response.request().header(authenticatorType) != null) {
}
@Singleton
@Provides
MagicKeyManager provideKeyManager(AppPreferences appPreferences, UserUtils userUtils) {
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, null);
X509KeyManager origKm = (X509KeyManager) kmf.getKeyManagers()[0];
return new MagicKeyManager(origKm, userUtils, appPreferences);
} catch (KeyStoreException e) {
Log.e(TAG, "KeyStoreException " + e.getLocalizedMessage());
} catch (CertificateException e) {
Log.e(TAG, "CertificateException " + e.getLocalizedMessage());
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "NoSuchAlgorithmException " + e.getLocalizedMessage());
} catch (IOException e) {
Log.e(TAG, "IOException " + e.getLocalizedMessage());
} catch (UnrecoverableKeyException e) {
Log.e(TAG, "UnrecoverableKeyException " + e.getLocalizedMessage());
}
return null; return null;
} }
@Singleton Response countedResponse = response;
@Provides
SSLSocketFactoryCompat provideSslSocketFactoryCompat(MagicKeyManager keyManager, MagicTrustManager
magicTrustManager) {
return new SSLSocketFactoryCompat(keyManager, magicTrustManager);
}
@Singleton int attemptsCount = 0;
@Provides
CookieManager provideCookieManager() {
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_NONE);
return cookieManager;
}
@Singleton while ((countedResponse = countedResponse.priorResponse()) != null) {
@Provides attemptsCount++;
Cache provideCache() { if (attemptsCount == 3) {
int cacheSize = 128 * 1024 * 1024; // 128 MB return null;
return new Cache(NextcloudTalkApplication.Companion.getSharedApplication().getCacheDir(), cacheSize);
}
@Singleton
@Provides
Dispatcher provideDispatcher() {
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequestsPerHost(100);
dispatcher.setMaxRequests(100);
return dispatcher;
}
@Singleton
@Provides
OkHttpClient provideHttpClient(Proxy proxy, AppPreferences appPreferences,
MagicTrustManager magicTrustManager,
SSLSocketFactoryCompat sslSocketFactoryCompat, Cache cache,
CookieManager cookieManager, Dispatcher dispatcher) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.retryOnConnectionFailure(true);
httpClient.connectTimeout(45, TimeUnit.SECONDS);
httpClient.readTimeout(45, TimeUnit.SECONDS);
httpClient.writeTimeout(45, TimeUnit.SECONDS);
httpClient.cookieJar(new JavaNetCookieJar(cookieManager));
httpClient.cache(cache);
// Trust own CA and all self-signed certs
httpClient.sslSocketFactory(sslSocketFactoryCompat, magicTrustManager);
httpClient.retryOnConnectionFailure(true);
httpClient.hostnameVerifier(magicTrustManager.getHostnameVerifier(OkHostnameVerifier.INSTANCE));
httpClient.dispatcher(dispatcher);
if (!Proxy.NO_PROXY.equals(proxy)) {
httpClient.proxy(proxy);
if (appPreferences.getProxyCredentials() &&
!TextUtils.isEmpty(appPreferences.getProxyUsername()) &&
!TextUtils.isEmpty(appPreferences.getProxyPassword())) {
httpClient.proxyAuthenticator(new MagicAuthenticator(Credentials.basic(
appPreferences.getProxyUsername(),
appPreferences.getProxyPassword()), "Proxy-Authorization"));
}
} }
}
httpClient.addInterceptor(new HeadersInterceptor()); return response.request().newBuilder()
.header(authenticatorType, credentials)
.build();
}
}
if (BuildConfig.DEBUG && !context.getResources().getBoolean(R.bool.nc_is_debug)) { private class GetProxyRunnable implements Runnable {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); private volatile Proxy proxy;
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); private AppPreferences appPreferences;
loggingInterceptor.redactHeader("Authorization");
loggingInterceptor.redactHeader("Proxy-Authorization");
httpClient.addInterceptor(loggingInterceptor);
} else if (context.getResources().getBoolean(R.bool.nc_is_debug)) {
HttpLoggingInterceptor.Logger fileLogger = GetProxyRunnable(AppPreferences appPreferences) {
s -> LoggingUtils.INSTANCE.writeLogEntryToFile(context, s); this.appPreferences = appPreferences;
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(fileLogger);
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
loggingInterceptor.redactHeader("Authorization");
loggingInterceptor.redactHeader("Proxy-Authorization");
httpClient.addInterceptor(loggingInterceptor);
}
return httpClient.build();
} }
public static class HeadersInterceptor implements Interceptor { @Override
public void run() {
@NonNull if (Proxy.Type.SOCKS.equals(Proxy.Type.valueOf(appPreferences.getProxyType()))) {
@Override proxy = new Proxy(Proxy.Type.valueOf(appPreferences.getProxyType()),
public Response intercept(@NonNull Chain chain) throws IOException { InetSocketAddress.createUnresolved(appPreferences.getProxyHost(), Integer.parseInt(
Request original = chain.request(); appPreferences.getProxyPort())));
Request request = original.newBuilder() } else {
.header("User-Agent", ApiUtils.getUserAgent()) proxy = new Proxy(Proxy.Type.valueOf(appPreferences.getProxyType()),
.header("Accept", "application/json") new InetSocketAddress(appPreferences.getProxyHost(),
.header("OCS-APIRequest", "true") Integer.parseInt(appPreferences.getProxyPort())));
.method(original.method(), original.body()) }
.build();
Response response = chain.proceed(request);
if (request.url().encodedPath().contains("/avatar/")) {
AvatarStatusCodeHolder.getInstance().setStatusCode(response.code());
}
return response;
}
} }
public static class MagicAuthenticator implements Authenticator { Proxy getProxyValue() {
return proxy;
private String credentials;
private String authenticatorType;
public MagicAuthenticator(@NonNull String credentials, @NonNull String authenticatorType) {
this.credentials = credentials;
this.authenticatorType = authenticatorType;
}
@Nullable
@Override
public Request authenticate(@Nullable Route route, @NonNull Response response) {
if (response.request().header(authenticatorType) != null) {
return null;
}
Response countedResponse = response;
int attemptsCount = 0;
while ((countedResponse = countedResponse.priorResponse()) != null) {
attemptsCount++;
if (attemptsCount == 3) {
return null;
}
}
return response.request().newBuilder()
.header(authenticatorType, credentials)
.build();
}
}
private class GetProxyRunnable implements Runnable {
private volatile Proxy proxy;
private AppPreferences appPreferences;
GetProxyRunnable(AppPreferences appPreferences) {
this.appPreferences = appPreferences;
}
@Override
public void run() {
if (Proxy.Type.SOCKS.equals(Proxy.Type.valueOf(appPreferences.getProxyType()))) {
proxy = new Proxy(Proxy.Type.valueOf(appPreferences.getProxyType()),
InetSocketAddress.createUnresolved(appPreferences.getProxyHost(), Integer.parseInt(
appPreferences.getProxyPort())));
} else {
proxy = new Proxy(Proxy.Type.valueOf(appPreferences.getProxyType()),
new InetSocketAddress(appPreferences.getProxyHost(),
Integer.parseInt(appPreferences.getProxyPort())));
}
}
Proxy getProxyValue() {
return proxy;
}
} }
}
} }

View File

@ -24,27 +24,28 @@ import lombok.Data;
@Data @Data
public class BottomSheetLockEvent { public class BottomSheetLockEvent {
private final boolean cancelable; private final boolean cancelable;
private final int delay; private final int delay;
private final boolean shouldRefreshData; private final boolean shouldRefreshData;
private final boolean cancel; private final boolean cancel;
private boolean dismissView; private boolean dismissView;
public BottomSheetLockEvent(boolean cancelable, int delay, boolean shouldRefreshData, boolean cancel) { public BottomSheetLockEvent(boolean cancelable, int delay, boolean shouldRefreshData,
this.cancelable = cancelable; boolean cancel) {
this.delay = delay; this.cancelable = cancelable;
this.shouldRefreshData = shouldRefreshData; this.delay = delay;
this.cancel = cancel; this.shouldRefreshData = shouldRefreshData;
this.dismissView = true; this.cancel = cancel;
} this.dismissView = true;
}
public BottomSheetLockEvent(boolean cancelable, int delay, boolean shouldRefreshData, boolean cancel, boolean
dismissView) {
this.cancelable = cancelable;
this.delay = delay;
this.shouldRefreshData = shouldRefreshData;
this.cancel = cancel;
this.dismissView = dismissView;
}
public BottomSheetLockEvent(boolean cancelable, int delay, boolean shouldRefreshData,
boolean cancel, boolean
dismissView) {
this.cancelable = cancelable;
this.delay = delay;
this.shouldRefreshData = shouldRefreshData;
this.cancel = cancel;
this.dismissView = dismissView;
}
} }

View File

@ -26,28 +26,28 @@ import com.nextcloud.talk.utils.ssl.MagicTrustManager;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
public class CertificateEvent { public class CertificateEvent {
private final X509Certificate x509Certificate; private final X509Certificate x509Certificate;
private final MagicTrustManager magicTrustManager; private final MagicTrustManager magicTrustManager;
@Nullable @Nullable
private final SslErrorHandler sslErrorHandler; private final SslErrorHandler sslErrorHandler;
public CertificateEvent(X509Certificate x509Certificate, MagicTrustManager magicTrustManager, public CertificateEvent(X509Certificate x509Certificate, MagicTrustManager magicTrustManager,
@Nullable SslErrorHandler sslErrorHandler) { @Nullable SslErrorHandler sslErrorHandler) {
this.x509Certificate = x509Certificate; this.x509Certificate = x509Certificate;
this.magicTrustManager = magicTrustManager; this.magicTrustManager = magicTrustManager;
this.sslErrorHandler = sslErrorHandler; this.sslErrorHandler = sslErrorHandler;
} }
@Nullable @Nullable
public SslErrorHandler getSslErrorHandler() { public SslErrorHandler getSslErrorHandler() {
return sslErrorHandler; return sslErrorHandler;
} }
public X509Certificate getX509Certificate() { public X509Certificate getX509Certificate() {
return x509Certificate; return x509Certificate;
} }
public MagicTrustManager getMagicTrustManager() { public MagicTrustManager getMagicTrustManager() {
return magicTrustManager; return magicTrustManager;
} }
} }

View File

@ -24,18 +24,17 @@ import lombok.Data;
@Data @Data
public class EventStatus { public class EventStatus {
private long userId; private long userId;
private EventType eventType; private EventType eventType;
private boolean allGood; private boolean allGood;
public EventStatus(long userId, EventType eventType, boolean allGood) { public EventStatus(long userId, EventType eventType, boolean allGood) {
this.userId = userId; this.userId = userId;
this.eventType = eventType; this.eventType = eventType;
this.allGood = allGood; this.allGood = allGood;
} }
public enum EventType {
PUSH_REGISTRATION, CAPABILITIES_FETCH, SIGNALING_SETTINGS, CONVERSATION_UPDATE, PARTICIPANTS_UPDATE
}
public enum EventType {
PUSH_REGISTRATION, CAPABILITIES_FETCH, SIGNALING_SETTINGS, CONVERSATION_UPDATE, PARTICIPANTS_UPDATE
}
} }

View File

@ -26,13 +26,14 @@ import org.webrtc.MediaStream;
@Data @Data
public class MediaStreamEvent { public class MediaStreamEvent {
private final MediaStream mediaStream; private final MediaStream mediaStream;
private final String session; private final String session;
private final String videoStreamType; private final String videoStreamType;
public MediaStreamEvent(@Nullable MediaStream mediaStream, String session, String videoStreamType) { public MediaStreamEvent(@Nullable MediaStream mediaStream, String session,
this.mediaStream = mediaStream; String videoStreamType) {
this.session = session; this.mediaStream = mediaStream;
this.videoStreamType = videoStreamType; this.session = session;
} this.videoStreamType = videoStreamType;
}
} }

View File

@ -25,9 +25,9 @@ import lombok.Data;
@Data @Data
public class MoreMenuClickEvent { public class MoreMenuClickEvent {
private final Conversation conversation; private final Conversation conversation;
public MoreMenuClickEvent(Conversation conversation) { public MoreMenuClickEvent(Conversation conversation) {
this.conversation = conversation; this.conversation = conversation;
} }
} }

View File

@ -24,13 +24,13 @@ import lombok.Data;
@Data @Data
public class NetworkEvent { public class NetworkEvent {
public enum NetworkConnectionEvent { private final NetworkConnectionEvent networkConnectionEvent;
NETWORK_CONNECTED, NETWORK_DISCONNECTED
}
private final NetworkConnectionEvent networkConnectionEvent; public NetworkEvent(NetworkConnectionEvent networkConnectionEvent) {
this.networkConnectionEvent = networkConnectionEvent;
}
public NetworkEvent(NetworkConnectionEvent networkConnectionEvent) { public enum NetworkConnectionEvent {
this.networkConnectionEvent = networkConnectionEvent; NETWORK_CONNECTED, NETWORK_DISCONNECTED
} }
} }

View File

@ -25,22 +25,23 @@ import lombok.Data;
@Data @Data
public class PeerConnectionEvent { public class PeerConnectionEvent {
private final PeerConnectionEventType peerConnectionEventType; private final PeerConnectionEventType peerConnectionEventType;
private final String sessionId; private final String sessionId;
private final String nick; private final String nick;
private final Boolean changeValue; private final Boolean changeValue;
private final String videoStreamType; private final String videoStreamType;
public PeerConnectionEvent(PeerConnectionEventType peerConnectionEventType, @Nullable String sessionId, public PeerConnectionEvent(PeerConnectionEventType peerConnectionEventType,
@Nullable String nick, Boolean changeValue, @Nullable String videoStreamType) { @Nullable String sessionId,
this.peerConnectionEventType = peerConnectionEventType; @Nullable String nick, Boolean changeValue, @Nullable String videoStreamType) {
this.nick = nick; this.peerConnectionEventType = peerConnectionEventType;
this.changeValue = changeValue; this.nick = nick;
this.sessionId = sessionId; this.changeValue = changeValue;
this.videoStreamType = videoStreamType; this.sessionId = sessionId;
} this.videoStreamType = videoStreamType;
}
public enum PeerConnectionEventType { public enum PeerConnectionEventType {
PEER_CONNECTED, PEER_CLOSED, SENSOR_FAR, SENSOR_NEAR, NICK_CHANGE, AUDIO_CHANGE, VIDEO_CHANGE, PUBLISHER_FAILED PEER_CONNECTED, PEER_CLOSED, SENSOR_FAR, SENSOR_NEAR, NICK_CHANGE, AUDIO_CHANGE, VIDEO_CHANGE, PUBLISHER_FAILED
} }
} }

View File

@ -27,20 +27,21 @@ import org.webrtc.SessionDescription;
@Data @Data
public class SessionDescriptionSendEvent { public class SessionDescriptionSendEvent {
@Nullable @Nullable
private final SessionDescription sessionDescription; private final SessionDescription sessionDescription;
private final String peerId; private final String peerId;
private final String type; private final String type;
@Nullable @Nullable
private final NCIceCandidate ncIceCandidate; private final NCIceCandidate ncIceCandidate;
private final String videoStreamType; private final String videoStreamType;
public SessionDescriptionSendEvent(@Nullable SessionDescription sessionDescription, String peerId, String type, public SessionDescriptionSendEvent(@Nullable SessionDescription sessionDescription, String peerId,
@Nullable NCIceCandidate ncIceCandidate, @Nullable String videoStreamType) { String type,
this.sessionDescription = sessionDescription; @Nullable NCIceCandidate ncIceCandidate, @Nullable String videoStreamType) {
this.peerId = peerId; this.sessionDescription = sessionDescription;
this.type = type; this.peerId = peerId;
this.ncIceCandidate = ncIceCandidate; this.type = type;
this.videoStreamType = videoStreamType; this.ncIceCandidate = ncIceCandidate;
} this.videoStreamType = videoStreamType;
}
} }

View File

@ -24,5 +24,5 @@ import lombok.Data;
@Data @Data
public class UserMentionClickEvent { public class UserMentionClickEvent {
public final String userId; public final String userId;
} }

View File

@ -26,7 +26,7 @@ import lombok.Data;
@Data @Data
public class WebSocketCommunicationEvent { public class WebSocketCommunicationEvent {
public final String type; public final String type;
@Nullable @Nullable
public final HashMap<String, String> hashMap; public final HashMap<String, String> hashMap;
} }

View File

@ -22,6 +22,6 @@ package com.nextcloud.talk.interfaces
interface ClosedInterface { interface ClosedInterface {
val isGooglePlayServicesAvailable: Boolean val isGooglePlayServicesAvailable: Boolean
fun providerInstallerInstallIfNeededAsync() fun providerInstallerInstallIfNeededAsync()
} }

View File

@ -23,5 +23,8 @@ package com.nextcloud.talk.interfaces
import android.os.Bundle import android.os.Bundle
interface ConversationMenuInterface { interface ConversationMenuInterface {
fun openLovelyDialogWithIdAndBundle(dialogId: Int, bundle: Bundle) fun openLovelyDialogWithIdAndBundle(
dialogId: Int,
bundle: Bundle
)
} }

View File

@ -21,7 +21,7 @@
package com.nextcloud.talk.interfaces package com.nextcloud.talk.interfaces
interface SelectionInterface { interface SelectionInterface {
fun toggleBrowserItemSelection(path: String) fun toggleBrowserItemSelection(path: String)
fun isPathSelected(path: String): Boolean fun isPathSelected(path: String): Boolean
} }

View File

@ -30,12 +30,12 @@ import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import com.bluelinelabs.logansquare.LoganSquare; import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.models.json.generic.GenericOverall;
import com.nextcloud.talk.models.json.push.PushConfigurationState;
import com.nextcloud.talk.R; import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.generic.GenericOverall;
import com.nextcloud.talk.models.json.push.PushConfigurationState;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageUtils; import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageUtils;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;
@ -54,196 +54,205 @@ import retrofit2.Retrofit;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class AccountRemovalWorker extends Worker { public class AccountRemovalWorker extends Worker {
public static final String TAG = "AccountRemovalWorker"; public static final String TAG = "AccountRemovalWorker";
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
ArbitraryStorageUtils arbitraryStorageUtils; ArbitraryStorageUtils arbitraryStorageUtils;
@Inject @Inject
Retrofit retrofit; Retrofit retrofit;
@Inject @Inject
OkHttpClient okHttpClient; OkHttpClient okHttpClient;
NcApi ncApi; NcApi ncApi;
public AccountRemovalWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { public AccountRemovalWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams); super(context, workerParams);
} }
@NonNull @NonNull
@Override @Override
public Result doWork() { public Result doWork() {
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
PushConfigurationState pushConfigurationState; PushConfigurationState pushConfigurationState;
String credentials; String credentials;
for (Object userEntityObject : userUtils.getUsersScheduledForDeletion()) { for (Object userEntityObject : userUtils.getUsersScheduledForDeletion()) {
UserEntity userEntity = (UserEntity) userEntityObject; UserEntity userEntity = (UserEntity) userEntityObject;
try { try {
if (!TextUtils.isEmpty(userEntity.getPushConfigurationState())) { if (!TextUtils.isEmpty(userEntity.getPushConfigurationState())) {
pushConfigurationState = LoganSquare.parse(userEntity.getPushConfigurationState(), pushConfigurationState = LoganSquare.parse(userEntity.getPushConfigurationState(),
PushConfigurationState.class); PushConfigurationState.class);
PushConfigurationState finalPushConfigurationState = pushConfigurationState; PushConfigurationState finalPushConfigurationState = pushConfigurationState;
credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()); credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken());
ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new
JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class); JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class);
String finalCredentials = credentials; String finalCredentials = credentials;
ncApi.unregisterDeviceForNotificationsWithNextcloud(credentials, ApiUtils.getUrlNextcloudPush(userEntity ncApi.unregisterDeviceForNotificationsWithNextcloud(credentials,
.getBaseUrl())) ApiUtils.getUrlNextcloudPush(userEntity
.blockingSubscribe(new Observer<GenericOverall>() { .getBaseUrl()))
@Override .blockingSubscribe(new Observer<GenericOverall>() {
public void onSubscribe(Disposable d) { @Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(GenericOverall genericOverall) {
if (genericOverall.getOcs().getMeta().getStatusCode() == 200
|| genericOverall.getOcs().getMeta().getStatusCode() == 202) {
HashMap<String, String> queryMap = new HashMap<>();
queryMap.put("deviceIdentifier", finalPushConfigurationState.getDeviceIdentifier());
queryMap.put("userPublicKey", finalPushConfigurationState.getUserPublicKey());
queryMap.put("deviceIdentifierSignature",
finalPushConfigurationState.getDeviceIdentifierSignature());
ncApi.unregisterDeviceForNotificationsWithProxy
(ApiUtils.getUrlPushProxy(), queryMap)
.subscribe(new Observer<Void>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Void aVoid) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String groupName = String.format(getApplicationContext().getResources()
.getString(R.string
.nc_notification_channel), userEntity.getUserId(), userEntity.getBaseUrl());
CRC32 crc32 = new CRC32();
crc32.update(groupName.getBytes());
NotificationManager notificationManager =
(NotificationManager) getApplicationContext().getSystemService
(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.deleteNotificationChannelGroup(Long
.toString(crc32.getValue()));
}
}
WebSocketConnectionHelper.deleteExternalSignalingInstanceForUserEntity(userEntity.getId());
arbitraryStorageUtils.deleteAllEntriesForAccountIdentifier(userEntity.getId()).subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Object o) {
userUtils.deleteUser(userEntity.getId()).subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
}
});
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
} else {
userUtils.deleteUser(userEntity.getId())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
}
});
} }
} catch (IOException e) {
Log.d(TAG, "Something went wrong while removing job at parsing PushConfigurationState");
userUtils.deleteUser(userEntity.getId())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
@Override
public void onNext(GenericOverall genericOverall) {
if (genericOverall.getOcs().getMeta().getStatusCode() == 200
|| genericOverall.getOcs().getMeta().getStatusCode() == 202) {
HashMap<String, String> queryMap = new HashMap<>();
queryMap.put("deviceIdentifier",
finalPushConfigurationState.getDeviceIdentifier());
queryMap.put("userPublicKey", finalPushConfigurationState.getUserPublicKey());
queryMap.put("deviceIdentifierSignature",
finalPushConfigurationState.getDeviceIdentifierSignature());
ncApi.unregisterDeviceForNotificationsWithProxy
(ApiUtils.getUrlPushProxy(), queryMap)
.subscribe(new Observer<Void>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Void aVoid) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String groupName =
String.format(getApplicationContext().getResources()
.getString(R.string
.nc_notification_channel), userEntity.getUserId(),
userEntity.getBaseUrl());
CRC32 crc32 = new CRC32();
crc32.update(groupName.getBytes());
NotificationManager notificationManager =
(NotificationManager) getApplicationContext().getSystemService
(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.deleteNotificationChannelGroup(Long
.toString(crc32.getValue()));
}
} }
@Override WebSocketConnectionHelper.deleteExternalSignalingInstanceForUserEntity(
public void onComplete() { userEntity.getId());
} arbitraryStorageUtils.deleteAllEntriesForAccountIdentifier(
userEntity.getId()).subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
@Override }
public void onError(Throwable e) {
} @Override
public void onNext(Object o) {
userUtils.deleteUser(userEntity.getId())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
}
});
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
}); });
} }
} }
return Result.success(); @Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
} else {
userUtils.deleteUser(userEntity.getId())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
}
});
}
} catch (IOException e) {
Log.d(TAG, "Something went wrong while removing job at parsing PushConfigurationState");
userUtils.deleteUser(userEntity.getId())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
}
});
}
} }
return Result.success();
}
} }

View File

@ -26,10 +26,10 @@ import androidx.work.Data;
import androidx.work.Worker; import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import com.nextcloud.talk.models.RetrofitBucket;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.events.EventStatus; import com.nextcloud.talk.events.EventStatus;
import com.nextcloud.talk.models.RetrofitBucket;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
@ -40,50 +40,56 @@ import org.greenrobot.eventbus.EventBus;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class AddParticipantsToConversation extends Worker { public class AddParticipantsToConversation extends Worker {
@Inject @Inject
NcApi ncApi; NcApi ncApi;
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
EventBus eventBus; EventBus eventBus;
public AddParticipantsToConversation(@NonNull Context context, @NonNull WorkerParameters workerParams) { public AddParticipantsToConversation(@NonNull Context context,
super(context, workerParams); @NonNull WorkerParameters workerParams) {
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); super(context, workerParams);
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
}
@NonNull
@Override
public Result doWork() {
Data data = getInputData();
String[] selectedUserIds = data.getStringArray(BundleKeys.INSTANCE.getKEY_SELECTED_USERS());
String[] selectedGroupIds = data.getStringArray(BundleKeys.INSTANCE.getKEY_SELECTED_GROUPS());
UserEntity user = userUtils.getUserWithInternalId(
data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1));
String conversationToken = data.getString(BundleKeys.INSTANCE.getKEY_TOKEN());
String credentials = ApiUtils.getCredentials(user.getUsername(), user.getToken());
RetrofitBucket retrofitBucket;
for (String userId : selectedUserIds) {
retrofitBucket =
ApiUtils.getRetrofitBucketForAddParticipant(user.getBaseUrl(), conversationToken,
userId);
ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.io())
.blockingSubscribe();
} }
@NonNull for (String groupId : selectedGroupIds) {
@Override retrofitBucket =
public Result doWork() { ApiUtils.getRetrofitBucketForAddGroupParticipant(user.getBaseUrl(), conversationToken,
Data data = getInputData(); groupId);
String[] selectedUserIds = data.getStringArray(BundleKeys.INSTANCE.getKEY_SELECTED_USERS());
String[] selectedGroupIds = data.getStringArray(BundleKeys.INSTANCE.getKEY_SELECTED_GROUPS());
UserEntity user = userUtils.getUserWithInternalId(data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1));
String conversationToken = data.getString(BundleKeys.INSTANCE.getKEY_TOKEN());
String credentials = ApiUtils.getCredentials(user.getUsername(), user.getToken());
RetrofitBucket retrofitBucket; ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
for (String userId : selectedUserIds) { .subscribeOn(Schedulers.io())
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(user.getBaseUrl(), conversationToken, .blockingSubscribe();
userId);
ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.io())
.blockingSubscribe();
}
for (String groupId : selectedGroupIds) {
retrofitBucket = ApiUtils.getRetrofitBucketForAddGroupParticipant(user.getBaseUrl(), conversationToken,
groupId);
ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.io())
.blockingSubscribe();
}
eventBus.post(new EventStatus(user.getId(), EventStatus.EventType.PARTICIPANTS_UPDATE, true));
return Result.success();
} }
eventBus.post(new EventStatus(user.getId(), EventStatus.EventType.PARTICIPANTS_UPDATE, true));
return Result.success();
}
} }

View File

@ -28,11 +28,11 @@ import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import com.bluelinelabs.logansquare.LoganSquare; import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.events.EventStatus; import com.nextcloud.talk.events.EventStatus;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;
@ -50,114 +50,116 @@ import retrofit2.Retrofit;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class CapabilitiesWorker extends Worker { public class CapabilitiesWorker extends Worker {
public static final String TAG = "CapabilitiesWorker"; public static final String TAG = "CapabilitiesWorker";
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
Retrofit retrofit; Retrofit retrofit;
@Inject @Inject
EventBus eventBus; EventBus eventBus;
@Inject @Inject
OkHttpClient okHttpClient; OkHttpClient okHttpClient;
NcApi ncApi; NcApi ncApi;
public CapabilitiesWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { public CapabilitiesWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams); super(context, workerParams);
}
private void updateUser(CapabilitiesOverall capabilitiesOverall, UserEntity internalUserEntity) {
try {
userUtils.createOrUpdateUser(null, null,
null, null,
null, null, null, internalUserEntity.getId(),
LoganSquare.serialize(capabilitiesOverall.getOcs().getData().getCapabilities()), null,
null)
.blockingSubscribe(new Observer<UserEntity>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(UserEntity userEntity) {
eventBus.post(new EventStatus(userEntity.getId(),
EventStatus.EventType.CAPABILITIES_FETCH, true));
}
@Override
public void onError(Throwable e) {
eventBus.post(new EventStatus(internalUserEntity.getId(),
EventStatus.EventType.CAPABILITIES_FETCH, false));
}
@Override
public void onComplete() {
}
});
} catch (IOException e) {
Log.e(TAG, "Failed to create or update user");
}
}
@NonNull
@Override
public Result doWork() {
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
Data data = getInputData();
long internalUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1);
UserEntity userEntity;
List userEntityObjectList = new ArrayList();
if (internalUserId == -1
|| (userEntity = userUtils.getUserWithInternalId(internalUserId)) == null) {
userEntityObjectList = userUtils.getUsers();
} else {
userEntityObjectList.add(userEntity);
} }
private void updateUser(CapabilitiesOverall capabilitiesOverall, UserEntity internalUserEntity) { for (Object userEntityObject : userEntityObjectList) {
try { UserEntity internalUserEntity = (UserEntity) userEntityObject;
userUtils.createOrUpdateUser(null, null,
null, null,
null, null, null, internalUserEntity.getId(),
LoganSquare.serialize(capabilitiesOverall.getOcs().getData().getCapabilities()), null, null)
.blockingSubscribe(new Observer<UserEntity>() {
@Override
public void onSubscribe(Disposable d) {
} ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new
JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class);
@Override ncApi.getCapabilities(ApiUtils.getCredentials(internalUserEntity.getUsername(),
public void onNext(UserEntity userEntity) { internalUserEntity.getToken()),
eventBus.post(new EventStatus(userEntity.getId(), ApiUtils.getUrlForCapabilities(internalUserEntity.getBaseUrl()))
EventStatus.EventType.CAPABILITIES_FETCH, true)); .retry(3)
} .blockingSubscribe(new Observer<CapabilitiesOverall>() {
@Override
public void onSubscribe(Disposable d) {
@Override }
public void onError(Throwable e) {
eventBus.post(new EventStatus(internalUserEntity.getId(),
EventStatus.EventType.CAPABILITIES_FETCH, false));
}
@Override @Override
public void onComplete() { public void onNext(CapabilitiesOverall capabilitiesOverall) {
updateUser(capabilitiesOverall, internalUserEntity);
}
} @Override
}); public void onError(Throwable e) {
} catch (IOException e) { eventBus.post(new EventStatus(internalUserEntity.getId(),
Log.e(TAG, "Failed to create or update user"); EventStatus.EventType.CAPABILITIES_FETCH, false));
} }
@Override
public void onComplete() {
}
});
} }
@NonNull return Result.success();
@Override }
public Result doWork() {
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
Data data = getInputData();
long internalUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1);
UserEntity userEntity;
List userEntityObjectList = new ArrayList();
if (internalUserId == -1 || (userEntity = userUtils.getUserWithInternalId(internalUserId)) == null) {
userEntityObjectList = userUtils.getUsers();
} else {
userEntityObjectList.add(userEntity);
}
for (Object userEntityObject : userEntityObjectList) {
UserEntity internalUserEntity = (UserEntity) userEntityObject;
ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new
JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class);
ncApi.getCapabilities(ApiUtils.getCredentials(internalUserEntity.getUsername(),
internalUserEntity.getToken()), ApiUtils.getUrlForCapabilities(internalUserEntity.getBaseUrl()))
.retry(3)
.blockingSubscribe(new Observer<CapabilitiesOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(CapabilitiesOverall capabilitiesOverall) {
updateUser(capabilitiesOverall, internalUserEntity);
}
@Override
public void onError(Throwable e) {
eventBus.post(new EventStatus(internalUserEntity.getId(),
EventStatus.EventType.CAPABILITIES_FETCH, false));
}
@Override
public void onComplete() {
}
});
}
return Result.success();
}
} }

View File

@ -26,11 +26,11 @@ import androidx.work.Data;
import androidx.work.Worker; import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import com.nextcloud.talk.models.json.generic.GenericOverall;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.events.EventStatus; import com.nextcloud.talk.events.EventStatus;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.generic.GenericOverall;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;
@ -46,70 +46,72 @@ import retrofit2.Retrofit;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class DeleteConversationWorker extends Worker { public class DeleteConversationWorker extends Worker {
@Inject @Inject
Retrofit retrofit; Retrofit retrofit;
@Inject @Inject
OkHttpClient okHttpClient; OkHttpClient okHttpClient;
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
EventBus eventBus; EventBus eventBus;
NcApi ncApi; NcApi ncApi;
public DeleteConversationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { public DeleteConversationWorker(@NonNull Context context,
super(context, workerParams); @NonNull WorkerParameters workerParams) {
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); super(context, workerParams);
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
}
@NonNull
@Override
public Result doWork() {
Data data = getInputData();
long operationUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1);
String conversationToken = data.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN());
UserEntity operationUser = userUtils.getUserWithId(operationUserId);
if (operationUser != null) {
String credentials =
ApiUtils.getCredentials(operationUser.getUsername(), operationUser.getToken());
ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new
JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class);
EventStatus eventStatus = new EventStatus(operationUser.getId(),
EventStatus.EventType.CONVERSATION_UPDATE, true);
ncApi.deleteRoom(credentials, ApiUtils.getRoom(operationUser.getBaseUrl(), conversationToken))
.subscribeOn(Schedulers.io())
.blockingSubscribe(new Observer<GenericOverall>() {
Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
disposable = d;
}
@Override
public void onNext(GenericOverall genericOverall) {
eventBus.postSticky(eventStatus);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
disposable.dispose();
}
});
} }
@NonNull return Result.success();
@Override }
public Result doWork() {
Data data = getInputData();
long operationUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1);
String conversationToken = data.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN());
UserEntity operationUser = userUtils.getUserWithId(operationUserId);
if (operationUser != null) {
String credentials = ApiUtils.getCredentials(operationUser.getUsername(), operationUser.getToken());
ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new
JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class);
EventStatus eventStatus = new EventStatus(operationUser.getId(),
EventStatus.EventType.CONVERSATION_UPDATE, true);
ncApi.deleteRoom(credentials, ApiUtils.getRoom(operationUser.getBaseUrl(), conversationToken))
.subscribeOn(Schedulers.io())
.blockingSubscribe(new Observer<GenericOverall>() {
Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
disposable = d;
}
@Override
public void onNext(GenericOverall genericOverall) {
eventBus.postSticky(eventStatus);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
disposable.dispose();
}
});
}
return Result.success();
}
} }

View File

@ -26,11 +26,11 @@ import androidx.work.Data;
import androidx.work.Worker; import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import com.nextcloud.talk.models.json.generic.GenericOverall;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.events.EventStatus; import com.nextcloud.talk.events.EventStatus;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.generic.GenericOverall;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;
@ -46,70 +46,72 @@ import retrofit2.Retrofit;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class LeaveConversationWorker extends Worker { public class LeaveConversationWorker extends Worker {
@Inject @Inject
Retrofit retrofit; Retrofit retrofit;
@Inject @Inject
OkHttpClient okHttpClient; OkHttpClient okHttpClient;
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
EventBus eventBus; EventBus eventBus;
NcApi ncApi; NcApi ncApi;
public LeaveConversationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { public LeaveConversationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams); super(context, workerParams);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
}
@NonNull
@Override
public Result doWork() {
Data data = getInputData();
long operationUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1);
String conversationToken = data.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN());
UserEntity operationUser = userUtils.getUserWithId(operationUserId);
if (operationUser != null) {
String credentials =
ApiUtils.getCredentials(operationUser.getUsername(), operationUser.getToken());
ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new
JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class);
EventStatus eventStatus = new EventStatus(operationUser.getId(),
EventStatus.EventType.CONVERSATION_UPDATE, true);
ncApi.removeSelfFromRoom(credentials,
ApiUtils.getUrlForRemoveSelfFromRoom(operationUser.getBaseUrl(), conversationToken))
.subscribeOn(Schedulers.io())
.blockingSubscribe(new Observer<GenericOverall>() {
Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
disposable = d;
}
@Override
public void onNext(GenericOverall genericOverall) {
eventBus.postSticky(eventStatus);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
disposable.dispose();
}
});
} }
@NonNull return Result.success();
@Override }
public Result doWork() {
Data data = getInputData();
long operationUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1);
String conversationToken = data.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN());
UserEntity operationUser = userUtils.getUserWithId(operationUserId);
if (operationUser != null) {
String credentials = ApiUtils.getCredentials(operationUser.getUsername(), operationUser.getToken());
ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(new
JavaNetCookieJar(new CookieManager())).build()).build().create(NcApi.class);
EventStatus eventStatus = new EventStatus(operationUser.getId(),
EventStatus.EventType.CONVERSATION_UPDATE, true);
ncApi.removeSelfFromRoom(credentials, ApiUtils.getUrlForRemoveSelfFromRoom(operationUser.getBaseUrl(), conversationToken))
.subscribeOn(Schedulers.io())
.blockingSubscribe(new Observer<GenericOverall>() {
Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
disposable = d;
}
@Override
public void onNext(GenericOverall genericOverall) {
eventBus.postSticky(eventStatus);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
disposable.dispose();
}
});
}
return Result.success();
}
} }

View File

@ -27,19 +27,19 @@ import androidx.work.WorkerParameters;
import com.nextcloud.talk.utils.PushUtils; import com.nextcloud.talk.utils.PushUtils;
public class PushRegistrationWorker extends Worker { public class PushRegistrationWorker extends Worker {
public static final String TAG = "PushRegistrationWorker"; public static final String TAG = "PushRegistrationWorker";
public PushRegistrationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { public PushRegistrationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams); super(context, workerParams);
} }
@NonNull @NonNull
@Override @Override
public Result doWork() { public Result doWork() {
PushUtils pushUtils = new PushUtils(); PushUtils pushUtils = new PushUtils();
pushUtils.generateRsa2048KeyPair(); pushUtils.generateRsa2048KeyPair();
pushUtils.pushRegistrationToServer(); pushUtils.pushRegistrationToServer();
return Result.success(); return Result.success();
} }
} }

View File

@ -42,63 +42,64 @@ import javax.inject.Inject;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class ShareOperationWorker extends Worker { public class ShareOperationWorker extends Worker {
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
NcApi ncApi; NcApi ncApi;
private long userId; private long userId;
private UserEntity operationsUser; private UserEntity operationsUser;
private String roomToken; private String roomToken;
private List<String> filesArray = new ArrayList<>(); private List<String> filesArray = new ArrayList<>();
private String credentials; private String credentials;
private String baseUrl; private String baseUrl;
public ShareOperationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { public ShareOperationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams); super(context, workerParams);
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication()
Data data = workerParams.getInputData(); .getComponentApplication()
userId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), 0); .inject(this);
roomToken = data.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()); Data data = workerParams.getInputData();
Collections.addAll(filesArray, data.getStringArray(BundleKeys.INSTANCE.getKEY_FILE_PATHS())); userId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), 0);
operationsUser = userUtils.getUserWithId(userId); roomToken = data.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN());
credentials = ApiUtils.getCredentials(operationsUser.getUsername(), operationsUser.getToken()); Collections.addAll(filesArray, data.getStringArray(BundleKeys.INSTANCE.getKEY_FILE_PATHS()));
baseUrl = operationsUser.getBaseUrl(); operationsUser = userUtils.getUserWithId(userId);
credentials = ApiUtils.getCredentials(operationsUser.getUsername(), operationsUser.getToken());
baseUrl = operationsUser.getBaseUrl();
}
@NonNull
@Override
public Result doWork() {
for (int i = 0; i < filesArray.size(); i++) {
ncApi.createRemoteShare(credentials,
ApiUtils.getSharingUrl(baseUrl),
filesArray.get(i),
roomToken,
"10")
.subscribeOn(Schedulers.io())
.blockingSubscribe(new Observer<Void>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Void aVoid) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
} }
return Result.success();
@NonNull }
@Override
public Result doWork() {
for (int i = 0; i < filesArray.size(); i++) {
ncApi.createRemoteShare(credentials,
ApiUtils.getSharingUrl(baseUrl),
filesArray.get(i),
roomToken,
"10")
.subscribeOn(Schedulers.io())
.blockingSubscribe(new Observer<Void>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Void aVoid) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
return Result.success();
}
} }

View File

@ -30,12 +30,12 @@ import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import com.bluelinelabs.logansquare.LoganSquare; import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.models.ExternalSignalingServer;
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.events.EventStatus; import com.nextcloud.talk.events.EventStatus;
import com.nextcloud.talk.models.ExternalSignalingServer;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;
@ -49,100 +49,112 @@ import org.greenrobot.eventbus.EventBus;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class SignalingSettingsWorker extends Worker { public class SignalingSettingsWorker extends Worker {
private static final String TAG = "SignalingSettingsJob"; private static final String TAG = "SignalingSettingsJob";
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
@Inject @Inject
NcApi ncApi; NcApi ncApi;
@Inject @Inject
EventBus eventBus; EventBus eventBus;
public SignalingSettingsWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { public SignalingSettingsWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams); super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
Data data = getInputData();
long internalUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1);
List<UserEntity> userEntityList = new ArrayList<>();
UserEntity userEntity;
if (internalUserId == -1
|| (userEntity = userUtils.getUserWithInternalId(internalUserId)) == null) {
userEntityList = userUtils.getUsers();
} else {
userEntityList.add(userEntity);
} }
@NonNull for (int i = 0; i < userEntityList.size(); i++) {
@Override userEntity = userEntityList.get(i);
public Result doWork() { UserEntity finalUserEntity = userEntity;
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); ncApi.getSignalingSettings(
ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()),
ApiUtils.getUrlForSignalingSettings(userEntity.getBaseUrl()))
.blockingSubscribe(new Observer<SignalingSettingsOverall>() {
@Override
public void onSubscribe(Disposable d) {
Data data = getInputData(); }
long internalUserId = data.getLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), -1); @Override
public void onNext(SignalingSettingsOverall signalingSettingsOverall) {
ExternalSignalingServer externalSignalingServer;
externalSignalingServer = new ExternalSignalingServer();
externalSignalingServer.setExternalSignalingServer(
signalingSettingsOverall.getOcs().getSettings().getExternalSignalingServer());
externalSignalingServer.setExternalSignalingTicket(
signalingSettingsOverall.getOcs().getSettings().getExternalSignalingTicket());
List<UserEntity> userEntityList = new ArrayList<>(); try {
UserEntity userEntity; userUtils.createOrUpdateUser(null, null, null, null, null,
if (internalUserId == -1 || (userEntity = userUtils.getUserWithInternalId(internalUserId)) == null) { null, null, finalUserEntity.getId(), null, null,
userEntityList = userUtils.getUsers(); LoganSquare.serialize(externalSignalingServer))
} else { .subscribe(new Observer<UserEntity>() {
userEntityList.add(userEntity); @Override
} public void onSubscribe(Disposable d) {
for (int i = 0; i < userEntityList.size(); i++) { }
userEntity = userEntityList.get(i);
UserEntity finalUserEntity = userEntity;
ncApi.getSignalingSettings(ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()),
ApiUtils.getUrlForSignalingSettings(userEntity.getBaseUrl()))
.blockingSubscribe(new Observer<SignalingSettingsOverall>() {
@Override
public void onSubscribe(Disposable d) {
} @Override
public void onNext(UserEntity userEntity) {
eventBus.post(new EventStatus(finalUserEntity.getId(),
EventStatus.EventType.SIGNALING_SETTINGS, true));
}
@Override @Override
public void onNext(SignalingSettingsOverall signalingSettingsOverall) { public void onError(Throwable e) {
ExternalSignalingServer externalSignalingServer; eventBus.post(new EventStatus(finalUserEntity.getId(),
externalSignalingServer = new ExternalSignalingServer(); EventStatus.EventType.SIGNALING_SETTINGS, false));
externalSignalingServer.setExternalSignalingServer(signalingSettingsOverall.getOcs().getSettings().getExternalSignalingServer()); }
externalSignalingServer.setExternalSignalingTicket(signalingSettingsOverall.getOcs().getSettings().getExternalSignalingTicket());
try { @Override
userUtils.createOrUpdateUser(null, null, null, null, null, public void onComplete() {
null, null, finalUserEntity.getId(), null, null, LoganSquare.serialize(externalSignalingServer))
.subscribe(new Observer<UserEntity>() {
@Override
public void onSubscribe(Disposable d) {
} }
@Override
public void onNext(UserEntity userEntity) {
eventBus.post(new EventStatus(finalUserEntity.getId(), EventStatus.EventType.SIGNALING_SETTINGS, true));
}
@Override
public void onError(Throwable e) {
eventBus.post(new EventStatus(finalUserEntity.getId(), EventStatus.EventType.SIGNALING_SETTINGS, false));
}
@Override
public void onComplete() {
}
});
} catch (IOException e) {
Log.e(TAG, "Failed to serialize external signaling server");
}
}
@Override
public void onError(Throwable e) {
eventBus.post(new EventStatus(finalUserEntity.getId(), EventStatus.EventType.SIGNALING_SETTINGS, false));
}
@Override
public void onComplete() {
}
}); });
} } catch (IOException e) {
Log.e(TAG, "Failed to serialize external signaling server");
}
}
OneTimeWorkRequest websocketConnectionsWorker = new OneTimeWorkRequest.Builder(WebsocketConnectionsWorker.class).build(); @Override
WorkManager.getInstance().enqueue(websocketConnectionsWorker); public void onError(Throwable e) {
eventBus.post(
new EventStatus(finalUserEntity.getId(), EventStatus.EventType.SIGNALING_SETTINGS,
false));
}
return Result.success(); @Override
public void onComplete() {
}
});
} }
OneTimeWorkRequest websocketConnectionsWorker =
new OneTimeWorkRequest.Builder(WebsocketConnectionsWorker.class).build();
WorkManager.getInstance().enqueue(websocketConnectionsWorker);
return Result.success();
}
} }

View File

@ -29,8 +29,8 @@ import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import autodagger.AutoInjector; import autodagger.AutoInjector;
import com.bluelinelabs.logansquare.LoganSquare; import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.models.ExternalSignalingServer;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.ExternalSignalingServer;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.utils.database.user.UserUtils; import com.nextcloud.talk.utils.database.user.UserUtils;
import com.nextcloud.talk.webrtc.WebSocketConnectionHelper; import com.nextcloud.talk.webrtc.WebSocketConnectionHelper;
@ -41,43 +41,47 @@ import javax.inject.Inject;
@AutoInjector(NextcloudTalkApplication.class) @AutoInjector(NextcloudTalkApplication.class)
public class WebsocketConnectionsWorker extends Worker { public class WebsocketConnectionsWorker extends Worker {
private static final String TAG = "WebsocketConnectionsWorker"; private static final String TAG = "WebsocketConnectionsWorker";
@Inject @Inject
UserUtils userUtils; UserUtils userUtils;
public WebsocketConnectionsWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { public WebsocketConnectionsWorker(@NonNull Context context,
super(context, workerParams); @NonNull WorkerParameters workerParams) {
} super(context, workerParams);
}
@SuppressLint("LongLogTag") @SuppressLint("LongLogTag")
@NonNull @NonNull
@Override @Override
public Result doWork() { public Result doWork() {
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
List<UserEntity> userEntityList = userUtils.getUsers(); List<UserEntity> userEntityList = userUtils.getUsers();
UserEntity userEntity; UserEntity userEntity;
ExternalSignalingServer externalSignalingServer; ExternalSignalingServer externalSignalingServer;
WebSocketConnectionHelper webSocketConnectionHelper = new WebSocketConnectionHelper(); WebSocketConnectionHelper webSocketConnectionHelper = new WebSocketConnectionHelper();
for (int i = 0; i < userEntityList.size(); i++) { for (int i = 0; i < userEntityList.size(); i++) {
userEntity = userEntityList.get(i); userEntity = userEntityList.get(i);
if (!TextUtils.isEmpty(userEntity.getExternalSignalingServer())) { if (!TextUtils.isEmpty(userEntity.getExternalSignalingServer())) {
try { try {
externalSignalingServer = LoganSquare.parse(userEntity.getExternalSignalingServer(), ExternalSignalingServer.class); externalSignalingServer = LoganSquare.parse(userEntity.getExternalSignalingServer(),
if (!TextUtils.isEmpty(externalSignalingServer.getExternalSignalingServer()) && ExternalSignalingServer.class);
!TextUtils.isEmpty(externalSignalingServer.getExternalSignalingTicket())) { if (!TextUtils.isEmpty(externalSignalingServer.getExternalSignalingServer()) &&
WebSocketConnectionHelper.getExternalSignalingInstanceForServer( !TextUtils.isEmpty(externalSignalingServer.getExternalSignalingTicket())) {
externalSignalingServer.getExternalSignalingServer(), WebSocketConnectionHelper.getExternalSignalingInstanceForServer(
userEntity, externalSignalingServer.getExternalSignalingTicket(), externalSignalingServer.getExternalSignalingServer(),
false); userEntity, externalSignalingServer.getExternalSignalingTicket(),
} false);
} catch (IOException e) { }
Log.e(TAG, "Failed to parse external signaling server"); } catch (IOException e) {
} Log.e(TAG, "Failed to parse external signaling server");
}
} }
}
return Result.success();
} }
return Result.success();
}
} }

View File

@ -29,8 +29,8 @@ import org.parceler.Parcel;
@Parcel @Parcel
@JsonObject @JsonObject
public class ExternalSignalingServer { public class ExternalSignalingServer {
@JsonField(name = "externalSignalingServer") @JsonField(name = "externalSignalingServer")
String externalSignalingServer; String externalSignalingServer;
@JsonField(name = "externalSignalingTicket") @JsonField(name = "externalSignalingTicket")
String externalSignalingTicket; String externalSignalingTicket;
} }

View File

@ -25,14 +25,14 @@ import lombok.Data;
@Data @Data
public class ImportAccount { public class ImportAccount {
public String username; public String username;
@Nullable @Nullable
public String token; public String token;
public String baseUrl; public String baseUrl;
public ImportAccount(String username, @Nullable String token, String baseUrl) { public ImportAccount(String username, @Nullable String token, String baseUrl) {
this.username = username; this.username = username;
this.token = token; this.token = token;
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
} }
} }

View File

@ -26,7 +26,7 @@ import org.parceler.Parcel;
@Parcel @Parcel
@Data @Data
public class LoginData { public class LoginData {
String serverUrl; String serverUrl;
String username; String username;
String token; String token;
} }

View File

@ -26,6 +26,6 @@ import org.parceler.Parcel;
@Parcel @Parcel
@Data @Data
public class RetrofitBucket { public class RetrofitBucket {
public String url; public String url;
public Map<String, String> queryMap; public Map<String, String> queryMap;
} }

View File

@ -32,9 +32,9 @@ import org.parceler.Parcel;
@JsonObject @JsonObject
@Data @Data
public class RingtoneSettings { public class RingtoneSettings {
@JsonField(name = "ringtoneUri", typeConverter = UriTypeConverter.class) @JsonField(name = "ringtoneUri", typeConverter = UriTypeConverter.class)
@Nullable @Nullable
Uri ringtoneUri; Uri ringtoneUri;
@JsonField(name = "ringtoneName") @JsonField(name = "ringtoneName")
String ringtoneName; String ringtoneName;
} }

View File

@ -20,7 +20,6 @@
package com.nextcloud.talk.models; package com.nextcloud.talk.models;
import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.database.UserEntity;
import lombok.Data; import lombok.Data;
import org.parceler.Parcel; import org.parceler.Parcel;
@ -28,6 +27,6 @@ import org.parceler.Parcel;
@Data @Data
@Parcel @Parcel
public class SignatureVerification { public class SignatureVerification {
boolean signatureValid; boolean signatureValid;
UserEntity userEntity; UserEntity userEntity;
} }

View File

@ -28,12 +28,12 @@ import java.io.Serializable;
@Entity @Entity
public interface ArbitraryStorage extends Parcelable, Persistable, Serializable { public interface ArbitraryStorage extends Parcelable, Persistable, Serializable {
@Key @Key
long getAccountIdentifier(); long getAccountIdentifier();
String getKey(); String getKey();
String getObject(); String getObject();
String getValue(); String getValue();
} }

View File

@ -33,98 +33,103 @@ import java.util.HashMap;
@Entity @Entity
public interface User extends Parcelable, Persistable, Serializable { public interface User extends Parcelable, Persistable, Serializable {
String TAG = "UserEntity"; String TAG = "UserEntity";
@Key @Key
@Generated @Generated
long getId(); long getId();
String getUserId(); String getUserId();
String getUsername(); String getUsername();
String getBaseUrl(); String getBaseUrl();
String getToken(); String getToken();
String getDisplayName(); String getDisplayName();
String getPushConfigurationState(); String getPushConfigurationState();
String getCapabilities(); String getCapabilities();
String getClientCertificate(); String getClientCertificate();
String getExternalSignalingServer(); String getExternalSignalingServer();
boolean getCurrent(); boolean getCurrent();
boolean getScheduledForDeletion(); boolean getScheduledForDeletion();
default boolean hasNotificationsCapability(String capabilityName) { default boolean hasNotificationsCapability(String capabilityName) {
if (getCapabilities() != null) { if (getCapabilities() != null) {
try { try {
Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class); Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
if (capabilities.getNotificationsCapability() != null && capabilities.getNotificationsCapability().getFeatures() != null) { if (capabilities.getNotificationsCapability() != null
return capabilities.getSpreedCapability().getFeatures().contains(capabilityName); && capabilities.getNotificationsCapability().getFeatures() != null) {
} return capabilities.getSpreedCapability().getFeatures().contains(capabilityName);
} catch (IOException e) {
Log.e(TAG, "Failed to get capabilities for the user");
}
} }
return false; } catch (IOException e) {
Log.e(TAG, "Failed to get capabilities for the user");
}
} }
return false;
}
default boolean hasExternalCapability(String capabilityName) { default boolean hasExternalCapability(String capabilityName) {
if (getCapabilities() != null) { if (getCapabilities() != null) {
try { try {
Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class); Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
if (capabilities.getExternalCapability() != null && capabilities.getExternalCapability().containsKey("v1")) { if (capabilities.getExternalCapability() != null && capabilities.getExternalCapability()
return capabilities.getExternalCapability().get("v1").contains("capabilityName"); .containsKey("v1")) {
} return capabilities.getExternalCapability().get("v1").contains("capabilityName");
} catch (IOException e) {
Log.e(TAG, "Failed to get capabilities for the user");
}
} }
return false; } catch (IOException e) {
Log.e(TAG, "Failed to get capabilities for the user");
}
} }
return false;
}
default boolean hasSpreedFeatureCapability(String capabilityName) { default boolean hasSpreedFeatureCapability(String capabilityName) {
if (getCapabilities() != null) { if (getCapabilities() != null) {
try { try {
Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class); Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
if (capabilities != null && capabilities.getSpreedCapability() != null && if (capabilities != null && capabilities.getSpreedCapability() != null &&
capabilities.getSpreedCapability().getFeatures() != null) { capabilities.getSpreedCapability().getFeatures() != null) {
return capabilities.getSpreedCapability().getFeatures().contains(capabilityName); return capabilities.getSpreedCapability().getFeatures().contains(capabilityName);
}
} catch (IOException e) {
Log.e(TAG, "Failed to get capabilities for the user");
}
} }
return false; } catch (IOException e) {
Log.e(TAG, "Failed to get capabilities for the user");
}
} }
return false;
}
default int getMessageMaxLength() { default int getMessageMaxLength() {
if (getCapabilities() != null) { if (getCapabilities() != null) {
Capabilities capabilities = null; Capabilities capabilities = null;
try { try {
capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class); capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
if (capabilities != null && capabilities.getSpreedCapability() != null && capabilities.getSpreedCapability().getConfig() != null if (capabilities != null
&& capabilities.getSpreedCapability().getConfig().containsKey("chat")) { && capabilities.getSpreedCapability() != null
HashMap<String, String> chatConfigHashMap = capabilities.getSpreedCapability().getConfig().get("chat"); && capabilities.getSpreedCapability().getConfig() != null
if (chatConfigHashMap != null && chatConfigHashMap.containsKey("max-length")) { && capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
int chatSize = Integer.parseInt(chatConfigHashMap.get("max-length")); HashMap<String, String> chatConfigHashMap =
if (chatSize > 0) { capabilities.getSpreedCapability().getConfig().get("chat");
return chatSize; if (chatConfigHashMap != null && chatConfigHashMap.containsKey("max-length")) {
} else { int chatSize = Integer.parseInt(chatConfigHashMap.get("max-length"));
return 1000; if (chatSize > 0) {
} return chatSize;
} } else {
} return 1000;
} catch (IOException e) {
e.printStackTrace();
} }
}
} }
return 1000; } catch (IOException e) {
e.printStackTrace();
}
} }
return 1000;
}
} }

View File

@ -31,6 +31,6 @@ import org.parceler.Parcel;
@Data @Data
@JsonObject @JsonObject
public class AutocompleteOCS extends GenericOCS { public class AutocompleteOCS extends GenericOCS {
@JsonField(name = "data") @JsonField(name = "data")
List<AutocompleteUser> data; List<AutocompleteUser> data;
} }

View File

@ -29,6 +29,6 @@ import org.parceler.Parcel;
@Data @Data
@JsonObject @JsonObject
public class AutocompleteOverall { public class AutocompleteOverall {
@JsonField(name = "ocs") @JsonField(name = "ocs")
AutocompleteOCS ocs; AutocompleteOCS ocs;
} }

View File

@ -29,12 +29,12 @@ import org.parceler.Parcel;
@Data @Data
@JsonObject @JsonObject
public class AutocompleteUser { public class AutocompleteUser {
@JsonField(name = "id") @JsonField(name = "id")
String id; String id;
@JsonField(name = "label") @JsonField(name = "label")
String label; String label;
@JsonField(name = "source") @JsonField(name = "source")
String source; String source;
} }

View File

@ -31,15 +31,15 @@ import org.parceler.Parcel;
@Data @Data
@JsonObject @JsonObject
public class Capabilities { public class Capabilities {
@JsonField(name = "spreed") @JsonField(name = "spreed")
SpreedCapability spreedCapability; SpreedCapability spreedCapability;
@JsonField(name = "notifications") @JsonField(name = "notifications")
NotificationsCapability notificationsCapability; NotificationsCapability notificationsCapability;
@JsonField(name = "theming") @JsonField(name = "theming")
ThemingCapability themingCapability; ThemingCapability themingCapability;
@JsonField(name = "external") @JsonField(name = "external")
HashMap<String, List<String>> externalCapability; HashMap<String, List<String>> externalCapability;
} }

View File

@ -29,6 +29,6 @@ import org.parceler.Parcel;
@Data @Data
@JsonObject @JsonObject
public class CapabilitiesList { public class CapabilitiesList {
@JsonField(name = "capabilities") @JsonField(name = "capabilities")
Capabilities capabilities; Capabilities capabilities;
} }

View File

@ -29,6 +29,6 @@ import org.parceler.Parcel;
@Parcel @Parcel
@JsonObject @JsonObject
public class CapabilitiesOCS extends GenericOCS { public class CapabilitiesOCS extends GenericOCS {
@JsonField(name = "data") @JsonField(name = "data")
CapabilitiesList data; CapabilitiesList data;
} }

View File

@ -28,6 +28,6 @@ import org.parceler.Parcel;
@Parcel @Parcel
@JsonObject @JsonObject
public class CapabilitiesOverall { public class CapabilitiesOverall {
@JsonField(name = "ocs") @JsonField(name = "ocs")
CapabilitiesOCS ocs; CapabilitiesOCS ocs;
} }

View File

@ -30,6 +30,6 @@ import org.parceler.Parcel;
@Data @Data
@JsonObject @JsonObject
public class NotificationsCapability { public class NotificationsCapability {
@JsonField(name = "ocs-endpoints") @JsonField(name = "ocs-endpoints")
List<String> features; List<String> features;
} }

View File

@ -31,9 +31,9 @@ import org.parceler.Parcel;
@Data @Data
@JsonObject @JsonObject
public class SpreedCapability { public class SpreedCapability {
@JsonField(name = "features") @JsonField(name = "features")
List<String> features; List<String> features;
@JsonField(name = "config") @JsonField(name = "config")
HashMap<String, HashMap<String, String>> config; HashMap<String, HashMap<String, String>> config;
} }

View File

@ -29,33 +29,33 @@ import org.parceler.Parcel;
@Data @Data
@JsonObject @JsonObject
class ThemingCapability { class ThemingCapability {
@JsonField(name = "name") @JsonField(name = "name")
String name; String name;
@JsonField(name = "url") @JsonField(name = "url")
String url; String url;
@JsonField(name = "slogan") @JsonField(name = "slogan")
String slogan; String slogan;
@JsonField(name = "color") @JsonField(name = "color")
String color; String color;
@JsonField(name = "color-text") @JsonField(name = "color-text")
String colorText; String colorText;
@JsonField(name = "color-element") @JsonField(name = "color-element")
String colorElement; String colorElement;
@JsonField(name = "logo") @JsonField(name = "logo")
String logo; String logo;
@JsonField(name = "background") @JsonField(name = "background")
String background; String background;
@JsonField(name = "background-plain") @JsonField(name = "background-plain")
boolean backgroundPlain; boolean backgroundPlain;
@JsonField(name = "background-default") @JsonField(name = "background-default")
boolean backgroundDefault; boolean backgroundDefault;
} }

View File

@ -45,233 +45,269 @@ import org.parceler.Parcel;
@Data @Data
@JsonObject @JsonObject
public class ChatMessage implements IMessage, MessageContentType, MessageContentType.Image { public class ChatMessage implements IMessage, MessageContentType, MessageContentType.Image {
@JsonIgnore @JsonIgnore
public boolean isGrouped; public boolean isGrouped;
@JsonIgnore @JsonIgnore
public boolean isOneToOneConversation; public boolean isOneToOneConversation;
@JsonIgnore @JsonIgnore
public UserEntity activeUser; public UserEntity activeUser;
@JsonIgnore @JsonIgnore
public Map<String, String> selectedIndividualHashMap; public Map<String, String> selectedIndividualHashMap;
@JsonIgnore @JsonIgnore
public boolean isLinkPreviewAllowed; public boolean isLinkPreviewAllowed;
List<MessageType> messageTypesToIgnore = Arrays.asList(MessageType.REGULAR_TEXT_MESSAGE, @JsonField(name = "id")
MessageType.SYSTEM_MESSAGE, MessageType.SINGLE_LINK_VIDEO_MESSAGE, public int jsonMessageId;
MessageType.SINGLE_LINK_AUDIO_MESSAGE, MessageType.SINGLE_LINK_MESSAGE); @JsonField(name = "token")
@JsonField(name = "id") public String token;
public int jsonMessageId; // guests or users
@JsonField(name = "token") @JsonField(name = "actorType")
public String token; public String actorType;
// guests or users @JsonField(name = "actorId")
@JsonField(name = "actorType") public String actorId;
public String actorType; // send when crafting a message
@JsonField(name = "actorId") @JsonField(name = "actorDisplayName")
public String actorId; public String actorDisplayName;
// send when crafting a message @JsonField(name = "timestamp")
@JsonField(name = "actorDisplayName") public long timestamp;
public String actorDisplayName; // send when crafting a message, max 1000 lines
@JsonField(name = "timestamp") @JsonField(name = "message")
public long timestamp; public String message;
// send when crafting a message, max 1000 lines @JsonField(name = "messageParameters")
@JsonField(name = "message") public HashMap<String, HashMap<String, String>> messageParameters;
public String message; @JsonField(name = "systemMessage", typeConverter = EnumSystemMessageTypeConverter.class)
@JsonField(name = "messageParameters") public SystemMessageType systemMessageType;
public HashMap<String, HashMap<String, String>> messageParameters; List<MessageType> messageTypesToIgnore = Arrays.asList(MessageType.REGULAR_TEXT_MESSAGE,
@JsonField(name = "systemMessage", typeConverter = EnumSystemMessageTypeConverter.class) MessageType.SYSTEM_MESSAGE, MessageType.SINGLE_LINK_VIDEO_MESSAGE,
public SystemMessageType systemMessageType; MessageType.SINGLE_LINK_AUDIO_MESSAGE, MessageType.SINGLE_LINK_MESSAGE);
private boolean hasFileAttachment() { private boolean hasFileAttachment() {
if (messageParameters != null && messageParameters.size() > 0) { if (messageParameters != null && messageParameters.size() > 0) {
for (String key : messageParameters.keySet()) { for (String key : messageParameters.keySet()) {
Map<String, String> individualHashMap = messageParameters.get(key); Map<String, String> individualHashMap = messageParameters.get(key);
if (individualHashMap.get("type").equals("file")) { if (individualHashMap.get("type").equals("file")) {
return true; return true;
}
}
} }
}
return false;
} }
@Nullable return false;
@Override }
public String getImageUrl() {
if (messageParameters != null && messageParameters.size() > 0) { @Nullable
for (String key : messageParameters.keySet()) { @Override
Map<String, String> individualHashMap = messageParameters.get(key); public String getImageUrl() {
if (individualHashMap.get("type").equals("file")) { if (messageParameters != null && messageParameters.size() > 0) {
selectedIndividualHashMap = individualHashMap; for (String key : messageParameters.keySet()) {
return (ApiUtils.getUrlForFilePreviewWithFileId(getActiveUser().getBaseUrl(), Map<String, String> individualHashMap = messageParameters.get(key);
individualHashMap.get("id"), NextcloudTalkApplication.Companion.getSharedApplication().getResources().getDimensionPixelSize(R.dimen.maximum_file_preview_size))); if (individualHashMap.get("type").equals("file")) {
} selectedIndividualHashMap = individualHashMap;
} return (ApiUtils.getUrlForFilePreviewWithFileId(getActiveUser().getBaseUrl(),
individualHashMap.get("id"), NextcloudTalkApplication.Companion.getSharedApplication()
.getResources()
.getDimensionPixelSize(R.dimen.maximum_file_preview_size)));
} }
}
if (!messageTypesToIgnore.contains(getMessageType()) && isLinkPreviewAllowed) {
return getMessage().trim();
}
return null;
} }
public MessageType getMessageType() { if (!messageTypesToIgnore.contains(getMessageType()) && isLinkPreviewAllowed) {
if (!TextUtils.isEmpty(getSystemMessage())) { return getMessage().trim();
return MessageType.SYSTEM_MESSAGE;
}
if (hasFileAttachment()) {
return MessageType.SINGLE_NC_ATTACHMENT_MESSAGE;
}
return TextMatchers.getMessageTypeFromString(getText());
} }
public Map<String, String> getSelectedIndividualHashMap() { return null;
return selectedIndividualHashMap; }
public MessageType getMessageType() {
if (!TextUtils.isEmpty(getSystemMessage())) {
return MessageType.SYSTEM_MESSAGE;
} }
public void setSelectedIndividualHashMap(Map<String, String> selectedIndividualHashMap) { if (hasFileAttachment()) {
this.selectedIndividualHashMap = selectedIndividualHashMap; return MessageType.SINGLE_NC_ATTACHMENT_MESSAGE;
} }
@Override return TextMatchers.getMessageTypeFromString(getText());
public String getId() { }
return Integer.toString(jsonMessageId);
}
@Override public Map<String, String> getSelectedIndividualHashMap() {
public String getText() { return selectedIndividualHashMap;
return ChatUtils.getParsedMessage(getMessage(), getMessageParameters()); }
}
public String getLastMessageDisplayText() { public void setSelectedIndividualHashMap(Map<String, String> selectedIndividualHashMap) {
if (getMessageType().equals(MessageType.REGULAR_TEXT_MESSAGE) || getMessageType().equals(MessageType.SYSTEM_MESSAGE)) { this.selectedIndividualHashMap = selectedIndividualHashMap;
return getText(); }
@Override
public String getId() {
return Integer.toString(jsonMessageId);
}
@Override
public String getText() {
return ChatUtils.getParsedMessage(getMessage(), getMessageParameters());
}
public String getLastMessageDisplayText() {
if (getMessageType().equals(MessageType.REGULAR_TEXT_MESSAGE) || getMessageType().equals(
MessageType.SYSTEM_MESSAGE)) {
return getText();
} else {
if (getMessageType().equals(MessageType.SINGLE_LINK_GIPHY_MESSAGE)
|| getMessageType().equals(MessageType.SINGLE_LINK_TENOR_MESSAGE)
|| getMessageType().equals(MessageType.SINGLE_LINK_GIF_MESSAGE)) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_sent_a_gif_you));
} else { } else {
if (getMessageType().equals(MessageType.SINGLE_LINK_GIPHY_MESSAGE) return (String.format(NextcloudTalkApplication.Companion.getSharedApplication()
|| getMessageType().equals(MessageType.SINGLE_LINK_TENOR_MESSAGE) .getResources()
|| getMessageType().equals(MessageType.SINGLE_LINK_GIF_MESSAGE)) { .getString(R.string.nc_sent_a_gif),
if (getActorId().equals(getActiveUser().getUserId())) { !TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName()
return (NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_sent_a_gif_you)); : NextcloudTalkApplication.Companion.getSharedApplication()
} else { .getString(R.string.nc_guest)));
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication().getResources().getString(R.string.nc_sent_a_gif),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_NC_ATTACHMENT_MESSAGE)) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_sent_an_attachment_you));
} else {
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication().getResources().getString(R.string.nc_sent_an_attachment),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_MESSAGE)) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_sent_a_link_you));
} else {
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication().getResources().getString(R.string.nc_sent_a_link),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_AUDIO_MESSAGE)) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_sent_an_audio_you));
} else {
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication().getResources().getString(R.string.nc_sent_an_audio),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_VIDEO_MESSAGE)) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_sent_a_video_you));
} else {
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication().getResources().getString(R.string.nc_sent_a_video),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_IMAGE_MESSAGE)) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_sent_an_image_you));
} else {
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication().getResources().getString(R.string.nc_sent_an_image),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest)));
}
}
} }
} else if (getMessageType().equals(MessageType.SINGLE_NC_ATTACHMENT_MESSAGE)) {
return ""; if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_sent_an_attachment_you));
} else {
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication()
.getResources()
.getString(R.string.nc_sent_an_attachment),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName()
: NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_MESSAGE)) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_sent_a_link_you));
} else {
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication()
.getResources()
.getString(R.string.nc_sent_a_link),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName()
: NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_AUDIO_MESSAGE)) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_sent_an_audio_you));
} else {
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication()
.getResources()
.getString(R.string.nc_sent_an_audio),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName()
: NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_VIDEO_MESSAGE)) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_sent_a_video_you));
} else {
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication()
.getResources()
.getString(R.string.nc_sent_a_video),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName()
: NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_IMAGE_MESSAGE)) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_sent_an_image_you));
} else {
return (String.format(NextcloudTalkApplication.Companion.getSharedApplication()
.getResources()
.getString(R.string.nc_sent_an_image),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName()
: NextcloudTalkApplication.Companion.getSharedApplication()
.getString(R.string.nc_guest)));
}
}
} }
@Override return "";
public IUser getUser() { }
return new IUser() {
@Override
public String getId() {
return actorId;
}
@Override @Override
public String getName() { public IUser getUser() {
return actorDisplayName; return new IUser() {
} @Override
public String getId() {
return actorId;
}
@Override @Override
public String getAvatar() { public String getName() {
if (getActorType().equals("users")) { return actorDisplayName;
return ApiUtils.getUrlForAvatarWithName(getActiveUser().getBaseUrl(), actorId, R.dimen.avatar_size); }
} else if (getActorType().equals("guests")) {
String apiId =
NextcloudTalkApplication.Companion.getSharedApplication().getString(R.string.nc_guest);
if (!TextUtils.isEmpty(getActorDisplayName())) { @Override
apiId = getActorDisplayName(); public String getAvatar() {
} if (getActorType().equals("users")) {
return ApiUtils.getUrlForAvatarWithNameForGuests(getActiveUser().getBaseUrl(), apiId, R.dimen.avatar_size); return ApiUtils.getUrlForAvatarWithName(getActiveUser().getBaseUrl(), actorId,
} else { R.dimen.avatar_size);
return null; } else if (getActorType().equals("guests")) {
} String apiId =
} NextcloudTalkApplication.Companion.getSharedApplication()
}; .getString(R.string.nc_guest);
}
@Override if (!TextUtils.isEmpty(getActorDisplayName())) {
public Date getCreatedAt() { apiId = getActorDisplayName();
return new Date(timestamp * 1000L); }
} return ApiUtils.getUrlForAvatarWithNameForGuests(getActiveUser().getBaseUrl(), apiId,
R.dimen.avatar_size);
} else {
return null;
}
}
};
}
@Override @Override
public String getSystemMessage() { public Date getCreatedAt() {
return new EnumSystemMessageTypeConverter().convertToString(getSystemMessageType()); return new Date(timestamp * 1000L);
} }
public enum MessageType { @Override
REGULAR_TEXT_MESSAGE, public String getSystemMessage() {
SYSTEM_MESSAGE, return new EnumSystemMessageTypeConverter().convertToString(getSystemMessageType());
SINGLE_LINK_GIPHY_MESSAGE, }
SINGLE_LINK_TENOR_MESSAGE,
SINGLE_LINK_GIF_MESSAGE,
SINGLE_LINK_MESSAGE,
SINGLE_LINK_VIDEO_MESSAGE,
SINGLE_LINK_IMAGE_MESSAGE,
SINGLE_LINK_AUDIO_MESSAGE,
SINGLE_NC_ATTACHMENT_MESSAGE,
}
public enum SystemMessageType { public enum MessageType {
DUMMY, REGULAR_TEXT_MESSAGE,
CONVERSATION_CREATED, SYSTEM_MESSAGE,
CONVERSATION_RENAMED, SINGLE_LINK_GIPHY_MESSAGE,
CALL_STARTED, SINGLE_LINK_TENOR_MESSAGE,
CALL_JOINED, SINGLE_LINK_GIF_MESSAGE,
CALL_LEFT, SINGLE_LINK_MESSAGE,
CALL_ENDED, SINGLE_LINK_VIDEO_MESSAGE,
GUESTS_ALLOWED, SINGLE_LINK_IMAGE_MESSAGE,
GUESTS_DISALLOWED, SINGLE_LINK_AUDIO_MESSAGE,
PASSWORD_SET, SINGLE_NC_ATTACHMENT_MESSAGE,
PASSWORD_REMOVED, }
USER_ADDED,
USER_REMOVED, public enum SystemMessageType {
MODERATOR_PROMOTED, DUMMY,
MODERATOR_DEMOTED, CONVERSATION_CREATED,
FILE_SHARED, CONVERSATION_RENAMED,
LOBBY_NONE, CALL_STARTED,
LOBBY_NON_MODERATORS, CALL_JOINED,
LOBBY_OPEN_TO_EVERYONE CALL_LEFT,
} CALL_ENDED,
GUESTS_ALLOWED,
GUESTS_DISALLOWED,
PASSWORD_SET,
PASSWORD_REMOVED,
USER_ADDED,
USER_REMOVED,
MODERATOR_PROMOTED,
MODERATOR_DEMOTED,
FILE_SHARED,
LOBBY_NONE,
LOBBY_NON_MODERATORS,
LOBBY_OPEN_TO_EVERYONE
}
} }

View File

@ -30,6 +30,6 @@ import org.parceler.Parcel;
@Parcel @Parcel
@JsonObject @JsonObject
public class ChatOCS extends GenericOCS { public class ChatOCS extends GenericOCS {
@JsonField(name = "data") @JsonField(name = "data")
public List<ChatMessage> data; public List<ChatMessage> data;
} }

Some files were not shown because too many files have changed in this diff Show More