ProfileFunction WIP

This commit is contained in:
Milos Kozak 2019-12-26 23:26:00 +01:00
parent 3654b0b66f
commit 12253007f1
20 changed files with 170 additions and 40 deletions

View file

@ -25,7 +25,6 @@ import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRebuildTabs;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin;
import info.nightscout.androidaps.utils.LocaleHelper;
import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.SP;

View file

@ -6,6 +6,8 @@ import dagger.Binds
import dagger.Module
import dagger.Provides
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImplementation
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.resources.ResourceHelperImplementation
import info.nightscout.androidaps.utils.sharedPreferences.SP
@ -21,6 +23,12 @@ class AppModule {
return SPImplementation(PreferenceManager.getDefaultSharedPreferences(context))
}
@Provides
@Singleton
fun provideProfileFunction(sp : SP): ProfileFunction {
return ProfileFunctionImplementation(sp)
}
@Provides
@Singleton
fun provideResources(mainApp: MainApp): ResourceHelper {

View file

@ -97,7 +97,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.careportal_profileswitch), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), Runnable {
ProfileFunctions.doProfileSwitch(profileStore, profile, duration.toInt(), percent, timeShift, eventTime)
ProfileFunctions.getInstance().doProfileSwitch(profileStore, profile, duration.toInt(), percent, timeShift, eventTime)
})
}
return true

View file

