Some UI candy

This commit is contained in:
TebbeUbben 2020-05-20 23:59:14 +02:00
parent 09b81093dc
commit c7df607d97
8 changed files with 234 additions and 37 deletions

View file

@ -2049,4 +2049,29 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
} }
return Collections.emptyList(); return Collections.emptyList();
} }
public long getOHQueueSize() {
try {
return getDaoOpenHumansQueue().countOf();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return 0L;
}
public long getCountOfAllRows() {
try {
return getDaoBgReadings().countOf()
+ getDaoCareportalEvents().countOf()
+ getDaoExtendedBolus().countOf()
+ getDaoCareportalEvents().countOf()
+ getDaoProfileSwitch().countOf()
+ getDaoTDD().countOf()
+ getDaoTemporaryBasal().countOf()
+ getDaoTempTargets().countOf();
} catch (SQLException e) {
log.error("Unhandled exception", e);
}
return 0L;
}
} }

View file

@ -6,18 +6,101 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import android.widget.TextView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.work.WorkInfo
import androidx.work.WorkManager
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.Event
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.plusAssign
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.TimeUnit
class OpenHumansFragment : Fragment() { class OpenHumansFragment : Fragment() {
private var viewsCreated = false
private var login: Button? = null
private var logout: Button? = null
private var memberId: TextView? = null
private var queueSize: TextView? = null
private var workerState: TextView? = null
private var queueSizeValue = 0L
private val compositeDisposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
compositeDisposable += RxBus.toObservable(UpdateQueueEvent::class.java)
.throttleLatest(5, TimeUnit.SECONDS)
.observeOn(Schedulers.io())
.map { MainApp.getDbHelper().ohQueueSize }
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
queueSizeValue = it
updateGUI()
}
compositeDisposable += RxBus.toObservable(UpdateViewEvent::class.java)
.observeOn(Schedulers.io())
.map { MainApp.getDbHelper().ohQueueSize }
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
queueSizeValue = it
updateGUI()
}
WorkManager.getInstance(MainApp.instance()).getWorkInfosForUniqueWorkLiveData(OpenHumansUploader.WORK_NAME).observe(this, Observer<List<WorkInfo>> {
val workInfo = it.lastOrNull()
if (workInfo == null) {
workerState?.visibility = View.GONE
} else {
workerState?.visibility = View.VISIBLE
workerState?.text = getString(R.string.worker_state, workInfo.state.toString())
}
})
}
override fun onDestroy() {
compositeDisposable.clear()
super.onDestroy()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val view = inflater.inflate(R.layout.fragment_open_humans, container, false) val view = inflater.inflate(R.layout.fragment_open_humans, container, false)
val button = view.findViewById<Button>(R.id.login) login = view.findViewById(R.id.login)
button.setOnClickListener { logout = view.findViewById(R.id.logout)
startActivity(Intent(context, OpenHumansLoginActivity::class.java)) memberId = view.findViewById(R.id.member_id)
} queueSize = view.findViewById(R.id.queue_size)
workerState = view.findViewById(R.id.worker_state)
login!!.setOnClickListener { startActivity(Intent(context, OpenHumansLoginActivity::class.java)) }
logout!!.setOnClickListener { OpenHumansUploader.logout() }
viewsCreated = true
updateGUI()
return view return view
} }
override fun onDestroyView() {
viewsCreated = false
login = null
logout = null
memberId = null
queueSize = null
super.onDestroyView()
}
fun updateGUI() {
if (viewsCreated) {
queueSize!!.text = getString(R.string.queue_size, queueSizeValue)
val projectMemberId = OpenHumansUploader.projectMemberId
memberId!!.text = getString(R.string.project_member_id, projectMemberId ?: getString(R.string.not_logged_in))
login!!.visibility = if (projectMemberId == null) View.VISIBLE else View.GONE
logout!!.visibility = if (projectMemberId != null) View.VISIBLE else View.GONE
}
}
object UpdateViewEvent : Event()
object UpdateQueueEvent : Event()
} }

View file

