Skip to content

Commit

Permalink
Merge branch 'develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
MohamadJaara authored Oct 23, 2024
2 parents d04ae83 + 46d80bb commit b5f27c9
Show file tree
Hide file tree
Showing 20 changed files with 1,324 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,17 @@

package com.wire.android.feature

import android.content.Context
import android.content.Intent
import android.os.Build
import com.wire.android.appLogger
import com.wire.android.services.PersistentWebSocketService
import dagger.hilt.android.qualifiers.ApplicationContext
import com.wire.android.services.ServicesManager
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class StartPersistentWebsocketIfNecessaryUseCase @Inject constructor(
@ApplicationContext private val appContext: Context,
private val servicesManager: ServicesManager,
private val shouldStartPersistentWebSocketService: ShouldStartPersistentWebSocketServiceUseCase
) {
suspend operator fun invoke() {
val persistentWebSocketServiceIntent = PersistentWebSocketService.newIntent(appContext)
shouldStartPersistentWebSocketService().let {
when (it) {
is ShouldStartPersistentWebSocketServiceUseCase.Result.Failure -> {
Expand All @@ -43,33 +38,17 @@ class StartPersistentWebsocketIfNecessaryUseCase @Inject constructor(

is ShouldStartPersistentWebSocketServiceUseCase.Result.Success -> {
if (it.shouldStartPersistentWebSocketService) {
startForegroundService(persistentWebSocketServiceIntent)
appLogger.i("${TAG}: Starting PersistentWebsocketService")
servicesManager.startPersistentWebSocketService()
} else {
appLogger.i("${TAG}: Stopping PersistentWebsocketService, no user with persistent web socket enabled found")
appContext.stopService(persistentWebSocketServiceIntent)
servicesManager.stopPersistentWebSocketService()
}
}
}
}
}

private fun startForegroundService(persistentWebSocketServiceIntent: Intent) {
when {
PersistentWebSocketService.isServiceStarted -> {
appLogger.i("${TAG}: PersistentWebsocketService already started, not starting again")
}

else -> {
appLogger.i("${TAG}: Starting PersistentWebsocketService")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
appContext.startForegroundService(persistentWebSocketServiceIntent)
} else {
appContext.startService(persistentWebSocketServiceIntent)
}
}
}
}

companion object {
const val TAG = "StartPersistentWebsocketIfNecessaryUseCase"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ object ReportBugDestination : IntentDirection {
val dir = LogFileWriter.logsDirectory(context)
val logsUris = context.getUrisOfFilesInDirectory(dir)
val intent = context.multipleFileSharingIntent(logsUris)
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("[email protected]"))
intent.putExtra(Intent.EXTRA_SUBJECT, "Bug Report - Wire Beta")
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf(context.getString(R.string.send_bug_report_email)))
intent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.send_bug_report_subject))
intent.putExtra(
Intent.EXTRA_TEXT,
EmailComposer.reportBugEmailTemplate(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.navigation

import com.ramcosta.composedestinations.spec.Direction
import com.wire.android.ui.destinations.TeamMigrationConfirmationStepScreenDestination
import com.wire.android.ui.destinations.TeamMigrationDoneStepScreenDestination

sealed class TeamMigrationDestination(
val direction: Direction
) {

data object Confirmation : TeamMigrationDestination(
direction = TeamMigrationConfirmationStepScreenDestination
)

data object MigrationDone : TeamMigrationDestination(
direction = TeamMigrationDoneStepScreenDestination
)

val itemName: String get() = ITEM_NAME_PREFIX + this

companion object {
private const val ITEM_NAME_PREFIX = "TeamMigrationNavigationItem."
fun fromRoute(fullRoute: String): TeamMigrationDestination? =
values().find { it.direction.route.getBaseRoute() == fullRoute.getBaseRoute() }

fun values(): Array<TeamMigrationDestination> =
arrayOf(Confirmation, MigrationDone)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@

package com.wire.android.services

import android.app.ForegroundServiceStartNotAllowedException
import android.app.Notification
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
Expand Down Expand Up @@ -131,12 +133,29 @@ class PersistentWebSocketService : Service() {
.setOngoing(true)
.build()

ServiceCompat.startForeground(
this,
NotificationIds.PERSISTENT_NOTIFICATION_ID.ordinal,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
try {
ServiceCompat.startForeground(
this,
NotificationIds.PERSISTENT_NOTIFICATION_ID.ordinal,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
} catch (e: ForegroundServiceStartNotAllowedException) {
// ForegroundServiceStartNotAllowedException may be thrown on restarting service from the background.
// this is the only suggested workaround from google for now.
// https://issuetracker.google.com/issues/307329994#comment86
appLogger.e("Failure while starting foreground: $e")
stopSelf()
}
} else {
ServiceCompat.startForeground(
this,
NotificationIds.PERSISTENT_NOTIFICATION_ID.ordinal,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
}
}

override fun onDestroy() {
Expand Down
15 changes: 9 additions & 6 deletions app/src/main/kotlin/com/wire/android/services/ServicesManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

package com.wire.android.services

import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
Expand All @@ -34,7 +33,6 @@ import kotlinx.coroutines.launch
import org.jetbrains.annotations.VisibleForTesting
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.reflect.KClass

/**
* This is helper class that should be used for starting/stopping any services.
Expand Down Expand Up @@ -102,11 +100,15 @@ class ServicesManager @Inject constructor(

// Persistent WebSocket
fun startPersistentWebSocketService() {
startService(PersistentWebSocketService.newIntent(context))
if (PersistentWebSocketService.isServiceStarted) {
appLogger.i("ServicesManager: PersistentWebsocketService already started, not starting again")
} else {
startService(PersistentWebSocketService.newIntent(context))
}
}

fun stopPersistentWebSocketService() {
stopService(PersistentWebSocketService::class)
stopService(PersistentWebSocketService.newIntent(context))
}

fun isPersistentWebSocketServiceRunning(): Boolean =
Expand All @@ -121,8 +123,9 @@ class ServicesManager @Inject constructor(
}
}

private fun stopService(serviceClass: KClass<out Service>) {
context.stopService(Intent(context, serviceClass.java))
private fun stopService(intent: Intent) {
appLogger.i("ServicesManager: stopping service for $intent")
context.stopService(intent)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import com.wire.android.ui.common.visbility.rememberVisibilityState
import com.wire.android.ui.destinations.AppSettingsScreenDestination
import com.wire.android.ui.destinations.AvatarPickerScreenDestination
import com.wire.android.ui.destinations.SelfQRCodeScreenDestination
import com.wire.android.ui.destinations.TeamMigrationScreenDestination
import com.wire.android.ui.destinations.WelcomeScreenDestination
import com.wire.android.ui.home.conversations.search.HighlightName
import com.wire.android.ui.home.conversations.search.HighlightSubtitle
Expand Down Expand Up @@ -137,7 +138,7 @@ fun SelfUserProfileScreen(
navigator.navigate(NavigationCommand(SelfQRCodeScreenDestination(viewModelSelf.userProfileState.userName)))
},
onCreateAccount = {
// TODO: open screen to create a team
navigator.navigate(NavigationCommand(TeamMigrationScreenDestination))
},
isUserInCall = viewModelSelf::isUserInCall,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.userprofile.teammigration

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.isImeVisible
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.wire.android.R
import com.wire.android.ui.common.button.WireButtonState
import com.wire.android.ui.common.button.WirePrimaryButton
import com.wire.android.ui.common.button.WireSecondaryButton
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.preview.MultipleThemePreviews
import com.wire.android.ui.theme.WireTheme

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun BottomLineButtons(
isContinueButtonEnabled: Boolean,
modifier: Modifier = Modifier,
isBackButtonVisible: Boolean = true,
onBack: () -> Unit = { },
onContinue: () -> Unit = { }
) {
Column(
modifier = modifier
.padding(
top = dimensions().spacing16x,
start = dimensions().spacing16x,
end = dimensions().spacing16x,
bottom = if (!WindowInsets.isImeVisible) {
dimensions().spacing32x
} else {
dimensions().spacing16x
}
)
.imePadding()
) {
if (isBackButtonVisible) {
WireSecondaryButton(
modifier = Modifier.fillMaxWidth(),
text = stringResource(R.string.personal_to_team_migration_back_button_label),
onClick = onBack
)
}

WirePrimaryButton(
modifier = Modifier
.fillMaxWidth()
.padding(top = dimensions().spacing6x),
text = stringResource(R.string.label_continue),
onClick = onContinue,
state = if (isContinueButtonEnabled) {
WireButtonState.Default
} else {
WireButtonState.Disabled
}
)
}
}

@MultipleThemePreviews
@Composable
private fun BottomLineButtonsPreview() {
WireTheme {
BottomLineButtons(
isContinueButtonEnabled = true
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android.ui.userprofile.teammigration

import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextIndent
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.sp
import com.wire.android.ui.common.colorsScheme
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.ui.PreviewMultipleThemes

@Composable
fun BulletList(messages: List<String>, modifier: Modifier = Modifier) {
val bullet = "\u2022"
val paragraphStyle = ParagraphStyle(textIndent = TextIndent(restLine = 12.sp))
Text(
modifier = modifier,
text = buildAnnotatedString {
messages.forEach {
withStyle(style = paragraphStyle) {
append(bullet)
append("\t\t")
append(it)
}
}
},
style = MaterialTheme.wireTypography.body01,
color = colorsScheme().onBackground
)
}

@PreviewMultipleThemes
@Composable
private fun BulletListPreview() {
WireTheme {
BulletList(
messages = listOf(
"Item 1",
"Item 2",
"Item 3"
)
)
}
}
Loading

0 comments on commit b5f27c9

Please sign in to comment.