diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 11dff78046526a3564ab59d66b6456baf7d1d02e..fa10b50859672779aaf7a82b165c24e6a7c2ba50 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,32 +11,28 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" - android:theme="@style/AppTheme"> + android:theme="@style/Theme.SplashTheme"> <activity android:name=".ui.ChatActivity" android:exported="false" android:label="@string/app_name" - android:theme="@style/SplashTheme" android:windowSoftInputMode="adjustResize" /> <activity android:name=".ui.setup.accounts.AccountSetupActivity" android:exported="false" android:label="@string/app_name" android:parentActivityName=".ui.setup.accounts.AccountSelectionActivity" - android:theme="@style/SplashTheme" android:windowSoftInputMode="adjustResize" /> <activity android:name=".ui.setup.accounts.AccountEditActivity" android:exported="false" android:label="@string/app_name" android:parentActivityName=".ui.setup.accounts.AccountSelectionActivity" - android:theme="@style/SplashTheme" android:windowSoftInputMode="adjustResize" /> <activity android:name=".ui.setup.accounts.AccountSelectionActivity" android:exported="true" android:label="@string/app_name" - android:theme="@style/SplashTheme" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/PersistentSession.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/PersistentSession.kt new file mode 100644 index 0000000000000000000000000000000000000000..24b824652111f5ee489c2f96f144c8338902a209 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/PersistentSession.kt @@ -0,0 +1,26 @@ +package de.kuschku.quasseldroid_ng.persistence + +import de.kuschku.libquassel.protocol.IdentityId +import de.kuschku.libquassel.protocol.NetworkId +import de.kuschku.libquassel.quassel.syncables.* +import de.kuschku.libquassel.session.ConnectionState +import de.kuschku.libquassel.session.ISession +import io.reactivex.subjects.BehaviorSubject + +class PersistentSession : ISession { + override val aliasManager: AliasManager? = null + override val backlogManager: BacklogManager? = null + override val bufferSyncer: BufferSyncer? = null + override val bufferViewManager: BufferViewManager? = null + override val certManagers: Map<IdentityId, CertManager> = emptyMap() + override val coreInfo: CoreInfo? = null + override val dccConfig: DccConfig? = null + override val identities: Map<IdentityId, Identity> = emptyMap() + override val ignoreListManager: IgnoreListManager? = null + override val ircListHelper: IrcListHelper? = null + override val networks: Map<NetworkId, Network> = emptyMap() + override val networkConfig: NetworkConfig? = null + + override fun close() = Unit + override val state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED) +} diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt index f4463a670556b4b9329208a60d31ee927daf4925..3b07cd915b0a97fdbfe75d2b862b79395c1f62ce 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt @@ -57,6 +57,12 @@ abstract class QuasselDatabase : RoomDatabase() { var networkName: String ) + @Entity + class BufferViewConfig( + @PrimaryKey var id: Int, + var name: String + ) + @Dao interface NetworkDao { @Insert(onConflict = OnConflictStrategy.REPLACE) diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt index ed212b2e0580fc1fa608954cdd0264e6b6619bad..a1b4123ec452ddb8e8e6c225071ecb60a5c8d54c 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt @@ -7,11 +7,11 @@ import android.os.Handler import android.os.HandlerThread import de.kuschku.libquassel.protocol.* import de.kuschku.libquassel.session.Backend -import de.kuschku.libquassel.session.ISession import de.kuschku.libquassel.session.SessionManager import de.kuschku.libquassel.session.SocketAddress import de.kuschku.quasseldroid_ng.BuildConfig import de.kuschku.quasseldroid_ng.R +import de.kuschku.quasseldroid_ng.persistence.PersistentSession import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase import de.kuschku.quasseldroid_ng.util.compatibility.AndroidHandlerService import org.threeten.bp.Instant @@ -78,7 +78,7 @@ class QuasselService : LifecycleService() { handler = Handler(thread.looper) super.onCreate() database = QuasselDatabase.Creator.init(application) - sessionManager = SessionManager(ISession.NULL) + sessionManager = SessionManager(PersistentSession()) clientData = ClientData( identifier = "${resources.getString(R.string.app_name)} ${BuildConfig.VERSION_NAME}", buildDate = Instant.ofEpochSecond(BuildConfig.GIT_COMMIT_DATE), diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatActivity.kt index 1bc376a8f4d7ff6a814740f48f0cc271a82b2dd3..e9bf43aaed72769a5f83cddfe2aab6dbdcd67975 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatActivity.kt @@ -1,14 +1,13 @@ package de.kuschku.quasseldroid_ng.ui import android.app.Activity -import android.arch.lifecycle.LiveDataReactiveStreams import android.arch.lifecycle.Observer import android.content.Context -import android.content.Intent import android.os.Bundle import android.os.Handler import android.os.HandlerThread import android.support.design.widget.Snackbar +import android.support.v7.widget.Toolbar import android.util.Log import android.view.Menu import android.view.MenuItem @@ -16,17 +15,16 @@ import android.widget.Button import android.widget.TextView import butterknife.BindView import butterknife.ButterKnife -import de.kuschku.libquassel.session.Backend -import de.kuschku.libquassel.session.ConnectionState -import de.kuschku.libquassel.session.SocketAddress +import de.kuschku.libquassel.session.* import de.kuschku.libquassel.util.compatibility.LoggingHandler +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.ERROR +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO +import de.kuschku.libquassel.util.compatibility.log import de.kuschku.quasseldroid_ng.Keys import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.persistence.AccountDatabase -import de.kuschku.quasseldroid_ng.service.QuasselService -import de.kuschku.quasseldroid_ng.util.helper.editApply -import de.kuschku.quasseldroid_ng.util.helper.stickyMapNotNull -import de.kuschku.quasseldroid_ng.util.helper.stickySwitchMapNotNull +import de.kuschku.quasseldroid_ng.util.helper.* +import de.kuschku.quasseldroid_ng.util.service.ServiceBoundActivity import org.threeten.bp.ZoneOffset import org.threeten.bp.ZonedDateTime import org.threeten.bp.format.DateTimeFormatter @@ -44,19 +42,35 @@ class ChatActivity : ServiceBoundActivity() { @BindView(R.id.errorList) lateinit var errorList: TextView + @BindView(R.id.toolbar) + lateinit var toolbar: Toolbar + private val thread = HandlerThread("Chat") private lateinit var handler: Handler - private val state = backend.stickyMapNotNull(null, Backend::sessionManager) - .stickySwitchMapNotNull(ConnectionState.DISCONNECTED) { session -> - LiveDataReactiveStreams.fromPublisher(session.state) + private val sessionManager = backend.map(Backend::sessionManager) + private val state + = sessionManager.switchMapRx(SessionManager::state) + + private val bufferViewManager + = sessionManager.switchMapRx(SessionManager::session).map(ISession::bufferViewManager) + private val bufferViewConfigs = bufferViewManager.switchMapRx { manager -> + manager.bufferViewConfigIds.map { ids -> + ids.map { id -> + manager.bufferViewConfig(id) + }.sortedBy { it?.bufferViewName() } } + } - private var snackbar: Snackbar? = null + private + var snackbar: Snackbar? = null - private val dateTimeFormatter: DateTimeFormatter = DateTimeFormatter.ISO_TIME - private val logHandler = object : LoggingHandler() { - override fun log(logLevel: LogLevel, tag: String, message: String?, throwable: Throwable?) { + private + val dateTimeFormatter: DateTimeFormatter = DateTimeFormatter.ISO_TIME + private + val logHandler = object : LoggingHandler() { + override fun log(logLevel: LogLevel, tag: String, message: String?, + throwable: Throwable?) { val time = dateTimeFormatter.format(ZonedDateTime.now(ZoneOffset.UTC)) runOnUiThread { errorList.append("$time $tag: ") @@ -72,7 +86,7 @@ class ChatActivity : ServiceBoundActivity() { } override fun isLoggable(logLevel: LogLevel, tag: String) - = (logLevel.ordinal >= LogLevel.INFO.ordinal) + = (logLevel.ordinal >= INFO.ordinal) } override fun onRestoreInstanceState(savedInstanceState: Bundle?) { @@ -86,15 +100,15 @@ class ChatActivity : ServiceBoundActivity() { } var account: AccountDatabase.Account? = null + override fun onCreate(savedInstanceState: Bundle?) { thread.start() handler = Handler(thread.looper) - startService(Intent(this, QuasselService::class.java)) - setTheme(R.style.AppTheme) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) ButterKnife.bind(this) + setSupportActionBar(toolbar) val database = AccountDatabase.Creator.init(this) handler.post { @@ -130,7 +144,7 @@ class ChatActivity : ServiceBoundActivity() { errorList.text = "" } - state.observe(this, Observer { + state.observeSticky(this, Observer { val status = it ?: ConnectionState.DISCONNECTED val disconnected = status == ConnectionState.DISCONNECTED @@ -141,6 +155,13 @@ class ChatActivity : ServiceBoundActivity() { snackbar = Snackbar.make(errorList, status.name, Snackbar.LENGTH_SHORT) snackbar?.show() }) + + bufferViewManager.observeSticky(this, Observer { + log(ERROR, "bufferViewManager", it.toString()) + }) + bufferViewConfigs.or(emptyList()).observeSticky(this, Observer { + log(ERROR, "bufferViewConfigs", it.toString()) + }) } override fun onCreateOptionsMenu(menu: Menu?): Boolean { diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt index 8991a7e38d2e94b792077b2437482dadc1367b3e..0493f46823c5f41b046b18c12ed26bfe833c7ce0 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt @@ -14,7 +14,9 @@ import android.view.ViewGroup import butterknife.BindView import butterknife.ButterKnife import de.kuschku.quasseldroid_ng.R -import de.kuschku.quasseldroid_ng.util.helper.stickySwitchMapNotNull +import de.kuschku.quasseldroid_ng.util.helper.observeSticky +import de.kuschku.quasseldroid_ng.util.helper.or +import de.kuschku.quasseldroid_ng.util.helper.switchMap abstract class SetupActivity : AppCompatActivity() { @BindView(R.id.view_pager) @@ -28,7 +30,7 @@ abstract class SetupActivity : AppCompatActivity() { protected abstract val fragments: List<SlideFragment> private val currentPage = MutableLiveData<SlideFragment?>() - private val isValid = currentPage.stickySwitchMapNotNull(false, SlideFragment::valid) + private val isValid = currentPage.switchMap(SlideFragment::valid).or(false) private val pageChangeListener = object : ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) { @@ -53,7 +55,7 @@ abstract class SetupActivity : AppCompatActivity() { } override fun onCreate(savedInstanceState: Bundle?) { - setTheme(R.style.SetupTheme) + setTheme(R.style.Theme_SetupTheme) super.onCreate(savedInstanceState) setContentView(R.layout.activity_setup) ButterKnife.bind(this) @@ -68,7 +70,7 @@ abstract class SetupActivity : AppCompatActivity() { else viewPager.setCurrentItem(viewPager.currentItem + 1, true) } - isValid.observe(this, Observer { + isValid.observeSticky(this, Observer { if (it == true) { button.show() adapter.lastValidItem = viewPager.currentItem diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt index d6500de7580ee08c7e76fa3cf98e01c018bcf756..ba542dabb28e7fb112e95459a0ba371aef5e8cc0 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt @@ -58,7 +58,7 @@ class AccountEditActivity : AppCompatActivity() { thread.start() handler = Handler(thread.looper) - setTheme(R.style.AppTheme) + setTheme(R.style.Theme_AppTheme_Light) super.onCreate(savedInstanceState) setContentView(R.layout.setup_account_edit) ButterKnife.bind(this) diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..aa95e41c5574f92ecadbbc85957ac5600a1b66da --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt @@ -0,0 +1,117 @@ +package de.kuschku.quasseldroid_ng.util.helper + +import android.arch.lifecycle.* +import android.support.annotation.MainThread +import de.kuschku.libquassel.util.helpers.toLiveData +import io.reactivex.BackpressureStrategy +import io.reactivex.Observable + +@MainThread +inline fun <X, Y> LiveData<X?>.switchMap( + noinline func: (X) -> LiveData<Y>? +): LiveData<Y> { + val result = MediatorLiveData<Y>() + result.addSource(this, object : Observer<X?> { + internal var mSource: LiveData<Y>? = null + + override fun onChanged(x: X?) { + val newLiveData = if (x == null) null else func(x) + if (mSource === newLiveData) { + return + } + if (mSource != null) { + result.removeSource(mSource) + } + mSource = newLiveData + if (mSource != null) { + result.addSource(mSource) { y -> result.value = y } + } else { + result.value = null + } + } + }) + return result +} + +@MainThread +inline fun <X, Y> LiveData<X?>.switchMapRx( + strategy: BackpressureStrategy, + noinline func: (X) -> Observable<Y>? +): LiveData<Y> { + val result = MediatorLiveData<Y>() + result.addSource(this, object : Observer<X?> { + internal var mSource: LiveData<Y>? = null + + override fun onChanged(x: X?) { + val newLiveData = if (x == null) null else func(x)?.toLiveData(strategy) + if (mSource === newLiveData) { + return + } + if (mSource != null) { + result.removeSource(mSource) + } + mSource = newLiveData + if (mSource != null) { + result.addSource(mSource) { y -> result.value = y } + } else { + result.value = null + } + } + }) + return result +} + +@MainThread +inline fun <X, Y> LiveData<X?>.switchMapRx( + noinline func: (X) -> Observable<Y>? +): LiveData<Y> = switchMapRx(BackpressureStrategy.LATEST, func) + +@MainThread +inline fun <X, Y> LiveData<X?>.map( + noinline func: (X) -> Y? +): LiveData<Y?> { + val result = MediatorLiveData<Y?>() + result.addSource(this) { x -> + result.value = if (x == null) null else func.invoke(x) + } + return result +} + +@MainThread +inline fun <X> LiveData<X>.orElse( + noinline func: () -> X +): LiveData<X> { + val result = object : MediatorLiveData<X>() { + override fun getValue() = super.getValue() ?: func() + } + result.addSource(this) { x -> + result.value = x ?: func() + } + return result +} + +@MainThread +inline fun <X> LiveData<X>.or( + default: X +): LiveData<X> { + val result = object : MediatorLiveData<X>() { + override fun getValue() = super.getValue() ?: default + } + result.addSource(this) { x -> + result.value = x ?: default + } + return result +} + +inline fun <T> LiveData<T>.observeSticky(lifecycleOwner: LifecycleOwner, observer: Observer<T>) { + observe(lifecycleOwner, observer) + observer.onChanged(value) +} + +inline fun <T> LiveData<T>.observeForeverSticky(observer: Observer<T>) { + observeForever(observer) + observer.onChanged(value) +} + +inline fun <T> LiveData<T>.toObservable(lifecycleOwner: LifecycleOwner) + = Observable.fromPublisher(LiveDataReactiveStreams.toPublisher(lifecycleOwner, this)) diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ObservableHelper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ObservableHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..3bb0e08be8350411c415cd24981f8b4919156e84 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ObservableHelper.kt @@ -0,0 +1,9 @@ +package de.kuschku.libquassel.util.helpers + +import android.arch.lifecycle.LiveDataReactiveStreams +import io.reactivex.BackpressureStrategy +import io.reactivex.Observable + +inline fun <T> Observable<T>.toLiveData( + strategy: BackpressureStrategy = BackpressureStrategy.LATEST) + = LiveDataReactiveStreams.fromPublisher(toFlowable(strategy)) diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/TransformationsHelper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/TransformationsHelper.kt deleted file mode 100644 index ad934b62b48aba3ff1f55b02317fa5b1ade9161f..0000000000000000000000000000000000000000 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/TransformationsHelper.kt +++ /dev/null @@ -1,95 +0,0 @@ -package de.kuschku.quasseldroid_ng.util.helper - -import android.arch.lifecycle.LifecycleOwner -import android.arch.lifecycle.LiveData -import android.arch.lifecycle.MediatorLiveData -import android.arch.lifecycle.Observer -import android.support.annotation.MainThread - -@MainThread -fun <X, Y> LiveData<X?>.stickySwitchMapNotNull( - defaultValue: Y, - func: (X) -> LiveData<Y>? -): LiveData<Y> { - val result = object : MediatorLiveData<Y>() { - override fun observe(owner: LifecycleOwner?, observer: Observer<Y>?) { - super.observe(owner, observer) - observer?.onChanged(value ?: defaultValue) - } - - override fun observeForever(observer: Observer<Y>?) { - super.observeForever(observer) - observer?.onChanged(value ?: defaultValue) - } - } - result.addSource(this, object : Observer<X?> { - internal var mSource: LiveData<Y>? = null - - override fun onChanged(x: X?) { - val newLiveData = if (x != null) func(x) else null - if (mSource === newLiveData) { - return - } - if (mSource != null) { - result.removeSource(mSource) - } - mSource = newLiveData - if (mSource != null) { - result.addSource(mSource) { y -> result.value = y ?: defaultValue } - } else { - result.value = defaultValue - } - } - }) - return result -} - -@MainThread -fun <X, Y> LiveData<X?>.switchMapNullable( - defaultValue: Y, - func: (X) -> LiveData<Y>? -): LiveData<Y> { - val result = MediatorLiveData<Y>() - result.addSource(this, object : Observer<X?> { - internal var mSource: LiveData<Y>? = null - - override fun onChanged(x: X?) { - val newLiveData = if (x != null) func(x) else null - if (mSource === newLiveData) { - return - } - if (mSource != null) { - result.removeSource(mSource) - } - mSource = newLiveData - if (mSource != null) { - result.addSource(mSource) { y -> result.value = y ?: defaultValue } - } else { - result.value = defaultValue - } - } - }) - return result -} - -@MainThread -fun <X, Y> LiveData<X?>.stickyMapNotNull( - defaultValue: Y, - func: (X) -> Y? -): LiveData<Y> { - val result = object : MediatorLiveData<Y>() { - override fun observe(owner: LifecycleOwner?, observer: Observer<Y>?) { - super.observe(owner, observer) - observer?.onChanged(value ?: defaultValue) - } - - override fun observeForever(observer: Observer<Y>?) { - super.observeForever(observer) - observer?.onChanged(value ?: defaultValue) - } - } - result.addSource(this) { x -> - result.setValue(if (x == null) defaultValue else func(x) ?: defaultValue) - } - return result -} diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ServiceBoundActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt similarity index 79% rename from app/src/main/java/de/kuschku/quasseldroid_ng/ui/ServiceBoundActivity.kt rename to app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt index e46c5ad4998e35d6f818b25e935335516de908ad..b7a6d0b4ef9148ed7883dd6bc7c507accde99916 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ServiceBoundActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt @@ -1,12 +1,14 @@ -package de.kuschku.quasseldroid_ng.ui +package de.kuschku.quasseldroid_ng.util.service import android.arch.lifecycle.MutableLiveData import android.content.ComponentName import android.content.Intent import android.content.ServiceConnection +import android.os.Bundle import android.os.IBinder import android.support.v7.app.AppCompatActivity import de.kuschku.libquassel.session.Backend +import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.service.QuasselService abstract class ServiceBoundActivity : AppCompatActivity() { @@ -31,6 +33,12 @@ abstract class ServiceBoundActivity : AppCompatActivity() { } } + override fun onCreate(savedInstanceState: Bundle?) { + setTheme(R.style.Theme_ChatTheme_Quassel_Light) + super.onCreate(savedInstanceState) + startService(Intent(this, QuasselService::class.java)) + } + override fun onStart() { bindService(Intent(this, QuasselService::class.java), connection, 0) super.onStart() diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/DrawerRecyclerView.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/DrawerRecyclerView.kt new file mode 100644 index 0000000000000000000000000000000000000000..105cbb0e5c83eb842b264c4700556bb527d04e05 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/DrawerRecyclerView.kt @@ -0,0 +1,104 @@ +package de.kuschku.quasseldroid_ng.util.ui + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Rect +import android.graphics.drawable.Drawable +import android.support.v4.view.ViewCompat +import android.support.v4.view.WindowInsetsCompat +import android.support.v7.widget.RecyclerView +import android.util.AttributeSet +import de.kuschku.quasseldroid_ng.R + +class DrawerRecyclerView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : RecyclerView(context, attrs, defStyleAttr) { + private var mInsetForeground: Drawable? = null + private var mInsets: Rect? = null + private val mTempRect = Rect() + private val maxWidth: Int + + init { + val a = context.obtainStyledAttributes(attrs, + R.styleable.ScrimInsetsFrameLayout, defStyleAttr, + R.style.Widget_Design_ScrimInsetsFrameLayout) + mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsFrameLayout_insetForeground) + a.recycle() + setWillNotDraw(true) // No need to draw until the insets are adjusted + ViewCompat.setOnApplyWindowInsetsListener(this + ) { v, insets -> + if (null == mInsets) { + mInsets = Rect() + } + mInsets!!.set(insets.systemWindowInsetLeft, + insets.systemWindowInsetTop, + insets.systemWindowInsetRight, + insets.systemWindowInsetBottom) + setPadding(insets.systemWindowInsetLeft, + insets.systemWindowInsetTop, + insets.systemWindowInsetRight, + insets.systemWindowInsetBottom) + onInsetsChanged(insets) + setWillNotDraw(!insets.hasSystemWindowInsets() || mInsetForeground == null) + ViewCompat.postInvalidateOnAnimation(this@DrawerRecyclerView) + insets.consumeSystemWindowInsets() + } + + maxWidth = context.resources.getDimensionPixelSize(R.dimen.navigation_drawer_max_width) + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure( + MeasureSpec.makeMeasureSpec( + Math.min(MeasureSpec.getSize(widthMeasureSpec), maxWidth), + MeasureSpec.getMode(widthMeasureSpec) + ), + heightMeasureSpec + ) + } + + override fun draw(canvas: Canvas) { + super.draw(canvas) + val width = width + val height = height + if (mInsets != null && mInsetForeground != null) { + val sc = canvas.save() + canvas.translate(scrollX.toFloat(), scrollY.toFloat()) + // Top + mTempRect.set(0, 0, width, mInsets!!.top) + mInsetForeground!!.bounds = mTempRect + mInsetForeground!!.draw(canvas) + // Bottom + mTempRect.set(0, height - mInsets!!.bottom, width, height) + mInsetForeground!!.bounds = mTempRect + mInsetForeground!!.draw(canvas) + // Left + mTempRect.set(0, mInsets!!.top, mInsets!!.left, height - mInsets!!.bottom) + mInsetForeground!!.bounds = mTempRect + mInsetForeground!!.draw(canvas) + // Right + mTempRect.set(width - mInsets!!.right, mInsets!!.top, width, height - mInsets!!.bottom) + mInsetForeground!!.bounds = mTempRect + mInsetForeground!!.draw(canvas) + canvas.restoreToCount(sc) + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + if (mInsetForeground != null) { + mInsetForeground!!.callback = this + } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + if (mInsetForeground != null) { + mInsetForeground!!.callback = null + } + } + + protected open fun onInsetsChanged(insets: WindowInsetsCompat) {} +} diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/NavigationDrawerLayout.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/NavigationDrawerLayout.kt new file mode 100644 index 0000000000000000000000000000000000000000..2371bc628527f494a9543562d770891b25a67844 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ui/NavigationDrawerLayout.kt @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.kuschku.quasseldroid_ng.util.ui + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Rect +import android.graphics.drawable.Drawable +import android.support.v4.view.ViewCompat +import android.support.v4.view.WindowInsetsCompat +import android.util.AttributeSet +import android.widget.FrameLayout +import de.kuschku.quasseldroid_ng.R + +class NavigationDrawerLayout @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + private var mInsetForeground: Drawable? = null + private var mInsets: Rect? = null + private val mTempRect = Rect() + private val maxWidth: Int + + init { + val a = context.obtainStyledAttributes(attrs, + R.styleable.ScrimInsetsFrameLayout, defStyleAttr, + R.style.Widget_Design_ScrimInsetsFrameLayout) + mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsFrameLayout_insetForeground) + a.recycle() + setWillNotDraw(true) // No need to draw until the insets are adjusted + ViewCompat.setOnApplyWindowInsetsListener(this + ) { v, insets -> + if (null == mInsets) { + mInsets = Rect() + } + mInsets!!.set(insets.systemWindowInsetLeft, + insets.systemWindowInsetTop, + insets.systemWindowInsetRight, + insets.systemWindowInsetBottom) + setPadding(insets.systemWindowInsetLeft, + insets.systemWindowInsetTop, + insets.systemWindowInsetRight, + insets.systemWindowInsetBottom) + onInsetsChanged(insets) + setWillNotDraw(!insets.hasSystemWindowInsets() || mInsetForeground == null) + ViewCompat.postInvalidateOnAnimation(this@NavigationDrawerLayout) + insets.consumeSystemWindowInsets() + } + + maxWidth = context.resources.getDimensionPixelSize(R.dimen.navigation_drawer_max_width) + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure( + MeasureSpec.makeMeasureSpec( + Math.min(MeasureSpec.getSize(widthMeasureSpec), maxWidth), + MeasureSpec.getMode(widthMeasureSpec) + ), + heightMeasureSpec + ) + } + + override fun draw(canvas: Canvas) { + super.draw(canvas) + val width = width + val height = height + if (mInsets != null && mInsetForeground != null) { + val sc = canvas.save() + canvas.translate(scrollX.toFloat(), scrollY.toFloat()) + // Top + mTempRect.set(0, 0, width, mInsets!!.top) + mInsetForeground!!.bounds = mTempRect + mInsetForeground!!.draw(canvas) + // Bottom + mTempRect.set(0, height - mInsets!!.bottom, width, height) + mInsetForeground!!.bounds = mTempRect + mInsetForeground!!.draw(canvas) + // Left + mTempRect.set(0, mInsets!!.top, mInsets!!.left, height - mInsets!!.bottom) + mInsetForeground!!.bounds = mTempRect + mInsetForeground!!.draw(canvas) + // Right + mTempRect.set(width - mInsets!!.right, mInsets!!.top, width, height - mInsets!!.bottom) + mInsetForeground!!.bounds = mTempRect + mInsetForeground!!.draw(canvas) + canvas.restoreToCount(sc) + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + if (mInsetForeground != null) { + mInsetForeground!!.callback = this + } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + if (mInsetForeground != null) { + mInsetForeground!!.callback = null + } + } + + protected open fun onInsetsChanged(insets: WindowInsetsCompat) {} +} diff --git a/app/src/main/res/drawable/bg_intro.xml b/app/src/main/res/drawable/bg_intro.xml new file mode 100644 index 0000000000000000000000000000000000000000..1ade9669ad68db6d4c9b6aace31bded678ce60e5 --- /dev/null +++ b/app/src/main/res/drawable/bg_intro.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="1440dp" + android:height="810dp" + android:viewportHeight="810" + android:viewportWidth="1440"> + + <path + android:fillColor="#d7d7d7" + android:pathData="M 0 0 L 0 810 L 1440 810 L 1440 0 L 0 0 z" /> + <path + android:fillColor="#dcdcdc" + android:pathData="M 259.01562 810 L 1440 810 L 1440 0 L 745.32812 0 L 97.171875 648.15625 L 259.01562 810 z" /> + <path + android:fillColor="#e1e1e1" + android:pathData="M 556.24609 810 L 1440 810 L 1440 0 L 1366.2441 0 L 556.24609 810 z" /> + <path + android:fillColor="#e6e6e6" + android:pathData="M 644.31836 810 L 1440 810 L 1440 14.318359 L 644.31836 810 z" /> + <path + android:fillColor="#ebebeb" + android:pathData="M 1439.0195 810 L 1440 810 L 1440 270.47656 L 1169.748 540.72852 L 1439.0195 810z" /> + <path + android:fillColor="#f0f0f0" + android:pathData="M 900.47656 810 L 1440 810 L 1440 805.58203 L 1172.4473 538.0293 L 900.47656 810z" /> + <path + android:fillColor="#f5f5f5" + android:pathData="M 334.24023 0 L 0 0 L 0 810 L 1144.2402 810 L 334.24023 0 z" /> + <path + android:fillColor="#fafafa" + android:pathData="M 0 455.43359 L 0 810 L 354.56836 810 L 0 455.43359 z" /> + <path + android:fillColor="#ffffff" + android:pathData="M 0 536.39453 L 0 810 L 273.60547 810 L 0 536.39453 z" /> +</vector> diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 2f767fd2961521820dace4d4923f0e5cb659a46a..ebbea8d560a06dab78280fd5c9a774237fbfbc85 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,50 +1,63 @@ -<?xml version="1.0" encoding="utf-8"?> -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" +<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/drawer_layout" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:fitsSystemWindows="true" + tools:openDrawer="start"> - <LinearLayout + <include layout="@layout/content_main" /> + + <de.kuschku.quasseldroid_ng.util.ui.DrawerRecyclerView + android:id="@+id/nickList" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="end" + android:background="?android:attr/windowBackground" + android:clipToPadding="false" + android:fitsSystemWindows="true" /> + + <de.kuschku.quasseldroid_ng.util.ui.NavigationDrawerLayout android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:layout_marginTop="8dp" - android:orientation="vertical" - android:paddingLeft="24dp" - android:paddingRight="24dp"> + android:layout_height="match_parent" + android:layout_gravity="start" + android:background="?android:attr/windowBackground" + android:fitsSystemWindows="true" + app:insetForeground="?attr/colorPrimaryDark"> <LinearLayout android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="match_parent" + android:orientation="vertical"> - <Button - android:id="@+id/connect" - android:layout_width="wrap_content" + <android.support.design.widget.AppBarLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:minWidth="88dp" - android:text="Connect" - android:theme="@style/AppTheme.Button.Colored" /> + android:theme="?attr/actionBarTheme"> - <Button - android:id="@+id/disconnect" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:minWidth="88dp" - android:text="Disconnect" - android:theme="@style/AppTheme.Button" /> + <android.support.v7.widget.Toolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:background="?attr/colorPrimary" + app:contentInsetStartWithNavigation="0dp"> - <Button - android:id="@+id/clear" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:minWidth="88dp" - android:text="Clear" - android:theme="@style/AppTheme.Button" /> - </LinearLayout> + <android.support.v7.widget.AppCompatSpinner + android:id="@+id/chatListSpinner" + android:layout_width="fill_parent" + android:layout_height="match_parent" + android:theme="?attr/actionBarTheme" /> - <TextView - android:id="@+id/errorList" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textIsSelectable="true" /> - </LinearLayout> -</ScrollView> + </android.support.v7.widget.Toolbar> + + </android.support.design.widget.AppBarLayout> + + + <android.support.v7.widget.RecyclerView + android:id="@+id/chatList" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + </LinearLayout> + </de.kuschku.quasseldroid_ng.util.ui.NavigationDrawerLayout> +</android.support.v4.widget.DrawerLayout> diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml new file mode 100644 index 0000000000000000000000000000000000000000..a4984d3789756b6101de591c7cd1159a7ddf92b1 --- /dev/null +++ b/app/src/main/res/layout/content_main.xml @@ -0,0 +1,128 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fitsSystemWindows="true" + android:orientation="vertical"> + + <android.support.design.widget.AppBarLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:theme="?attr/actionBarTheme"> + + <android.support.v7.widget.Toolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:background="?attr/colorPrimary" + app:contentInsetStartWithNavigation="0dp"> + + <LinearLayout + android:id="@+id/toolbar_action_area" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:background="?attr/selectableItemBackgroundBorderless" + android:clickable="true" + android:focusable="true" + android:focusableInTouchMode="false" + android:gravity="center_vertical|start" + android:minHeight="?attr/actionBarSize" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_marginTop="-2dp" + android:baselineAligned="false" + android:gravity="center_vertical"> + + <TextView + android:id="@+id/key" + style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_marginEnd="2dp" + android:layout_marginRight="2dp" + android:layout_marginTop="2dp" + android:gravity="center" + android:textSize="16sp" + android:visibility="gone" /> + + <TextView + android:id="@+id/toolbar_title" + style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:gravity="center_vertical" + android:singleLine="true" + android:text="@string/app_name" /> + + </LinearLayout> + + <TextView + android:id="@+id/toolbar_subtitle" + style="@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="-3dp" + android:ellipsize="end" + android:singleLine="true" + android:visibility="gone" /> + </LinearLayout> + + </android.support.v7.widget.Toolbar> + + </android.support.design.widget.AppBarLayout> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="8dp" + android:layout_marginTop="8dp" + android:orientation="vertical" + android:paddingLeft="24dp" + android:paddingRight="24dp"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <Button + android:id="@+id/connect" + style="@style/Widget.Button.Colored" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minWidth="88dp" + android:text="Connect" /> + + <Button + android:id="@+id/disconnect" + style="@style/Widget.Button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minWidth="88dp" + android:text="Disconnect" /> + + <Button + android:id="@+id/clear" + style="@style/Widget.Button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minWidth="88dp" + android:text="Clear" /> + </LinearLayout> + + <TextView + android:id="@+id/errorList" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textIsSelectable="true" /> + </LinearLayout> + </ScrollView> +</LinearLayout> diff --git a/app/src/main/res/values-sw600dp/dimens.xml b/app/src/main/res/values-sw600dp/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..d5591b01943f2b7105b52250a6640ad0eb936c13 --- /dev/null +++ b/app/src/main/res/values-sw600dp/dimens.xml @@ -0,0 +1,3 @@ +<resources> + <dimen name="navigation_drawer_max_width">400dp</dimen> +</resources> diff --git a/app/src/main/res/values-sw600dp/styles.xml b/app/src/main/res/values-sw600dp/themes_base.xml similarity index 58% rename from app/src/main/res/values-sw600dp/styles.xml rename to app/src/main/res/values-sw600dp/themes_base.xml index 62a61762872f1553b16bad8ec6de6ac687cb3cce..424f44028f5b4059997759fd204cb07383d91db0 100644 --- a/app/src/main/res/values-sw600dp/styles.xml +++ b/app/src/main/res/values-sw600dp/themes_base.xml @@ -1,6 +1,6 @@ <resources> - <style name="SetupTheme" parent="AppTheme.NoActionBar"> + <style name="Theme.SetupTheme" parent="Theme.AppTheme.Light.NoActionBar"> <item name="android:windowBackground">?attr/colorPrimary</item> </style> </resources> diff --git a/app/src/main/res/values-v21/themes_base.xml b/app/src/main/res/values-v21/themes_base.xml new file mode 100644 index 0000000000000000000000000000000000000000..128214dfe23956b650f7350f91062a11c9966e86 --- /dev/null +++ b/app/src/main/res/values-v21/themes_base.xml @@ -0,0 +1,26 @@ +<resources> + + <style name="Theme.AppTheme.NoActionBar" parent="Theme.AppCompat.NoActionBar"> + <item name="colorPrimary">@color/colorPrimary</item> + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="colorAccent">@color/colorAccent</item> + <item name="android:windowDrawsSystemBarBackgrounds">true</item> + <item name="android:statusBarColor">?attr/colorPrimaryDark</item> + </style> + + <style name="Theme.AppTheme.Light.NoActionBar" parent="Theme.AppCompat.Light.NoActionBar"> + <item name="colorPrimary">@color/colorPrimary</item> + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="colorAccent">@color/colorAccent</item> + <item name="android:windowDrawsSystemBarBackgrounds">true</item> + <item name="android:statusBarColor">?attr/colorPrimaryDark</item> + </style> + + <style name="Base.ChatTheme" parent="Theme.AppTheme.NoActionBar"> + <item name="android:statusBarColor">#0000</item> + </style> + + <style name="Base.ChatTheme.Light" parent="Theme.AppTheme.Light.NoActionBar"> + <item name="android:statusBarColor">#0000</item> + </style> +</resources> diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 0000000000000000000000000000000000000000..46a053646ce0fed01fb5e8b8740b82110e0b67e2 --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,70 @@ +<resources> + <!-- sender colors --> + <attr name="senderColor0" format="color" /> + <attr name="senderColor1" format="color" /> + <attr name="senderColor2" format="color" /> + <attr name="senderColor3" format="color" /> + <attr name="senderColor4" format="color" /> + <attr name="senderColor5" format="color" /> + <attr name="senderColor6" format="color" /> + <attr name="senderColor7" format="color" /> + <attr name="senderColor8" format="color" /> + <attr name="senderColor9" format="color" /> + <attr name="senderColorA" format="color" /> + <attr name="senderColorB" format="color" /> + <attr name="senderColorC" format="color" /> + <attr name="senderColorD" format="color" /> + <attr name="senderColorE" format="color" /> + <attr name="senderColorF" format="color" /> + + <!-- mirc colors --> + <attr name="mircColor0" format="color" /> + <attr name="mircColor1" format="color" /> + <attr name="mircColor2" format="color" /> + <attr name="mircColor3" format="color" /> + <attr name="mircColor4" format="color" /> + <attr name="mircColor5" format="color" /> + <attr name="mircColor6" format="color" /> + <attr name="mircColor7" format="color" /> + <attr name="mircColor8" format="color" /> + <attr name="mircColor9" format="color" /> + <attr name="mircColorA" format="color" /> + <attr name="mircColorB" format="color" /> + <attr name="mircColorC" format="color" /> + <attr name="mircColorD" format="color" /> + <attr name="mircColorE" format="color" /> + <attr name="mircColorF" format="color" /> + + <!-- Background and foreground colors for UI --> + <attr name="colorForeground" format="color" /> + <attr name="colorForegroundHighlight" format="color" /> + <attr name="colorForegroundSecondary" format="color" /> + <attr name="colorForegroundAction" format="color" /> + <attr name="colorForegroundError" format="color" /> + + <attr name="colorForegroundMirc" format="integer" /> + + <attr name="colorDivider" format="color" /> + + <attr name="colorBackground" format="color" /> + <attr name="colorBackgroundHighlight" format="color" /> + <attr name="colorBackgroundSecondary" format="color" /> + <attr name="colorBackgroundCard" format="color" /> + <attr name="colorBackgroundDialog" format="color" /> + + <!-- Tint colors for drawer --> + <attr name="colorTintActivity" format="color" /> + <attr name="colorTintMessage" format="color" /> + <attr name="colorTintHighlight" format="color" /> + <attr name="chatlineExpandedSize" /> + + <!-- Icons --> + <attr name="colorOffline" format="color" /> + <attr name="colorAway" format="color" /> + <attr name="colorFill" format="color" /> + + <attr name="formatBarTheme" format="reference" /> + <attr name="buttonTheme" format="reference" /> + <attr name="buttonThemeColored" format="reference" /> + <attr name="cardStyle" format="reference" /> +</resources> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 3d2127148d95fdc23b4f6ec04c65d08f79df69ea..1b74be2c0c09054ae5886367863895f9eff7c065 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,4 +3,13 @@ <color name="colorPrimary">#0a70c0</color> <color name="colorPrimaryDark">#105a94</color> <color name="colorAccent">#ffaf3b</color> + + <color name="colorFillLight">#757575</color> + <color name="colorFillDark">#ffffff</color> + + <color name="colorOfflineLight">#757575</color> + <color name="colorOfflineDark">#B3B3B3</color> + + <color name="colorAwayLight">#959595</color> + <color name="colorAwayDark">#939393</color> </resources> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000000000000000000000000000000000000..4b085309263b5803199bd1e9b8e414b5185a313c --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,3 @@ +<resources> + <dimen name="navigation_drawer_max_width">320dp</dimen> +</resources> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml deleted file mode 100644 index 97b0c5a58e61c285190fc0c545f0661127837ce3..0000000000000000000000000000000000000000 --- a/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,29 +0,0 @@ -<resources> - - <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> - <item name="colorPrimary">@color/colorPrimary</item> - <item name="colorPrimaryDark">@color/colorPrimaryDark</item> - <item name="colorAccent">@color/colorAccent</item> - </style> - - <style name="AppTheme.NoActionBar" parent="Theme.AppCompat.Light.NoActionBar"> - <item name="colorPrimary">@color/colorPrimary</item> - <item name="colorPrimaryDark">@color/colorPrimaryDark</item> - <item name="colorAccent">@color/colorAccent</item> - </style> - - <style name="SetupTheme" parent="AppTheme.NoActionBar" /> - - <style name="AppTheme.Button" parent="AppTheme"> - <item name="colorButtonNormal">@android:color/background_light</item> - </style> - - <style name="AppTheme.Button.Colored" parent="AppTheme.Button"> - <item name="android:textColor">?android:attr/textColorPrimaryInverse</item> - <item name="colorButtonNormal">@color/colorAccent</item> - </style> - - <style name="SplashTheme" parent="AppTheme.NoActionBar"> - <item name="android:windowBackground">@drawable/bg_splash</item> - </style> -</resources> diff --git a/app/src/main/res/values/styles_widgets.xml b/app/src/main/res/values/styles_widgets.xml new file mode 100644 index 0000000000000000000000000000000000000000..f10b077c7d58296629c4a67f69298a5ab73e4da8 --- /dev/null +++ b/app/src/main/res/values/styles_widgets.xml @@ -0,0 +1,38 @@ +<resources> + + <style name="Widget" /> + + <style name="Widget.Button" parent="Widget.AppCompat.Button"> + <item name="backgroundTint">?attr/colorBackgroundCard</item> + </style> + + <style name="Widget.Button.Colored" parent="Widget.AppCompat.Button.Colored" /> + + <style name="Widget.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"> + <item name="colorControlNormal">@color/colorFillDark</item> + <item name="android:textColorPrimary">@color/colorFillDark</item> + <item name="drawerArrowStyle">@style/Widget.DrawerArrowToggle</item> + + <item name="colorFill">@color/colorFillDark</item> + <item name="colorOffline">@color/colorOfflineDark</item> + <item name="colorAway">@color/colorAwayDark</item> + </style> + + <style name="Widget.AppBarOverlay.Light" parent="ThemeOverlay.AppCompat.ActionBar"> + <item name="colorControlNormal">@color/colorFillLight</item> + <item name="android:textColorPrimary">@color/colorFillLight</item> + <item name="drawerArrowStyle">@style/Widget.DrawerArrowToggle.Light</item> + + <item name="colorFill">@color/colorFillLight</item> + <item name="colorOffline">@color/colorOfflineLight</item> + <item name="colorAway">@color/colorAwayLight</item> + </style> + + <style name="Widget.DrawerArrowToggle" parent="Widget.AppCompat.DrawerArrowToggle"> + <item name="color">?attr/colorControlNormal</item> + </style> + + <style name="Widget.DrawerArrowToggle.Light" parent="Widget.AppCompat.DrawerArrowToggle"> + <item name="color">?attr/colorControlNormal</item> + </style> +</resources> diff --git a/app/src/main/res/values/themes_amoled.xml b/app/src/main/res/values/themes_amoled.xml new file mode 100644 index 0000000000000000000000000000000000000000..3b9760efea1a10b190cdba5fa39e832a2364dfd2 --- /dev/null +++ b/app/src/main/res/values/themes_amoled.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ QuasselDroid - Quassel client for Android + ~ Copyright (C) 2016 Janne Koschinski + ~ Copyright (C) 2016 Ken Børge Viktil + ~ Copyright (C) 2016 Magnus Fjell + ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org> + ~ + ~ 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/>. + --> + +<resources> + <string name="themeAmoledkName">AMOLED (Black)</string> + <string name="themeAmoledId">AMOLED</string> + + <style name="Theme.ChatTheme.Amoled" parent="Theme.ChatTheme"> + <item name="colorPrimary">#000</item> + <item name="colorPrimaryDark">#000</item> + <item name="colorAccent">@color/colorAccent</item> + + <item name="senderColor0">#e90d7f</item> + <item name="senderColor1">#8e55e9</item> + <item name="senderColor2">#b30e0e</item> + <item name="senderColor3">#17b339</item> + <item name="senderColor4">#58afb3</item> + <item name="senderColor5">#9d54b3</item> + <item name="senderColor6">#b39775</item> + <item name="senderColor7">#3176b3</item> + <item name="senderColor8">#e90d7f</item> + <item name="senderColor9">#8e55e9</item> + <item name="senderColorA">#b30e0e</item> + <item name="senderColorB">#17b339</item> + <item name="senderColorC">#58afb3</item> + <item name="senderColorD">#9d54b3</item> + <item name="senderColorE">#b39775</item> + <item name="senderColorF">#3176b3</item> + + <item name="colorForeground">#FFFFFF</item> + <item name="colorForegroundHighlight">#FFFFFF</item> + <item name="colorForegroundSecondary">#B3FFFFFF</item> + <item name="colorForegroundAction">#7986cb</item> + <item name="colorForegroundError">#800000</item> + + <item name="colorForegroundMirc">0x0</item> + + <item name="colorBackground">#000000</item> + <item name="android:windowBackground">@color/amoled_background</item> + <item name="colorBackgroundHighlight">#ff8811</item> + <item name="colorBackgroundSecondary">@null</item> + <item name="colorBackgroundCard">#303030</item> + <item name="colorBackgroundDialog">#000000</item> + + <item name="colorTintActivity">#88cc33</item> + <item name="colorTintMessage">#2277dd</item> + <item name="colorTintHighlight">#ff8811</item> + </style> + + <color name="amoled_background">#000000</color> +</resources> diff --git a/app/src/main/res/values/themes_base.xml b/app/src/main/res/values/themes_base.xml new file mode 100644 index 0000000000000000000000000000000000000000..1929c6d5a5bb2291628cb0523db12e4901735fe0 --- /dev/null +++ b/app/src/main/res/values/themes_base.xml @@ -0,0 +1,100 @@ +<resources> + + <style name="Theme.AppTheme" parent="Theme.AppCompat"> + <item name="colorPrimary">@color/colorPrimary</item> + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="colorAccent">@color/colorAccent</item> + </style> + + <style name="Theme.AppTheme.Light" parent="Theme.AppCompat.Light.DarkActionBar"> + <item name="colorPrimary">@color/colorPrimary</item> + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="colorAccent">@color/colorAccent</item> + </style> + + <style name="Theme.AppTheme.Light.NoActionBar" parent="Theme.AppCompat.Light.NoActionBar"> + <item name="colorPrimary">@color/colorPrimary</item> + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="colorAccent">@color/colorAccent</item> + </style> + + <style name="Theme.AppTheme.NoActionBar" parent="Theme.AppCompat.NoActionBar"> + <item name="colorPrimary">@color/colorPrimary</item> + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="colorAccent">@color/colorAccent</item> + </style> + + <style name="Theme.Base.ChatTheme" parent="Theme.AppTheme.NoActionBar" /> + + <style name="Theme.Base.ChatTheme.Light" parent="Theme.AppTheme.Light.NoActionBar" /> + + <style name="Theme.SetupTheme" parent="Theme.AppTheme.Light.NoActionBar" /> + + <style name="Theme.SplashTheme" parent="Theme.AppTheme.Light.NoActionBar"> + <item name="android:windowBackground">@drawable/bg_splash</item> + </style> + + <style name="Theme.ChatTheme" parent="Base.ChatTheme"> + <item name="actionBarTheme">@style/Widget.AppBarOverlay</item> + <item name="formatBarTheme">@style/Widget.AppBarOverlay</item> + + <item name="windowActionModeOverlay">true</item> + + <item name="colorDivider">#1FFFFFFF</item> + + <item name="colorFill">@color/colorFillDark</item> + <item name="colorOffline">@color/colorOfflineDark</item> + <item name="colorAway">@color/colorAwayDark</item> + + <item name="cardStyle">@style/CardView.Dark</item> + + <item name="mircColor0">#ffffff</item> + <item name="mircColor1">#000000</item> + <item name="mircColor2">#000080</item> + <item name="mircColor3">#008000</item> + <item name="mircColor4">#ff0000</item> + <item name="mircColor5">#800000</item> + <item name="mircColor6">#800080</item> + <item name="mircColor7">#ffa500</item> + <item name="mircColor8">#ffff00</item> + <item name="mircColor9">#00ff00</item> + <item name="mircColorA">#008080</item> + <item name="mircColorB">#00ffff</item> + <item name="mircColorC">#4169e1</item> + <item name="mircColorD">#ff00ff</item> + <item name="mircColorE">#808080</item> + <item name="mircColorF">#c0c0c0</item> + </style> + + <style name="Theme.ChatTheme.Light" parent="Base.ChatTheme.Light"> + <item name="actionBarTheme">@style/Widget.AppBarOverlay</item> + <item name="formatBarTheme">@style/Widget.AppBarOverlay.Light</item> + + <item name="windowActionModeOverlay">true</item> + + <item name="colorDivider">#1F000000</item>> + + <item name="colorFill">@color/colorFillLight</item> + <item name="colorOffline">@color/colorOfflineLight</item> + <item name="colorAway">@color/colorAwayLight</item> + + <item name="cardStyle">@style/CardView.Light</item> + + <item name="mircColor0">#ffffff</item> + <item name="mircColor1">#000000</item> + <item name="mircColor2">#000080</item> + <item name="mircColor3">#008000</item> + <item name="mircColor4">#ff0000</item> + <item name="mircColor5">#800000</item> + <item name="mircColor6">#800080</item> + <item name="mircColor7">#ffa500</item> + <item name="mircColor8">#ffff00</item> + <item name="mircColor9">#00ff00</item> + <item name="mircColorA">#008080</item> + <item name="mircColorB">#00ffff</item> + <item name="mircColorC">#4169e1</item> + <item name="mircColorD">#ff00ff</item> + <item name="mircColorE">#808080</item> + <item name="mircColorF">#c0c0c0</item> + </style> +</resources> diff --git a/app/src/main/res/values/themes_quassel.xml b/app/src/main/res/values/themes_quassel.xml new file mode 100644 index 0000000000000000000000000000000000000000..2d46014a775e42e3a6b40d65e0f7a7d6a7e997a2 --- /dev/null +++ b/app/src/main/res/values/themes_quassel.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ QuasselDroid - Quassel client for Android + ~ Copyright (C) 2016 Janne Koschinski + ~ Copyright (C) 2016 Ken Børge Viktil + ~ Copyright (C) 2016 Magnus Fjell + ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org> + ~ + ~ 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/>. + --> + +<resources> + <string name="themeQuasselLightName">Quassel™ (Light)</string> + <string name="themeQuasselLightId">QUASSEL_LIGHT</string> + + <style name="Theme.ChatTheme.Quassel_Light" parent="Theme.ChatTheme.Light"> + <item name="senderColor0">#e90d7f</item> + <item name="senderColor1">#8e55e9</item> + <item name="senderColor2">#b30e0e</item> + <item name="senderColor3">#17b339</item> + <item name="senderColor4">#58afb3</item> + <item name="senderColor5">#9d54b3</item> + <item name="senderColor6">#b39775</item> + <item name="senderColor7">#3176b3</item> + <item name="senderColor8">#e90d7f</item> + <item name="senderColor9">#8e55e9</item> + <item name="senderColorA">#b30e0e</item> + <item name="senderColorB">#17b339</item> + <item name="senderColorC">#58afb3</item> + <item name="senderColorD">#9d54b3</item> + <item name="senderColorE">#b39775</item> + <item name="senderColorF">#3176b3</item> + + <item name="colorForeground">#DE000000</item> + <item name="colorForegroundHighlight">#DE000000</item> + <item name="colorForegroundSecondary">#8A000000</item> + <item name="colorForegroundAction">#1a237e</item> + <item name="colorForegroundError">#800000</item> + + <item name="colorForegroundMirc">0x1</item> + + <item name="colorBackground">#FAFAFA</item> + <item name="android:windowBackground">@color/quasselLight_background</item> + <item name="colorBackgroundHighlight">#ff8811</item> + <item name="colorBackgroundSecondary">@null</item> + <item name="colorBackgroundCard">#FFFFFF</item> + <item name="colorBackgroundDialog">#FAFAFA</item> + + <item name="colorTintActivity">#88cc33</item> + <item name="colorTintMessage">#2277dd</item> + <item name="colorTintHighlight">#ff8811</item> + </style> + + <color name="quasselLight_background">#FAFAFA</color> + + <string name="themeQuasselDarkName">Quassel™ (Dark)</string> + <string name="themeQuasselDarkId">QUASSEL_DARK</string> + + <style name="Theme.ChatTheme.Quassel_Dark" parent="Theme.ChatTheme"> + <item name="senderColor0">#e90d7f</item> + <item name="senderColor1">#8e55e9</item> + <item name="senderColor2">#b30e0e</item> + <item name="senderColor3">#17b339</item> + <item name="senderColor4">#58afb3</item> + <item name="senderColor5">#9d54b3</item> + <item name="senderColor6">#b39775</item> + <item name="senderColor7">#3176b3</item> + <item name="senderColor8">#e90d7f</item> + <item name="senderColor9">#8e55e9</item> + <item name="senderColorA">#b30e0e</item> + <item name="senderColorB">#17b339</item> + <item name="senderColorC">#58afb3</item> + <item name="senderColorD">#9d54b3</item> + <item name="senderColorE">#b39775</item> + <item name="senderColorF">#3176b3</item> + + <item name="colorForeground">#FFFFFF</item> + <item name="colorForegroundHighlight">#FFFFFF</item> + <item name="colorForegroundSecondary">#B3FFFFFF</item> + <item name="colorForegroundAction">#7986cb</item> + <item name="colorForegroundError">#800000</item> + + <item name="colorForegroundMirc">0x0</item> + + <item name="colorBackground">#303030</item> + <item name="android:windowBackground">@color/quasselDark_background</item> + <item name="colorBackgroundHighlight">#ff8811</item> + <item name="colorBackgroundSecondary">@null</item> + <item name="colorBackgroundCard">#424242</item> + <item name="colorBackgroundDialog">#303030</item> + + <item name="colorTintActivity">#88cc33</item> + <item name="colorTintMessage">#2277dd</item> + <item name="colorTintHighlight">#ff8811</item> + </style> + + <color name="quasselDark_background">#303030</color> +</resources> diff --git a/app/src/main/res/values/themes_solarized.xml b/app/src/main/res/values/themes_solarized.xml new file mode 100644 index 0000000000000000000000000000000000000000..953e2cf5f5cd8157e67230cb9e22cfc287fc3949 --- /dev/null +++ b/app/src/main/res/values/themes_solarized.xml @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ QuasselDroid - Quassel client for Android + ~ Copyright (C) 2016 Janne Koschinski + ~ Copyright (C) 2016 Ken Børge Viktil + ~ Copyright (C) 2016 Magnus Fjell + ~ Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org> + ~ + ~ 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/>. + --> + +<resources> + <string name="themeSolarizedLightName">Solarized (Light)</string> + <string name="themeSolarizedLightId">SOLARIZED_LIGHT</string> + + <style name="Theme.ChatTheme.Solarized_Light" parent="Theme.ChatTheme.Light"> + <item name="colorPrimary">?attr/colorBackgroundCard</item> + <item name="colorPrimaryDark">#b0ac9e</item> + <item name="colorAccent">#B58900</item> + + <item name="actionBarTheme">@style/Widget.AppBarOverlay.Light</item> + + <item name="senderColor0">#B58900</item> + <item name="senderColor1">#CB4B16</item> + <item name="senderColor2">#DC322f</item> + <item name="senderColor3">#D33682</item> + <item name="senderColor4">#6C71C4</item> + <item name="senderColor5">#268BD2</item> + <item name="senderColor6">#2AA198</item> + <item name="senderColor7">#859900</item> + <item name="senderColor8">#D5A920</item> + <item name="senderColor9">#EB6B36</item> + <item name="senderColorA">#FC524f</item> + <item name="senderColorB">#F356A2</item> + <item name="senderColorC">#8C91E4</item> + <item name="senderColorD">#46ABF2</item> + <item name="senderColorE">#4AC1B8</item> + <item name="senderColorF">#657900</item> + + <item name="colorForeground">#839495</item> + <item name="colorForegroundHighlight">#839495</item> + <item name="colorForegroundSecondary">#576A66</item> + <item name="colorForegroundAction">#268BD2</item> + <item name="colorForegroundError">#B00000</item> + + <item name="colorForegroundMirc">0xF</item> + + <item name="colorBackground">#FDF6E3</item> + <item name="android:windowBackground">@color/solarizedLight_background</item> + <item name="colorBackgroundHighlight">#268bd2</item> + <item name="colorBackgroundSecondary">@null</item> + <item name="colorBackgroundCard">#EEE8D5</item> + <item name="colorBackgroundDialog">#FDF6E3</item> + + <item name="colorTintActivity">#88cc33</item> + <item name="colorTintMessage">#2277dd</item> + <item name="colorTintHighlight">#ff8811</item> + </style> + + <color name="solarizedLight_background">#FDF6E3</color> + + <string name="themeSolarizedDarkName">Solarized (Dark)</string> + <string name="themeSolarizedDarkId">SOLARIZED_DARK</string> + + <style name="Theme.ChatTheme.Solarized_Dark" parent="Theme.ChatTheme"> + <item name="colorPrimary">?attr/colorBackgroundCard</item> + <item name="colorPrimaryDark">?attr/colorBackground</item> + <item name="colorAccent">#B58900</item> + + <item name="senderColor0">#B58900</item> + <item name="senderColor1">#CB4B16</item> + <item name="senderColor2">#DC322f</item> + <item name="senderColor3">#D33682</item> + <item name="senderColor4">#6C71C4</item> + <item name="senderColor5">#268BD2</item> + <item name="senderColor6">#2AA198</item> + <item name="senderColor7">#859900</item> + <item name="senderColor8">#D5A920</item> + <item name="senderColor9">#EB6B36</item> + <item name="senderColorA">#FC524f</item> + <item name="senderColorB">#F356A2</item> + <item name="senderColorC">#8C91E4</item> + <item name="senderColorD">#46ABF2</item> + <item name="senderColorE">#4AC1B8</item> + <item name="senderColorF">#657900</item> + + <item name="colorForeground">#839495</item> + <item name="colorForegroundHighlight">#839495</item> + <item name="colorForegroundSecondary">#576A66</item> + <item name="colorForegroundAction">#268BD2</item> + <item name="colorForegroundError">#B00000</item> + + <item name="colorForegroundMirc">0xF</item> + + <item name="colorBackground">#002B36</item> + <item name="android:windowBackground">@color/solarizedDark_background</item> + <item name="colorBackgroundHighlight">#268bd2</item> + <item name="colorBackgroundSecondary">@null</item> + <item name="colorBackgroundCard">#073642</item> + <item name="colorBackgroundDialog">#002B36</item> + + <item name="colorTintActivity">#88cc33</item> + <item name="colorTintMessage">#2277dd</item> + <item name="colorTintHighlight">#ff8811</item> + </style> + + <color name="solarizedDark_background">#002B36</color> +</resources> diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt index a0b0451e0bb8297562f5d5a6ad00e091a35b9954..41fd63f5bbb76d5e5bb6e902d914c8489e2b1dc3 100644 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/primitive/serializer/DateTimeSerializer.kt @@ -59,12 +59,12 @@ object DateTimeSerializer : Serializer<Temporal> { if (milliOfDay == -1L || julianDay == -1L) return Instant.EPOCH return when (timeSpec) { - TimeSpec.LocalTime -> + TimeSpec.LocalTime -> Instant.EPOCH.atZone(ZoneOffset.systemDefault()) .with(JulianFields.JULIAN_DAY, julianDay) .with(ChronoField.MILLI_OF_DAY, milliOfDay) .toInstant() - else -> + else -> Instant.EPOCH.atOffset(ZoneOffset.UTC) .with(JulianFields.JULIAN_DAY, julianDay) .with(ChronoField.MILLI_OF_DAY, milliOfDay) diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt index efd3ffea182c842107e4e29e6b66b97ac3f3756b..e96c1a90b933d65a84b3b0caeecd17698a1fe52e 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewConfig.kt @@ -124,7 +124,7 @@ class BufferViewConfig constructor( _buffers.remove(bufferId) if (_temporarilyRemovedBuffers.contains(bufferId)) - _temporarilyRemovedBuffers.remove(bufferId); + _temporarilyRemovedBuffers.remove(bufferId) _removedBuffers.add(bufferId) } @@ -192,18 +192,18 @@ class BufferViewConfig constructor( super.setSortAlphabetically(sortAlphabetically) } - val _bufferViewId: Int = bufferViewId - var _bufferViewName: String = "" - var _networkId: NetworkId = 0 - var _addNewBuffersAutomatically: Boolean = true - var _sortAlphabetically: Boolean = true - var _hideInactiveBuffers: Boolean = false - var _hideInactiveNetworks: Boolean = false - var _disableDecoration: Boolean = false - var _allowedBufferTypes: Buffer_Types = Buffer_Type.of(*Buffer_Type.validValues) - var _minimumActivity: Buffer_Activities = Buffer_Activities.of(0) - var _showSearch: Boolean = false - var _buffers: MutableList<BufferId> = mutableListOf() - var _removedBuffers: MutableSet<BufferId> = mutableSetOf() - var _temporarilyRemovedBuffers: MutableSet<BufferId> = mutableSetOf() + private val _bufferViewId: Int = bufferViewId + private var _bufferViewName: String = "" + private var _networkId: NetworkId = 0 + private var _addNewBuffersAutomatically: Boolean = true + private var _sortAlphabetically: Boolean = true + private var _hideInactiveBuffers: Boolean = false + private var _hideInactiveNetworks: Boolean = false + private var _disableDecoration: Boolean = false + private var _allowedBufferTypes: Buffer_Types = Buffer_Type.of(*Buffer_Type.validValues) + private var _minimumActivity: Buffer_Activities = Buffer_Activities.of(0) + private var _showSearch: Boolean = false + private var _buffers: MutableList<BufferId> = mutableListOf() + private var _removedBuffers: MutableSet<BufferId> = mutableSetOf() + private var _temporarilyRemovedBuffers: MutableSet<BufferId> = mutableSetOf() } diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt index e23d3c563319b894bfb8c27cd631c6f468d654e8..101b215a48068c5443dc781699f283a6beaf2888 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/BufferViewManager.kt @@ -3,6 +3,7 @@ package de.kuschku.libquassel.quassel.syncables import de.kuschku.libquassel.protocol.* import de.kuschku.libquassel.quassel.syncables.interfaces.IBufferViewManager import de.kuschku.libquassel.session.SignalProxy +import io.reactivex.subjects.BehaviorSubject class BufferViewManager constructor( proxy: SignalProxy @@ -35,6 +36,7 @@ class BufferViewManager constructor( proxy.synchronize(config, !initialized) _bufferViewConfigs[config.bufferViewId()] = config + bufferViewConfigIds.onNext(_bufferViewConfigs.keys) } override fun addBufferViewConfig(bufferViewConfigId: Int) { @@ -49,7 +51,12 @@ class BufferViewManager constructor( return _bufferViewConfigs.remove(bufferViewConfigId) + bufferViewConfigIds.onNext(_bufferViewConfigs.keys) } - private val _bufferViewConfigs: MutableMap<BufferId, BufferViewConfig> = mutableMapOf() + private val _bufferViewConfigs: MutableMap<Int, BufferViewConfig> + = mutableMapOf() + + val bufferViewConfigIds: BehaviorSubject<Set<Int>> + = BehaviorSubject.createDefault<Set<Int>>(emptySet()) } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt index 652f3dadb47f12b05aafa520cdd53855a5f32020..6ca61a86786fd2f0ce8d2eea934ec0d6089e32b5 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt @@ -18,7 +18,6 @@ import de.kuschku.libquassel.util.helpers.hexDump import de.kuschku.libquassel.util.helpers.write import de.kuschku.libquassel.util.nio.ChainedByteBuffer import de.kuschku.libquassel.util.nio.WrappedChannel -import io.reactivex.BackpressureStrategy import io.reactivex.subjects.BehaviorSubject import org.threeten.bp.ZoneOffset import org.threeten.bp.format.DateTimeFormatter @@ -44,8 +43,7 @@ class CoreConnection( private val sizeBuffer = ByteBuffer.allocateDirect(4) private val chainedBuffer = ChainedByteBuffer(direct = true) - private val internalState = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED) - val state = internalState.toFlowable(BackpressureStrategy.LATEST) + val state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED) private var channel: WrappedChannel? = null @@ -61,7 +59,7 @@ class CoreConnection( fun setState(value: ConnectionState) { log(INFO, TAG, value.name) - internalState.onNext(value) + state.onNext(value) } private fun sendHandshake() { @@ -170,7 +168,7 @@ class CoreConnection( } dataBuffer.flip() handlerService.parse { - when (internalState.value) { + when (state.value) { ConnectionState.HANDSHAKE -> processHandshake(dataBuffer) else -> processSigProxy(dataBuffer) } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt b/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt index 64054b6ea97aa4cf45e4aefba47901aabeea292d..b5f4c0990ffc3cab881b2194a7ec83ea311da6cf 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/ISession.kt @@ -1,19 +1,45 @@ package de.kuschku.libquassel.session -import io.reactivex.BackpressureStrategy -import io.reactivex.Flowable +import de.kuschku.libquassel.protocol.IdentityId +import de.kuschku.libquassel.protocol.NetworkId +import de.kuschku.libquassel.quassel.syncables.* +import io.reactivex.Observable import io.reactivex.subjects.BehaviorSubject import java.io.Closeable interface ISession : Closeable { - val state: Flowable<ConnectionState> + val state: Observable<ConnectionState> + + val aliasManager: AliasManager? + val backlogManager: BacklogManager? + val bufferSyncer: BufferSyncer? + val bufferViewManager: BufferViewManager? + val certManagers: Map<IdentityId, CertManager> + val coreInfo: CoreInfo? + val dccConfig: DccConfig? + val identities: Map<IdentityId, Identity> + val ignoreListManager: IgnoreListManager? + val ircListHelper: IrcListHelper? + val networks: Map<NetworkId, Network> + val networkConfig: NetworkConfig? companion object { val NULL = object : ISession { + override val aliasManager: AliasManager? = null + override val backlogManager: BacklogManager? = null + override val bufferSyncer: BufferSyncer? = null + override val bufferViewManager: BufferViewManager? = null + override val certManagers: Map<IdentityId, CertManager> = emptyMap() + override val coreInfo: CoreInfo? = null + override val dccConfig: DccConfig? = null + override val identities: Map<IdentityId, Identity> = emptyMap() + override val ignoreListManager: IgnoreListManager? = null + override val ircListHelper: IrcListHelper? = null + override val networks: Map<NetworkId, Network> = emptyMap() + override val networkConfig: NetworkConfig? = null + override fun close() = Unit - override val state: Flowable<ConnectionState> - = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED) - .toFlowable(BackpressureStrategy.LATEST) + override val state = BehaviorSubject.createDefault(ConnectionState.DISCONNECTED) } } } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/Session.kt b/lib/src/main/java/de/kuschku/libquassel/session/Session.kt index d45a5f85d3e5d8205f3cb75c0cc9261e2b66ca38..158a82a439b4c9a29370adc308f020ff3d3e983a 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/Session.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/Session.kt @@ -10,7 +10,6 @@ import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO import de.kuschku.libquassel.util.compatibility.log import de.kuschku.libquassel.util.hasFlag -import io.reactivex.Flowable import org.threeten.bp.Instant import javax.net.ssl.X509TrustManager @@ -24,20 +23,20 @@ class Session( var coreFeatures: Quassel_Features = Quassel_Feature.NONE private val coreConnection = CoreConnection(this, address, handlerService) - override val state: Flowable<ConnectionState> = coreConnection.state - - private var aliasManager: AliasManager? = null - private var backlogManager: BacklogManager? = null - private var bufferSyncer: BufferSyncer? = null - private var bufferViewManager: BufferViewManager? = null - private var certManagers = mutableMapOf<IdentityId, CertManager>() - private var coreInfo: CoreInfo? = null - private var dccConfig: DccConfig? = null - private var identities = mutableMapOf<IdentityId, Identity>() - private var ignoreListManager: IgnoreListManager? = null - private var ircListHelper: IrcListHelper? = null - private var networks = mutableMapOf<NetworkId, Network>() - private var networkConfig: NetworkConfig? = null + override val state = coreConnection.state + + override val aliasManager = AliasManager(this) + override val backlogManager = BacklogManager(this) + override val bufferSyncer = BufferSyncer(this) + override val bufferViewManager = BufferViewManager(this) + override val certManagers = mutableMapOf<IdentityId, CertManager>() + override val coreInfo = CoreInfo(this) + override val dccConfig = DccConfig(this) + override val identities = mutableMapOf<IdentityId, Identity>() + override val ignoreListManager = IgnoreListManager(this) + override val ircListHelper = IrcListHelper(this) + override val networks = mutableMapOf<NetworkId, Network>() + override val networkConfig = NetworkConfig(this) init { coreConnection.start() @@ -74,31 +73,14 @@ class Session( networks.values.forEach { syncableObject -> this.synchronize(syncableObject, true) } certManagers.values.forEach { syncableObject -> this.synchronize(syncableObject, true) } - aliasManager = AliasManager(this) synchronize(aliasManager, true) - - backlogManager = BacklogManager(this) - - bufferSyncer = BufferSyncer(this) synchronize(bufferSyncer, true) - - bufferViewManager = BufferViewManager(this) synchronize(bufferViewManager, true) - - coreInfo = CoreInfo(this) synchronize(coreInfo, true) - - dccConfig = DccConfig(this) if (coreFeatures.hasFlag(QuasselFeature.DccFileTransfer)) synchronize(dccConfig, true) - - ignoreListManager = IgnoreListManager(this) synchronize(ignoreListManager, true) - - ircListHelper = IrcListHelper(this) synchronize(ircListHelper, true) - - networkConfig = NetworkConfig(this) synchronize(networkConfig, true) return true @@ -132,16 +114,6 @@ class Session( override fun close() { coreConnection.close() - aliasManager = null - backlogManager = null - bufferSyncer = null - bufferViewManager = null - coreInfo = null - dccConfig = null - ignoreListManager = null - ircListHelper = null - networkConfig = null - certManagers.clear() identities.clear() networks.clear() diff --git a/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt b/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt index f2e46155289b912958b5e2bb6f3f4d03cd2c1758..a90363ffa07ebab255cac266048141097b32a96a 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/SessionManager.kt @@ -1,18 +1,47 @@ package de.kuschku.libquassel.session import de.kuschku.libquassel.protocol.ClientData +import de.kuschku.libquassel.protocol.IdentityId +import de.kuschku.libquassel.protocol.NetworkId +import de.kuschku.libquassel.quassel.syncables.* import de.kuschku.libquassel.quassel.syncables.interfaces.invokers.Invokers import de.kuschku.libquassel.util.compatibility.HandlerService import de.kuschku.libquassel.util.compatibility.LoggingHandler import de.kuschku.libquassel.util.compatibility.log -import io.reactivex.BackpressureStrategy -import io.reactivex.Flowable +import io.reactivex.Observable import io.reactivex.subjects.BehaviorSubject import javax.net.ssl.X509TrustManager class SessionManager( private val offlineSession: ISession -) { +) : ISession { + override val aliasManager: AliasManager? + get() = session.or(offlineSession).aliasManager + override val backlogManager: BacklogManager? + get() = session.or(offlineSession).backlogManager + override val bufferSyncer: BufferSyncer? + get() = session.or(offlineSession).bufferSyncer + override val bufferViewManager: BufferViewManager? + get() = session.or(offlineSession).bufferViewManager + override val certManagers: Map<IdentityId, CertManager> + get() = session.or(offlineSession).certManagers + override val coreInfo: CoreInfo? + get() = session.or(offlineSession).coreInfo + override val dccConfig: DccConfig? + get() = session.or(offlineSession).dccConfig + override val identities: Map<IdentityId, Identity> + get() = session.or(offlineSession).identities + override val ignoreListManager: IgnoreListManager? + get() = session.or(offlineSession).ignoreListManager + override val ircListHelper: IrcListHelper? + get() = session.or(offlineSession).ircListHelper + override val networks: Map<NetworkId, Network> + get() = session.or(offlineSession).networks + override val networkConfig: NetworkConfig? + get() = session.or(offlineSession).networkConfig + + override fun close() = session.or(offlineSession).close() + init { log(LoggingHandler.LogLevel.INFO, "Session", "Session created") @@ -37,9 +66,7 @@ class SessionManager( } private var inProgressSession = BehaviorSubject.createDefault(offlineSession) - private val inProgressSessionPublisher: Flowable<ISession> - = inProgressSession.toFlowable(BackpressureStrategy.LATEST) - val state = inProgressSessionPublisher.switchMap { it.state } + override val state = inProgressSession.switchMap { it.state } val session = state.map { connectionState -> if (connectionState == ConnectionState.CONNECTED) inProgressSession.value @@ -47,3 +74,6 @@ class SessionManager( offlineSession } } + +fun <T> Observable<T>.or(default: T): T + = this.blockingLatest().firstOrNull() ?: default