Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06824cd7 authored by Guillaume Jacquart's avatar Guillaume Jacquart
Browse files

Merge branch '3189-subscribe_eos_lang_topic' into 'main'

feat:3185,3186,3189: register to eOS Broadcast topics on device config changes

See merge request !19
parents d06083f0 d26f3e8b
Loading
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
/*
 *  Copyright (c) 2025 E FOUNDATION
 *
 *   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 <https://www.gnu.org/licenses/>.
 */

package foundation.e.notificationsreceiver

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import foundation.e.notificationsreceiver.domain.utils.AppBackgroundScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import javax.inject.Singleton

@InstallIn(SingletonComponent::class)
@Module
object NotificationsReceiverModule {

    @Singleton
    @AppBackgroundScope
    @Provides
    fun providesAppBackgroundScope(): CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
}
+31 −0
Original line number Diff line number Diff line
/*
 *  Copyright (c) 2025 E FOUNDATION
 *
 *   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 <https://www.gnu.org/licenses/>.
 */

package foundation.e.notificationsreceiver.repositories

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import foundation.e.notificationsreceiver.domain.repositories.SubscriptionsRepository

@InstallIn(SingletonComponent::class)
@Module
abstract class RepositoryModule {
    @Binds
    abstract fun bindSubscriptionsRepository(impl: SubscriptionsRepositoryImpl): SubscriptionsRepository
}
+106 −0
Original line number Diff line number Diff line
/*
 *  Copyright (c) 2025 E FOUNDATION
 *
 *   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 <https://www.gnu.org/licenses/>.
 */
package foundation.e.notificationsreceiver.repositories

import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import foundation.e.notificationsreceiver.domain.entities.Topic
import foundation.e.notificationsreceiver.domain.repositories.SubscriptionsRepository
import foundation.e.notificationsreceiver.domain.utils.AppBackgroundScope
import io.heckel.ntfy.R
import io.heckel.ntfy.db.Database
import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.Subscription
import io.heckel.ntfy.db.SubscriptionDao
import io.heckel.ntfy.service.SubscriberServiceManager
import io.heckel.ntfy.util.randomSubscriptionId
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.Date
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class SubscriptionsRepositoryImpl @Inject constructor(
    @ApplicationContext private val appContext: Context,
    @AppBackgroundScope private val backgroundScope: CoroutineScope,
) : SubscriptionsRepository {
    companion object {
        private const val REFRESH_SUBSCRIPTION_DEBOUNCE_PERIOD_MS = 500L
    }

    private val subscriptionDao: SubscriptionDao
    private val repository: Repository
    init {
        val database = Database.getInstance(appContext)
        subscriptionDao = database.subscriptionDao()
        repository = Repository.getInstance(appContext)
    }

    private var willRefreshSubscriptionJob: Job? = null

    override fun getBaseUrl(): String {
        return repository.getDefaultBaseUrl() ?: appContext.getString(R.string.app_base_url)
    }

    override suspend fun getSubscriptions(): List<Topic> = withContext(Dispatchers.IO) {
        subscriptionDao.list().map { Topic(localId = it.id, baseUrl = it.baseUrl, topic = it.topic) }
    }

    override suspend fun subscribe(topic: Topic) = withContext(Dispatchers.IO) {
        val subscription = Subscription(
            id = randomSubscriptionId(),
            baseUrl = topic.baseUrl,
            topic = topic.topic,
            instant = true,
            dedicatedChannels = false,
            mutedUntil = 0,
            minPriority = Repository.MIN_PRIORITY_USE_GLOBAL,
            autoDelete = Repository.AUTO_DELETE_USE_GLOBAL,
            insistent = Repository.INSISTENT_MAX_PRIORITY_USE_GLOBAL,
            lastNotificationId = null,
            icon = null,
            upAppId = null,
            upConnectorToken = null,
            displayName = null,
            totalCount = 0,
            newCount = 0,
            lastActive = Date().time / 1000,
        )

        subscriptionDao.add(subscription)
        debouncedRefreshSubscriptions()
    }

    override suspend fun unsubscribe(topic: Topic): Unit = withContext(Dispatchers.IO) {
        subscriptionDao.remove(topic.localId)
        debouncedRefreshSubscriptions()
    }

    private fun debouncedRefreshSubscriptions() {
        willRefreshSubscriptionJob?.cancel()

        willRefreshSubscriptionJob = backgroundScope.launch {
            delay(REFRESH_SUBSCRIPTION_DEBOUNCE_PERIOD_MS)
            SubscriberServiceManager.refresh(appContext)
        }
    }
}
+25 −0
Original line number Diff line number Diff line
/*
 *  Copyright (c) 2025 E FOUNDATION
 *
 *   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 <https://www.gnu.org/licenses/>.
 */

package foundation.e.notificationsreceiver.domain.bridges.androidinterfaces

interface DeviceConfiguration {
    val version: String?
    val device: String
    val androidVersion: String
    suspend fun getLang(): String
}
+24 −0
Original line number Diff line number Diff line
/*
 *  Copyright (c) 2025 E FOUNDATION
 *
 *   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 <https://www.gnu.org/licenses/>.
 */

package foundation.e.notificationsreceiver.domain.entities

data class Topic(
    val localId: Long = -1,
    val baseUrl: String,
    val topic: String,
)
Loading