@ -22,7 +22,7 @@ import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
class OpenHumansLoginActivity : NoSplashAppCompatActivity() { class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
/*
private lateinit var customTabsClient: CustomTabsClient private lateinit var customTabsClient: CustomTabsClient
private lateinit var customTabsSession: CustomTabsSession private lateinit var customTabsSession: CustomTabsSession
@ -37,17 +37,17 @@ class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
override fun onServiceDisconnected(name: ComponentName?) { override fun onServiceDisconnected(name: ComponentName?) {
} }
} }
*/
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
CustomTabsClient.bindCustomTabsService(this, "com.android.chrome", connection) //CustomTabsClient.bindCustomTabsService(this, "com.android.chrome", connection)
setContentView(R.layout.activity_open_humans_login) setContentView(R.layout.activity_open_humans_login)
val button = findViewById<Button>(R.id.button) val button = findViewById<Button>(R.id.button)
val checkbox = findViewById<CheckBox>(R.id.checkbox) val checkbox = findViewById<CheckBox>(R.id.checkbox)
button.setOnClickListener { _ -> button.setOnClickListener { _ ->
if (checkbox.isChecked) { if (checkbox.isChecked) {
CustomTabsIntent.Builder().setSession(customTabsSession).build().launchUrl(this, Uri.parse(OpenHumansUploader.AUTH_URL)) CustomTabsIntent.Builder()/*.setSession(customTabsSession)*/.build().launchUrl(this, Uri.parse(OpenHumansUploader.AUTH_URL))
} else { } else {
Toast.makeText(this, R.string.you_need_to_accept_the_of_use_first, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.you_need_to_accept_the_of_use_first, Toast.LENGTH_SHORT).show()
} }

View file

@ -21,6 +21,7 @@ import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.L import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.SP import info.nightscout.androidaps.utils.SP
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
@ -86,11 +87,12 @@ object OpenHumansUploader : PluginBase(
SP.remove("openhumans_access_token") SP.remove("openhumans_access_token")
SP.remove("openhumans_refresh_token") SP.remove("openhumans_refresh_token")
SP.remove("openhumans_expires_at") SP.remove("openhumans_expires_at")
SP.remove("openhumans_expires_at")
} }
} }
private var projectMemberId: String? var projectMemberId: String?
get() = SP.getString("openhumans_project_member_id", null) get() = SP.getString("openhumans_project_member_id", null)
set(value) { private set(value) {
if (value == null) SP.remove("openhumans_project_member_id") if (value == null) SP.remove("openhumans_project_member_id")
else SP.putString("openhumans_project_member_id", value) else SP.putString("openhumans_project_member_id", value)
} }
@ -233,13 +235,14 @@ object OpenHumansUploader : PluginBase(
content = jsonObject.toString() content = jsonObject.toString()
) )
MainApp.getDbHelper().createOrUpdate(queueItem) MainApp.getDbHelper().createOrUpdate(queueItem)
RxBus.send(OpenHumansFragment.UpdateQueueEvent)
} catch (e: JSONException) { } catch (e: JSONException) {
e.printStackTrace() e.printStackTrace()
} }
} }
} }
fun login(authCode: String) = fun login(authCode: String): Completable =
openHumansAPI.exchangeAuthToken(authCode) openHumansAPI.exchangeAuthToken(authCode)
.doOnSuccess { .doOnSuccess {
oAuthTokens = it oAuthTokens = it
@ -248,6 +251,7 @@ object OpenHumansUploader : PluginBase(
.doOnSuccess { .doOnSuccess {
projectMemberId = it projectMemberId = it
copyExistingDataToQueue() copyExistingDataToQueue()
RxBus.send(OpenHumansFragment.UpdateViewEvent)
} }
.ignoreElement() .ignoreElement()
@ -258,34 +262,39 @@ object OpenHumansUploader : PluginBase(
oAuthTokens = null oAuthTokens = null
projectMemberId = null projectMemberId = null
MainApp.getDbHelper().clearOpenHumansQueue() MainApp.getDbHelper().clearOpenHumansQueue()
RxBus.send(OpenHumansFragment.UpdateViewEvent)
} }
private fun copyExistingDataToQueue() { private fun copyExistingDataToQueue() {
copyDisposable?.dispose() copyDisposable?.dispose()
var currentProgress = 0L
var maxProgress = 0L
copyDisposable = Completable.fromCallable { MainApp.getDbHelper().clearOpenHumansQueue() } copyDisposable = Completable.fromCallable { MainApp.getDbHelper().clearOpenHumansQueue() }
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allBgReadings) }) .andThen(Single.defer { Single.just(MainApp.getDbHelper().countOfAllRows) })
.map { queueBGReading(it) } .doOnSuccess { maxProgress = it }
.flatMapObservable { Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allBgReadings) } }
.map { queueBGReading(it); showOngoingNotification(maxProgress, ++currentProgress) }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allCareportalEvents) }) .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allCareportalEvents) })
.map { queueCareportalEvent(it) } .map { queueCareportalEvent(it); showOngoingNotification(maxProgress, ++currentProgress) }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allExtendedBoluses) }) .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allExtendedBoluses) })
.map { queueExtendedBolus(it) } .map { queueExtendedBolus(it); showOngoingNotification(maxProgress, ++currentProgress) }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allProfileSwitches) }) .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allProfileSwitches) })
.map { queueProfileSwitch(it) } .map { queueProfileSwitch(it); showOngoingNotification(maxProgress, ++currentProgress) }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTDDs) }) .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTDDs) })
.map { queueTotalDailyDose(it) } .map { queueTotalDailyDose(it); showOngoingNotification(maxProgress, ++currentProgress) }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTemporaryBasals) }) .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTemporaryBasals) })
.map { queueTemporaryBasal(it) } .map { queueTemporaryBasal(it); showOngoingNotification(maxProgress, ++currentProgress) }
.ignoreElements() .ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTempTargets) }) .andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allTempTargets) })
.map { queueTempTarget(it) } .map { queueTempTarget(it); showOngoingNotification(maxProgress, ++currentProgress) }
.ignoreElements() .ignoreElements()
.doOnSubscribe { .doOnSubscribe {
wakeLock.acquire() wakeLock.acquire(TimeUnit.MINUTES.toMillis(10))
showOngoingNotification() showOngoingNotification()
} }
.doOnComplete { .doOnComplete {
@ -305,12 +314,12 @@ object OpenHumansUploader : PluginBase(
.subscribe() .subscribe()
} }
private fun showOngoingNotification() { private fun showOngoingNotification(maxProgress: Long? = null, currentProgress: Long? = null) {
val notification = NotificationCompat.Builder(MainApp.instance(), "OpenHumans") val notification = NotificationCompat.Builder(MainApp.instance(), "OpenHumans")
.setContentTitle(MainApp.gs(R.string.finishing_open_humans_setup)) .setContentTitle(MainApp.gs(R.string.finishing_open_humans_setup))
.setContentText(MainApp.gs(R.string.this_may_take_a_while)) .setContentText(MainApp.gs(R.string.this_may_take_a_while))
.setStyle(NotificationCompat.BigTextStyle()) .setStyle(NotificationCompat.BigTextStyle())
.setProgress(0, 0, true) .setProgress(maxProgress?.toInt() ?: 0, currentProgress?.toInt() ?: 0, maxProgress == null || currentProgress == null)
.setOngoing(true) .setOngoing(true)
.setAutoCancel(false) .setAutoCancel(false)
.setSmallIcon(R.drawable.notif_icon) .setSmallIcon(R.drawable.notif_icon)
@ -340,7 +349,7 @@ object OpenHumansUploader : PluginBase(
notificationManager.notify(NOTIFICATION_ID, notification) notificationManager.notify(NOTIFICATION_ID, notification)
} }
fun uploadData() = gatherData() fun uploadData(): Completable = gatherData()
.flatMap { data -> refreshAccessTokensIfNeeded().map { accessToken -> accessToken to data } } .flatMap { data -> refreshAccessTokensIfNeeded().map { accessToken -> accessToken to data } }
.flatMap { uploadFile(it.first, it.second).andThen(Single.just(it.second)) } .flatMap { uploadFile(it.first, it.second).andThen(Single.just(it.second)) }
.flatMapCompletable { .flatMapCompletable {
@ -355,6 +364,7 @@ object OpenHumansUploader : PluginBase(
handleSignOut() handleSignOut()
} }
} }
.doOnComplete { RxBus.send(OpenHumansFragment.UpdateQueueEvent) }
private fun uploadFile(accessToken: String, uploadData: UploadData) = Completable.defer { private fun uploadFile(accessToken: String, uploadData: UploadData) = Completable.defer {
openHumansAPI.prepareFileUpload(accessToken, uploadData.fileName, uploadData.metadata) openHumansAPI.prepareFileUpload(accessToken, uploadData.fileName, uploadData.metadata)
@ -459,10 +469,6 @@ object OpenHumansUploader : PluginBase(
} }
private fun handleSignOut() { private fun handleSignOut() {
isSetup = false
projectMemberId = null
oAuthTokens = null
cancelWorker()
val notification = NotificationCompat.Builder(MainApp.instance(), "OpenHumans") val notification = NotificationCompat.Builder(MainApp.instance(), "OpenHumans")
.setContentTitle(MainApp.gs(R.string.you_have_been_signed_out_of_open_humans)) .setContentTitle(MainApp.gs(R.string.you_have_been_signed_out_of_open_humans))
.setContentText(MainApp.gs(R.string.click_here_to_sign_in_again_if_this_wasnt_on_purpose)) .setContentText(MainApp.gs(R.string.click_here_to_sign_in_again_if_this_wasnt_on_purpose))
@ -479,6 +485,7 @@ object OpenHumansUploader : PluginBase(
)) ))
.build() .build()
NotificationManagerCompat.from(MainApp.instance()).notify(NOTIFICATION_ID, notification) NotificationManagerCompat.from(MainApp.instance()).notify(NOTIFICATION_ID, notification)
logout()
} }
private fun cancelWorker() { private fun cancelWorker() {

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector android:height="100.5272dp" android:viewportHeight="108.36626"
android:viewportWidth="107.79796" android:width="100dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ff9161" android:pathData="m59.75,62.316c5.179,-2.256 8.801,-7.417 8.801,-13.427 0,-8.086 -6.555,-14.641 -14.641,-14.641 -8.086,0 -14.641,6.555 -14.641,14.641 0,6.01 3.622,11.171 8.801,13.427 -7.849,1.589 -14.555,6.318 -18.76,12.817 5.968,6.896 14.774,11.272 24.589,11.272 9.821,0 18.633,-4.382 24.601,-11.286 -4.205,-6.491 -10.907,-11.215 -18.75,-12.803z"/>
<path android:fillColor="#ff9161" android:pathData="M21.689,33.33 L10.002,21.643c-5.155,7 -8.677,15.271 -10.002,24.25l16.523,0c0.968,-4.535 2.741,-8.776 5.166,-12.563z"/>
<path android:fillColor="#ff9161" android:pathData="m91.275,45.893l16.523,0C106.473,36.909 102.947,28.634 97.787,21.631L86.101,33.317c2.429,3.79 4.205,8.035 5.174,12.576z"/>
<path android:fillColor="#ff9161" android:pathData="M86.305,10.106C79.304,4.91 71.02,1.351 62.022,0l0,15.422l13.059,5.908z"/>
<path android:fillColor="#ff9161" android:pathData="M45.754,15.339L45.754,0.003c-8.995,1.354 -17.276,4.915 -24.274,10.113l10.963,10.963z"/>
<path android:fillColor="#4bc0c7" android:pathData="m26.558,80.554c-4.881,-5.002 -8.405,-11.333 -9.971,-18.394l-16.546,0c4.001,26.128 26.629,46.206 53.858,46.206 27.229,0 49.857,-20.077 53.858,-46.206l-16.546,0c-1.564,7.053 -5.082,13.378 -9.955,18.378 -6.946,7.127 -16.643,11.56 -27.357,11.56 -10.706,0 -20.396,-4.427 -27.341,-11.544z"/>
</vector>

View file

@ -14,6 +14,22 @@
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/uploaded_data"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Headline" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/the_following_data_will_be_uploaded_to_your_open_humans_account"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/terms_of_use" android:text="@string/terms_of_use"
android:textAlignment="center" android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Headline" /> android:textAppearance="@style/TextAppearance.AppCompat.Headline" />
@ -21,7 +37,7 @@
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="8dp"
android:text="@string/open_humans_terms" android:text="@string/open_humans_terms"
android:textAlignment="center" android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> android:textAppearance="@style/TextAppearance.AppCompat.Body1" />

View file

@ -1,14 +1,63 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView 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:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical"> android:orientation="vertical">
<Button <ImageView
android:id="@+id/login" android:layout_width="200dp"
android:text="@string/login" android:layout_height="200dp"
android:layout_width="wrap_content" android:contentDescription="@null"
android:layout_height="wrap_content" /> android:paddingBottom="16dp"
app:srcCompat="@drawable/open_humans" />
<TextView
android:id="@+id/member_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
tools:text="Project Member ID: 5151515" />
<TextView
android:layout_marginTop="8dp"
android:id="@+id/queue_size"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
tools:text="Queue Size: 155" />
<TextView
android:layout_marginTop="8dp"
android:id="@+id/worker_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
tools:text="Worker State: Running" />
<Button
android:layout_marginTop="16dp"
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/login" />
<Button
android:id="@+id/logout"
android:layout_marginTop="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/logout" />
</LinearLayout> </LinearLayout>
</ScrollView>

View file

@ -1709,7 +1709,11 @@
<string name="open_humans_terms">This is an open source tool that will copy your data to Open Humans. We retain no rights to share your data with third parties without your explicit authorization. The data the project and app receive are identified via a random user ID and will only be securely transmitted to an Open Humans account with your authorization of that process. You can stop uploading and delete your upload data at any time via www.openhumans.org.</string> <string name="open_humans_terms">This is an open source tool that will copy your data to Open Humans. We retain no rights to share your data with third parties without your explicit authorization. The data the project and app receive are identified via a random user ID and will only be securely transmitted to an Open Humans account with your authorization of that process. You can stop uploading and delete your upload data at any time via www.openhumans.org.</string>
<string name="i_understand_and_agree">I understand and agree</string> <string name="i_understand_and_agree">I understand and agree</string>
<string name="login">Login</string> <string name="login">Login</string>
<string name="logout">Logout</string>
<string name="project_member_id">Project Member ID: %s</string>
<string name="queue_size">Queue Size: %d</string>
<string name="terms_of_use">Terms of Use</string> <string name="terms_of_use">Terms of Use</string>
<string name="not_logged_in">Not logged in</string>
<string name="you_need_to_accept_the_of_use_first">You need to accept the terms of use first.</string> <string name="you_need_to_accept_the_of_use_first">You need to accept the terms of use first.</string>
<string name="successfully_logged_in">Successfully logged in</string> <string name="successfully_logged_in">Successfully logged in</string>
<string name="setup_will_continue_in_background">The setup will be completed in background now. Thanks for uploading your data.</string> <string name="setup_will_continue_in_background">The setup will be completed in background now. Thanks for uploading your data.</string>
@ -1720,4 +1724,7 @@
<string name="click_here_to_sign_in_again_if_this_wasnt_on_purpose">Click here to sign in a again if this wasn\'t on purpose.</string> <string name="click_here_to_sign_in_again_if_this_wasnt_on_purpose">Click here to sign in a again if this wasn\'t on purpose.</string>
<string name="only_upload_if_connected_to_wifi">Only upload if connected to WiFi</string> <string name="only_upload_if_connected_to_wifi">Only upload if connected to WiFi</string>
<string name="only_upload_if_charging">Only upload if charging</string> <string name="only_upload_if_charging">Only upload if charging</string>
<string name="worker_state">Worker State: %s</string>
<string name="uploaded_data">Uploaded Data</string>
<string name="the_following_data_will_be_uploaded_to_your_open_humans_account">The following data will be uploaded to your Open Humans account: Glucose values, careportal events (except notes), extended boluses, profile switches, total daily doses, temporary basals, temp targets, preferences, application version, device model and screen dimensions. Secret or private information such as your Nightscout URL oder API secret will not be uploaded.</string>
</resources> </resources>