@ -43,7 +43,7 @@ class TempBasalDialog : DialogFragmentWithDate() {
super.onViewCreated(view, savedInstanceState)
val pumpDescription = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription ?: return
val profile = ProfileFunctions.getInstance().profile ?: return
val profile = ProfileFunctions.getInstance().getProfile() ?: return
val maxTempPercent = pumpDescription.maxTempPercent.toDouble()
val tempPercentStep = pumpDescription.tempPercentStep.toDouble()
@ -73,7 +73,7 @@ class TempBasalDialog : DialogFragmentWithDate() {
var percent = 0
var absolute = 0.0
val durationInMinutes = SafeParse.stringToInt(actions_tempbasal_duration.text)
val profile = ProfileFunctions.getInstance().profile ?: return false
val profile = ProfileFunctions.getInstance().getProfile() ?: return false
val actions: LinkedList<String> = LinkedList()
if (isPercentPump) {
val basalPercentInput = SafeParse.stringToInt(actions_tempbasal_basalpercentinput.text)

View file

@ -194,7 +194,7 @@ class WizardDialog : DialogFragment() {
}
private fun initDialog() {
val profile = ProfileFunctions.getInstance().profile
val profile = ProfileFunctions.getInstance().getProfile()
val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile
if (profile == null || profileStore == null) {
@ -249,8 +249,8 @@ class WizardDialog : DialogFragment() {
var profileName = treatments_wizard_profile.selectedItem.toString()
val specificProfile: Profile?
if (profileName == MainApp.gs(R.string.active)) {
specificProfile = ProfileFunctions.getInstance().profile
profileName = ProfileFunctions.getInstance().profileName
specificProfile = ProfileFunctions.getInstance().getProfile()
profileName = ProfileFunctions.getInstance().getProfileName() ?: return
} else
specificProfile = profileStore.getSpecificProfile(profileName)

View file

@ -2,11 +2,14 @@ package info.nightscout.androidaps.plugins.configBuilder;
import androidx.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import javax.inject.Inject;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.events.EventAppInitialized;
@ -22,6 +25,7 @@ import info.nightscout.androidaps.interfaces.SensitivityInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin;
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin;
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
@ -53,6 +57,9 @@ public class ConfigBuilderPlugin extends PluginBase {
private CommandQueue commandQueue = new CommandQueue();
@Inject
LocalProfilePlugin localProfilePlugin;
public ConfigBuilderPlugin() {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
@ -237,9 +244,10 @@ public class ConfigBuilderPlugin extends PluginBase {
return activeBgSource;
}
@Nullable
@NotNull
public ProfileInterface getActiveProfileInterface() {
return activeProfile;
if (activeProfile != null) return activeProfile;
else return localProfilePlugin;
}
@Nullable

View file

@ -0,0 +1,19 @@
package info.nightscout.androidaps.plugins.configBuilder
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.ProfileStore
import info.nightscout.androidaps.db.ProfileSwitch
interface ProfileFunction {
fun getProfileName(): String?
fun getProfileName(customized: Boolean): String
fun getProfileNameWithDuration(): String
fun getProfileName(time: Long, customized: Boolean, showRemainingTime: Boolean): String
fun isProfileValid(from: String): Boolean
fun getProfile(): Profile?
fun getUnits(): String
fun getProfile(time: Long): Profile?
fun prepareProfileSwitch(profileStore: ProfileStore, profileName: String, duration: Int, percentage: Int, timeShift: Int, date: Long): ProfileSwitch
fun doProfileSwitch(profileStore: ProfileStore, profileName: String, duration: Int, percentage: Int, timeShift: Int, date: Long)
fun doProfileSwitch(duration: Int, percentage: Int, timeShift: Int)
}

View file

@ -0,0 +1,80 @@
package info.nightscout.androidaps.plugins.configBuilder
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.data.ProfileStore
import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.db.Source
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.sharedPreferences.SP
import java.security.spec.InvalidParameterSpecException
import javax.inject.Inject
import javax.inject.Singleton
class ProfileFunctionImplementation constructor(private val sp: SP) : ProfileFunction {
override fun getProfileName(): String =
getProfileName(System.currentTimeMillis(), customized = true, showRemainingTime = false)
override fun getProfileName(customized: Boolean): String =
getProfileName(System.currentTimeMillis(), customized, showRemainingTime = false)
override fun getProfileName(time: Long, customized: Boolean, showRemainingTime: Boolean): String =
ProfileFunctions.getInstance().getProfileName(time, customized, showRemainingTime)
override fun getProfileNameWithDuration(): String =
getProfileName(System.currentTimeMillis(), customized = true, showRemainingTime = true)
override fun isProfileValid(from: String): Boolean =
getProfile()?.isValid(from) ?: false
override fun getProfile(): Profile? {
return ProfileFunctions.getInstance().getProfile()
}
override fun getProfile(time: Long): Profile? =
getProfile(System.currentTimeMillis())
override fun getUnits(): String =
sp.getString(R.string.key_units, Constants.MGDL)
override fun prepareProfileSwitch(profileStore: ProfileStore, profileName: String, duration: Int, percentage: Int, timeShift: Int, date: Long): ProfileSwitch {
val profile = profileStore.getSpecificProfile(profileName)
?: throw InvalidParameterSpecException(profileName)
val profileSwitch = ProfileSwitch()
profileSwitch.date = date
profileSwitch.source = Source.USER
profileSwitch.profileName = profileName
profileSwitch.profileJson = profile.data.toString()
profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().activeProfileInterface::class.java.name
profileSwitch.durationInMinutes = duration
profileSwitch.isCPP = percentage != 100 || timeShift != 0
profileSwitch.timeshift = timeShift
profileSwitch.percentage = percentage
return profileSwitch
}
override fun doProfileSwitch(profileStore: ProfileStore, profileName: String, duration: Int, percentage: Int, timeShift: Int, date: Long) {
val profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeShift, date)
TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch)
if (percentage == 90 && duration == 10)
sp.putBoolean(R.string.key_objectiveuseprofileswitch, true)
}
override fun doProfileSwitch(duration: Int, percentage: Int, timeShift: Int) {
getProfile()?.let {
val profileSwitch = ProfileSwitch()
profileSwitch.date = System.currentTimeMillis()
profileSwitch.source = Source.USER
profileSwitch.profileName = ProfileFunctions.getInstance().getProfileName(System.currentTimeMillis(), customized = false, showRemainingTime = false)
profileSwitch.profileJson = it.data.toString()
profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().activeProfileInterface::class.java.name
profileSwitch.durationInMinutes = duration
profileSwitch.isCPP = percentage != 100 || timeShift != 0
profileSwitch.timeshift = timeShift
profileSwitch.percentage = percentage
TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch)
}
}
}

View file

@ -7,6 +7,7 @@ import androidx.annotation.Nullable;
import com.google.firebase.analytics.FirebaseAnalytics;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -14,6 +15,7 @@ import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.activities.ErrorHelperActivity;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.db.ProfileSwitch;
@ -24,7 +26,6 @@ import info.nightscout.androidaps.interfaces.ProfileInterface;
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.bus.RxBus;
import info.nightscout.androidaps.activities.ErrorHelperActivity;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DateUtil;
@ -33,7 +34,7 @@ import info.nightscout.androidaps.utils.SP;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
public class ProfileFunctions {
public class ProfileFunctions implements ProfileFunction {
private static Logger log = LoggerFactory.getLogger(L.PROFILE);
private CompositeDisposable disposable = new CompositeDisposable();
@ -75,18 +76,22 @@ public class ProfileFunctions {
);
}
@NotNull
public String getProfileName() {
return getProfileName(System.currentTimeMillis(), true, false);
}
@NotNull
public String getProfileName(boolean customized) {
return getProfileName(System.currentTimeMillis(), customized, false);
}
@NotNull
public String getProfileNameWithDuration() {
return getProfileName(System.currentTimeMillis(), true, true);
}
@NotNull
public String getProfileName(long time, boolean customized, boolean showRemainingTime) {
String profileName = MainApp.gs(R.string.noprofileselected);
@ -114,7 +119,7 @@ public class ProfileFunctions {
return profileName;
}
public boolean isProfileValid(String from) {
public boolean isProfileValid(@NotNull String from) {
Profile profile = getProfile();
return profile != null && profile.isValid(from);
}
@ -124,6 +129,12 @@ public class ProfileFunctions {
return getProfile(System.currentTimeMillis());
}
@NotNull
public String getUnits() {
return getSystemUnits();
}
@NotNull
public static String getSystemUnits() {
return SP.getString(R.string.key_units, Constants.MGDL);
}
@ -156,7 +167,8 @@ public class ProfileFunctions {
return null;
}
public static ProfileSwitch prepareProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift, long date) {
@NotNull
public ProfileSwitch prepareProfileSwitch(@NotNull final ProfileStore profileStore, @NotNull final String profileName, final int duration, final int percentage, final int timeShift, long date) {
ProfileSwitch profileSwitch = new ProfileSwitch();
profileSwitch.date = date;
profileSwitch.source = Source.USER;
@ -164,20 +176,20 @@ public class ProfileFunctions {
profileSwitch.profileJson = profileStore.getSpecificProfile(profileName).getData().toString();
profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getClass().getName();
profileSwitch.durationInMinutes = duration;
profileSwitch.isCPP = percentage != 100 || timeshift != 0;
profileSwitch.timeshift = timeshift;
profileSwitch.isCPP = percentage != 100 || timeShift != 0;
profileSwitch.timeshift = timeShift;
profileSwitch.percentage = percentage;
return profileSwitch;
}
public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift, final long date) {
ProfileSwitch profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeshift, date);
public void doProfileSwitch(@NotNull final ProfileStore profileStore, @NotNull final String profileName, final int duration, final int percentage, final int timeShift, final long date) {
ProfileSwitch profileSwitch = prepareProfileSwitch(profileStore, profileName, duration, percentage, timeShift, date);
TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch);
if (percentage == 90 && duration == 10)
SP.putBoolean(R.string.key_objectiveuseprofileswitch, true);
}
public static void doProfileSwitch(final int duration, final int percentage, final int timeshift) {
public void doProfileSwitch(final int duration, final int percentage, final int timeShift) {
ProfileSwitch profileSwitch = TreatmentsPlugin.getPlugin().getProfileSwitchFromHistory(System.currentTimeMillis());
if (profileSwitch != null) {
profileSwitch = new ProfileSwitch();
@ -187,8 +199,8 @@ public class ProfileFunctions {
profileSwitch.profileJson = getInstance().getProfile().getData().toString();
profileSwitch.profilePlugin = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getClass().getName();
profileSwitch.durationInMinutes = duration;
profileSwitch.isCPP = percentage != 100 || timeshift != 0;
profileSwitch.timeshift = timeshift;
profileSwitch.isCPP = percentage != 100 || timeShift != 0;
profileSwitch.timeshift = timeShift;
profileSwitch.percentage = percentage;
TreatmentsPlugin.getPlugin().addToHistoryProfileSwitch(profileSwitch);
} else {

View file

@ -157,7 +157,7 @@ class ActionsFragment : Fragment() {
if (ConfigBuilderPlugin.getPlugin().activeProfileInterface?.profile != null) View.VISIBLE
else View.GONE
if (ProfileFunctions.getInstance().profile == null) {
if (ProfileFunctions.getInstance().getProfile() == null) {
actions_temptarget?.visibility = View.GONE
actions_extendedbolus?.visibility = View.GONE
actions_extendedbolus_cancel?.visibility = View.GONE

View file

@ -98,7 +98,7 @@ public class ActionProfileSwitch extends Action {
return;
}
ProfileFunctions.doProfileSwitch(profileStore, profileName, 0, 100, 0, DateUtil.now());
ProfileFunctions.getInstance().doProfileSwitch(profileStore, profileName, 0, 100, 0, DateUtil.now());
if (callback != null)
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
}

View file

@ -47,7 +47,7 @@ public class ActionProfileSwitchPercent extends Action {
@Override
public void doAction(Callback callback) {
ProfileFunctions.doProfileSwitch((int) duration.getValue(), (int) pct.getValue(), 0);
ProfileFunctions.getInstance().doProfileSwitch((int) duration.getValue(), (int) pct.getValue(), 0);
if (callback != null)
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
}

View file

@ -44,11 +44,11 @@ class EditActionDialog : DialogFragmentWithDate() {
return true
}
override fun onSaveInstanceState(bundle: Bundle) {
super.onSaveInstanceState(bundle)
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
action?.let {
bundle.putInt("actionPosition", actionPosition)
bundle.putString("action", it.toJSON())
savedInstanceState.putInt("actionPosition", actionPosition)
savedInstanceState.putString("action", it.toJSON())
}
}
}

View file

@ -704,7 +704,7 @@ public class NewNSTreatmentDialog extends AppCompatDialogFragment implements Vie
void createNSTreatment(JSONObject data) {
if (JsonHelper.safeGetString(data, "eventType", "").equals(CareportalEvent.PROFILESWITCH)) {
ProfileSwitch profileSwitch = ProfileFunctions.prepareProfileSwitch(
ProfileSwitch profileSwitch = ProfileFunctions.getInstance().prepareProfileSwitch(
profileStore,
JsonHelper.safeGetString(data, "profile"),
JsonHelper.safeGetInt(data, "duration"),

View file

@ -428,9 +428,15 @@ object SmsCommunicatorPlugin : PluginBase(PluginDescription()
receivedSms.processed = true
return
}
val profileName = ProfileFunctions.getInstance().getProfileName()
if (profileName == null) {
sendSMS(Sms(receivedSms.phoneNumber, R.string.notconfigured))
receivedSms.processed = true
return
}
val list = store.getProfileList()
if (splitted[1].toUpperCase(Locale.getDefault()) == "STATUS") {
sendSMS(Sms(receivedSms.phoneNumber, ProfileFunctions.getInstance().profileName))
sendSMS(Sms(receivedSms.phoneNumber, profileName))
} else if (splitted[1].toUpperCase(Locale.getDefault()) == "LIST") {
if (list.isEmpty()) sendSMS(Sms(receivedSms.phoneNumber, R.string.invalidprofile))
else {
@ -459,7 +465,7 @@ object SmsCommunicatorPlugin : PluginBase(PluginDescription()
val finalPercentage = percentage
messageToConfirm = AuthRequest(this, receivedSms, reply, passCode, object : SmsAction(list[pindex - 1] as String, finalPercentage) {
override fun run() {
ProfileFunctions.doProfileSwitch(store, list[pindex - 1] as String, 0, finalPercentage, 0, DateUtil.now())
ProfileFunctions.getInstance().doProfileSwitch(store, list[pindex - 1] as String, 0, finalPercentage, 0, DateUtil.now())
sendSMS(Sms(receivedSms.phoneNumber, R.string.profileswitchcreated))
}
})
@ -495,7 +501,7 @@ object SmsCommunicatorPlugin : PluginBase(PluginDescription()
var tempBasalPct = SafeParse.stringToInt(StringUtils.removeEnd(splitted[1], "%"))
var duration = 30
if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2])
val profile = ProfileFunctions.getInstance().profile
val profile = ProfileFunctions.getInstance().getProfile()
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, R.string.noprofile))
else if (tempBasalPct == 0 && splitted[1] != "0%") sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else if (duration == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
@ -527,7 +533,7 @@ object SmsCommunicatorPlugin : PluginBase(PluginDescription()
var tempBasal = SafeParse.stringToDouble(splitted[1])
var duration = 30
if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2])
val profile = ProfileFunctions.getInstance().profile
val profile = ProfileFunctions.getInstance().getProfile()
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, R.string.noprofile))
else if (tempBasal == 0.0 && splitted[1] != "0") sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
else if (duration == 0) sendSMS(Sms(receivedSms.phoneNumber, R.string.wrongformat))
@ -644,7 +650,7 @@ object SmsCommunicatorPlugin : PluginBase(PluginDescription()
replyText += "\n" + ConfigBuilderPlugin.getPlugin().activePump?.shortStatus(true)
lastRemoteBolusTime = DateUtil.now()
if (isMeal) {
ProfileFunctions.getInstance().profile?.let { currentProfile ->
ProfileFunctions.getInstance().getProfile()?.let { currentProfile ->
var eatingSoonTTDuration = SP.getInt(R.string.key_eatingsoon_duration, Constants.defaultEatingSoonTTDuration)
eatingSoonTTDuration =
if (eatingSoonTTDuration > 0) eatingSoonTTDuration

View file

@ -679,7 +679,7 @@ public class ActionStringHandler {
//send profile to pumpe
new NewNSTreatmentDialog(); //init
ProfileFunctions.doProfileSwitch(0, percentage, timeshift);
ProfileFunctions.getInstance().doProfileSwitch(0, percentage, timeshift);
}
private static void generateTempTarget(int duration, double low, double high) {

View file

@ -42,7 +42,7 @@ class NSProfileFragment : Fragment() {
activity?.let { activity ->
OKDialog.showConfirmation(activity, MainApp.gs(R.string.nsprofile),
MainApp.gs(R.string.activate_profile) + ": " + name + " ?", Runnable {
ProfileFunctions.doProfileSwitch(store, name, 0, 100, 0, DateUtil.now())
ProfileFunctions.getInstance().doProfileSwitch(store, name, 0, 100, 0, DateUtil.now())
})
}
}
@ -121,7 +121,7 @@ class NSProfileFragment : Fragment() {
nsprofile_spinner.adapter = adapter
// set selected to actual profile
for (p in profileList.indices) {
if (profileList[p] == ProfileFunctions.getInstance().profileName)
if (profileList[p] == ProfileFunctions.getInstance().getProfileName())
nsprofile_spinner.setSelection(p)
}
profileview_noprofile.visibility = View.GONE

View file

@ -90,7 +90,7 @@ class KeepAliveReceiver : BroadcastReceiver() {
private fun checkPump() {
val pump = ConfigBuilderPlugin.getPlugin().activePump
val profile = ProfileFunctions.getInstance().profile
val profile = ProfileFunctions.getInstance().getProfile()
if (pump != null && profile != null) {
val lastConnection = pump.lastDataTime()
val isStatusOutdated = lastConnection + STATUS_UPDATE_FREQUENCY < System.currentTimeMillis()

View file

@ -262,7 +262,7 @@ class BolusWizard @JvmOverloads constructor(val profile: Profile,
}
fun confirmAndExecute(context: Context) {
val profile = ProfileFunctions.getInstance().profile ?: return
val profile = ProfileFunctions.getInstance().getProfile() ?: return
val pump = ConfigBuilderPlugin.getPlugin().activePump ?: return
if (calculatedTotalInsulin > 0.0 || carbs > 0.0) {

View file

@ -62,13 +62,11 @@ object OKDialog {
}
@JvmStatic
@JvmOverloads
fun showConfirmation(activity: Activity, message: String, ok: Runnable?) {
showConfirmation(activity, MainApp.gs(R.string.confirmation), message, ok, null)
}
@JvmStatic
@JvmOverloads
fun showConfirmation(activity: Activity, message: Spanned, ok: Runnable?) {
showConfirmation(activity, MainApp.gs(R.string.confirmation), message, ok, null)
}