diff --git a/.travis.yml b/.travis.yml index e8e27f09b..774ffc332 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,23 +14,14 @@ android: # The BuildTools version used by your project # per travis-ci issue #5036, add '-tools' to use build-tools-23.0.2 - tools - - build-tools-23.0.2 + - build-tools-28.0.3 # The SDK version used to compile your project - - android-23 - - # Additional components go here. - - extra-android-support - - extra-android-m2repository + - android-28 # Specify at least one system image, # if you need to run emulator(s) during your tests -# Required to run retrolambda -before_install: - - export JAVA8_HOME=/usr/lib/jvm/java-8-oracle - - export JAVA_HOME=$JAVA8_HOME - before_script: # Tests crash if a local.properties file isn't present; this file is not kept # under version control. Create an empty local.properties for testing. diff --git a/authentication/.gitignore b/authentication/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/authentication/.gitignore @@ -0,0 +1 @@ +/build diff --git a/authentication/build.gradle b/authentication/build.gradle new file mode 100644 index 000000000..db77370e9 --- /dev/null +++ b/authentication/build.gradle @@ -0,0 +1,166 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +apply plugin: 'com.github.dcendents.android-maven' +apply plugin: 'com.jfrog.bintray' + +version = research_stack_version + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 19 + targetSdkVersion 28 + versionCode 1 + versionName version + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + resourcePrefix 'rsfa_' + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +Properties properties = new Properties() +properties.load(project.rootProject.file('local.properties').newDataInputStream()) + +ext { + bintrayRepo = 'ResearchStack' + bintrayName = 'Authentication' + + publishedGroupId = 'org.researchstack' + libraryName = 'Authentication' + artifact = 'authentication' + + libraryDescription = 'Authentication' + + siteUrl = 'https://researchstack.org' + gitUrl = 'https://github.com/ResearchStack/ResearchStack.git' + + libraryVersion = version + + userOrgName = 'researchstack' + developerId = properties.getProperty("bintray.user") + developerName = properties.getProperty("bintray.developerName") + developerEmail = properties.getProperty("bintray.developerEmail") + + licenseName = 'The Apache Software License, Version 2.0' + licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + allLicenses = ["Apache-2.0"] +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.legacy:legacy-preference-v14:1.0.0' + implementation 'com.google.android.material:material:1.0.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation project(':foundation') + + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} + +group = publishedGroupId // Maven Group ID for the artifact + +install { + repositories.mavenInstaller { + // This generates POM.xml with proper parameters + pom { + project { + packaging 'aar' + groupId publishedGroupId + artifactId artifact + + // Add your description here + name libraryName + description libraryDescription + url siteUrl + + // Set your license + licenses { + license { + name licenseName + url licenseUrl + } + } + developers { + developer { + id developerId + name developerName + email developerEmail + } + } + scm { + connection gitUrl + developerConnection gitUrl + url siteUrl + } + } + } + } +} + +if (project.hasProperty("android")) { // Android libraries + task sourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs + } + + task javadoc(type: Javadoc) { + failOnError false + source = android.sourceSets.main.java.srcDirs + } + + afterEvaluate { + javadoc.classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + javadoc.classpath += files(android.libraryVariants.collect { variant -> + variant.javaCompile.classpath.files + }) + } +} else { // Java libraries + task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from sourceSets.main.allSource + } +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives javadocJar + archives sourcesJar +} + +bintray { + user = properties.getProperty("bintray.user") + key = properties.getProperty("bintray.apikey") + + configurations = ['archives'] + pkg { + repo = bintrayRepo + name = bintrayName + userOrg = userOrgName + desc = libraryDescription + websiteUrl = siteUrl + vcsUrl = gitUrl + licenses = allLicenses + publish = true + } +} diff --git a/authentication/proguard-rules.pro b/authentication/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/authentication/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/authentication/src/androidTest/java/org/researchstack/feature/authentication/ExampleInstrumentedTest.java b/authentication/src/androidTest/java/org/researchstack/feature/authentication/ExampleInstrumentedTest.java new file mode 100644 index 000000000..fb5163b05 --- /dev/null +++ b/authentication/src/androidTest/java/org/researchstack/feature/authentication/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package org.researchstack.feature.authentication; + +import android.content.Context; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("org.researchstack.feature.authentication.test", appContext.getPackageName()); + } +} diff --git a/authentication/src/main/AndroidManifest.xml b/authentication/src/main/AndroidManifest.xml new file mode 100644 index 000000000..429932ed6 --- /dev/null +++ b/authentication/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/authentication/src/main/java/org/researchstack/feature/authentication/Authenticator.kt b/authentication/src/main/java/org/researchstack/feature/authentication/Authenticator.kt new file mode 100644 index 000000000..19f942ce4 --- /dev/null +++ b/authentication/src/main/java/org/researchstack/feature/authentication/Authenticator.kt @@ -0,0 +1,24 @@ +package org.researchstack.feature.authentication + +import androidx.core.os.CancellationSignal + +open abstract class Authenticator> { + + open class AuthenticationResult { + + } + + open class AuthenticationCallback { + open fun onAuthenticationError(errorCode: Int, errString: String) {} + + open fun onAuthenticationFailed() {} + + open fun onAuthenticationHelp(helpCode: Int, helpString: String) {} + + open fun onAuthenticationSucceeded(result: Result) {} + } + + abstract fun isRegistered(): Boolean + abstract fun authenticate(cancel: CancellationSignal, callback: Callback) + +} \ No newline at end of file diff --git a/authentication/src/main/java/org/researchstack/feature/authentication/pincode/PasscodeAuthenticator.kt b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/PasscodeAuthenticator.kt new file mode 100644 index 000000000..3c2c1d766 --- /dev/null +++ b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/PasscodeAuthenticator.kt @@ -0,0 +1,106 @@ +package org.researchstack.feature.authentication.pincode + +import androidx.core.os.CancellationSignal +import java.lang.ref.WeakReference +import org.researchstack.feature.authentication.Authenticator + +//there are two things that need to be delegated +//how to store the passcode +//how to present the authentication +//also, we need to think about how one might register, but for now, let's assume that +//This class will need to define some type of storage backend +//this class will also need to figure out how to present the passcode authentication view + +//in one case, this would be a fragment and we would pass it a cancelation signal and a callback +//however, it's not exactly clear how the fragment would be presented. The activity / app delegate would be re + +//in another case, + + +open class PasscodeAuthenticator(val passcodeConfig: PinCodeConfig, val store: PasscodeStore): Authenticator() { + + open interface PasscodeStore { + fun hasPasscode(): Boolean + fun registerPasscode(passcode: String) + fun checkPasscode(passcode: String) + fun removePasscode() + fun changePasscode(oldPasscode: String, newPasscode: String) + } + + open interface PresentationDelegate { + //this should present a way to get a passcode + //note that in order to support combined passcode + biometric, this should probably only + //return a yes / no response + //therefore, we probably need to pass it some type of + fun presentPasscodeAuthentication(authenticator: PasscodeAuthenticator, cancel: CancellationSignal, callback: PasscodeAuthenticator.PasscodeAuthenticationCallback) + } + + companion object { + + } + + var presentationDelegate: WeakReference? = null + fun setPresentationDelegate(presentationDelegate: PresentationDelegate) { + this.presentationDelegate = WeakReference(presentationDelegate) + } + + open class PasscodeAuthenticationResult(): Authenticator.AuthenticationResult() { + + } + + open class PasscodeAuthenticationCallback(): Authenticator.AuthenticationCallback() { + open fun onForgotPasscode() {} + } + + sealed class PasscodeAuthenticatorException: RuntimeException { + + constructor() {} + constructor(detailMessage: String) : super(detailMessage) {} + constructor(detailMessage: String, throwable: Throwable) : super(detailMessage, throwable) {} + constructor(throwable: Throwable) : super(throwable) {} + + class InvalidPasscodeException : PasscodeAuthenticatorException { + constructor() {} + constructor(detailMessage: String) : super(detailMessage) {} + constructor(detailMessage: String, throwable: Throwable) : super(detailMessage, throwable) {} + constructor(throwable: Throwable) : super(throwable) {} + } + + class PasscodeExistsException : PasscodeAuthenticatorException { + constructor() {} + constructor(detailMessage: String) : super(detailMessage) {} + constructor(detailMessage: String, throwable: Throwable) : super(detailMessage, throwable) {} + constructor(throwable: Throwable) : super(throwable) {} + } + + class PasscodeDoesNotExistException : PasscodeAuthenticatorException { + constructor() {} + constructor(detailMessage: String) : super(detailMessage) {} + constructor(detailMessage: String, throwable: Throwable) : super(detailMessage, throwable) {} + constructor(throwable: Throwable) : super(throwable) {} + } + + class PresentationDelegateNotSetException : PasscodeAuthenticatorException { + constructor() {} + constructor(detailMessage: String) : super(detailMessage) {} + constructor(detailMessage: String, throwable: Throwable) : super(detailMessage, throwable) {} + constructor(throwable: Throwable) : super(throwable) {} + } + + } + + override fun isRegistered(): Boolean { + return this.store.hasPasscode() + } + + override fun authenticate(cancel: CancellationSignal, callback: PasscodeAuthenticationCallback) { + val delegate = this.presentationDelegate?.get() + if (delegate == null) { + throw PasscodeAuthenticatorException.PresentationDelegateNotSetException(); + } + else { + delegate.presentPasscodeAuthentication(this, cancel, callback) + } + } + +} \ No newline at end of file diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/PinCodeConfig.java b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/PinCodeConfig.java similarity index 94% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/PinCodeConfig.java rename to authentication/src/main/java/org/researchstack/feature/authentication/pincode/PinCodeConfig.java index b3a4be7d5..73e6f1b56 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/PinCodeConfig.java +++ b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/PinCodeConfig.java @@ -1,11 +1,11 @@ -package org.researchstack.backbone.storage.file; +package org.researchstack.feature.authentication.pincode; import android.text.InputFilter; import android.text.InputType; import android.text.format.DateUtils; -import org.researchstack.backbone.R; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.feature.authentication.R; +import org.researchstack.foundation.components.utils.TextUtils; /** * This class allows you to customize the type/strength of the pin code that the user must create to @@ -126,11 +126,11 @@ public int getInputType() { @Override public int getInputTypeStringId() { if (this == PinCodeType.Numeric) { - return R.string.rsb_pincode_enter_digit; + return R.string.rsfa_pincode_enter_digit; } else if (this == PinCodeType.Alphabetic) { - return R.string.rsb_pincode_enter_letter; + return R.string.rsfa_pincode_enter_letter; } else { - return R.string.rsb_pincode_enter_character; + return R.string.rsfa_pincode_enter_character; } } diff --git a/authentication/src/main/java/org/researchstack/feature/authentication/pincode/PinCodeConfigProvider.kt b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/PinCodeConfigProvider.kt new file mode 100644 index 000000000..60a94ed7f --- /dev/null +++ b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/PinCodeConfigProvider.kt @@ -0,0 +1,13 @@ +package org.researchstack.feature.authentication.pincode + +public class PinCodeConfigProvider() { + companion object { + private var _pinCodeConfig: PinCodeConfig? = null + fun config(pinCodeConfig: PinCodeConfig) { + this._pinCodeConfig = pinCodeConfig + } + + val pinCodeConfig: PinCodeConfig + get() = this._pinCodeConfig!! + } +} \ No newline at end of file diff --git a/authentication/src/main/java/org/researchstack/feature/authentication/pincode/SimplePasscodeStore.kt b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/SimplePasscodeStore.kt new file mode 100644 index 000000000..c0d95f144 --- /dev/null +++ b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/SimplePasscodeStore.kt @@ -0,0 +1,46 @@ +package org.researchstack.feature.authentication.pincode + +//This is for demonstration purposes only! +class SimplePasscodeStore: PasscodeAuthenticator.PasscodeStore { + + private var passcode: String? = null + + override fun hasPasscode(): Boolean { + return this.passcode != null + } + + override fun registerPasscode(passcode: String) { + if (this.hasPasscode()) { + throw PasscodeAuthenticator.PasscodeAuthenticatorException.PasscodeExistsException() + } + + this.passcode = passcode + } + + override fun checkPasscode(passcode: String) { + if (this.passcode == null) { + throw PasscodeAuthenticator.PasscodeAuthenticatorException.PasscodeDoesNotExistException() + } + + if (this.passcode != passcode) { + throw PasscodeAuthenticator.PasscodeAuthenticatorException.InvalidPasscodeException() + } + } + + override fun removePasscode() { + this.passcode == null + } + + override fun changePasscode(oldPasscode: String, newPasscode: String) { + + if (this.passcode == null) { + throw PasscodeAuthenticator.PasscodeAuthenticatorException.PasscodeDoesNotExistException() + } + + if (this.passcode != oldPasscode) { + throw PasscodeAuthenticator.PasscodeAuthenticatorException.InvalidPasscodeException() + } + + this.passcode = newPasscode + } +} \ No newline at end of file diff --git a/skin/src/main/java/org/researchstack/skin/step/PassCodeCreationStep.java b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/step/PassCodeCreationStep.java similarity index 70% rename from skin/src/main/java/org/researchstack/skin/step/PassCodeCreationStep.java rename to authentication/src/main/java/org/researchstack/feature/authentication/pincode/step/PassCodeCreationStep.java index 0e819774e..f10de7510 100644 --- a/skin/src/main/java/org/researchstack/skin/step/PassCodeCreationStep.java +++ b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/step/PassCodeCreationStep.java @@ -1,7 +1,7 @@ -package org.researchstack.skin.step; +package org.researchstack.feature.authentication.pincode.step; -import org.researchstack.backbone.step.Step; -import org.researchstack.skin.ui.layout.SignUpPinCodeCreationStepLayout; +import org.researchstack.feature.authentication.pincode.ui.SignUpPinCodeCreationStepLayout; +import org.researchstack.foundation.core.models.step.Step; public class PassCodeCreationStep extends Step { diff --git a/authentication/src/main/java/org/researchstack/feature/authentication/pincode/ui/PasscodeAuthenticationFragment.kt b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/ui/PasscodeAuthenticationFragment.kt new file mode 100644 index 000000000..e4a2f8483 --- /dev/null +++ b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/ui/PasscodeAuthenticationFragment.kt @@ -0,0 +1,146 @@ +package org.researchstack.feature.authentication.pincode.ui + +import android.content.Context +import android.graphics.Color +import android.os.AsyncTask +import android.os.Build +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.text.Editable +import android.text.TextWatcher +import android.view.ContextThemeWrapper +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager +import android.widget.EditText +import android.widget.TextView +import org.researchstack.feature.authentication.R +import org.researchstack.feature.authentication.pincode.PasscodeAuthenticator +import org.researchstack.foundation.components.utils.ThemeUtils + +open class PasscodeAuthenticationFragment: androidx.fragment.app.Fragment() { + + open class AuthenticationCallback { + open fun onAuthenticationFailed() {} + open fun onAuthenticationSucceeded() {} + } + + companion object { + fun newInstance( + authenticator: PasscodeAuthenticator, + callback: AuthenticationCallback + ): PasscodeAuthenticationFragment { + val fragment = PasscodeAuthenticationFragment() + fragment.authenticator = authenticator + fragment.callback = callback + return fragment + } + } + + private var authenticator: PasscodeAuthenticator? = null + private var callback: AuthenticationCallback? = null + private var toggleKeyboardAction: ((Boolean) -> Unit)? = null + + override open fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + + // Show pincode layout + val authenticator = this.authenticator!! + val config = authenticator.passcodeConfig + + val themeResId = ThemeUtils.getPassCodeTheme(this.activity as Context) + val context = ContextThemeWrapper(this.activity, themeResId) + val pinCodeLayout = PinCodeLayout(context) + pinCodeLayout.setBackgroundColor(Color.WHITE) + + val errorColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + resources.getColor(R.color.rsf_error, context.theme) + } else { + resources.getColor(R.color.rsf_error) + } + + val summary = pinCodeLayout.findViewById(R.id.text) as TextView + val pincode = pinCodeLayout.findViewById(R.id.pincode) as EditText + + this.toggleKeyboardAction = { enable -> + pincode.isEnabled = enable + pincode.setText("") + pincode.requestFocus() + if (enable) { + val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.showSoftInput(pincode, InputMethodManager.SHOW_FORCED) + } + } + + val pinCodeWatcher = object: TextWatcher { + //JDK - 4/13/19 + //It appears that Kotlin object expressions that implement interfaces + //MUST implement all methods and specify the 'override' modifier + override fun afterTextChanged(s: Editable?) { + //JDK - 4/13/19 + //do nothing + } + + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { + //JDK - 4/13/19 + //do nothing + } + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + + if (summary.currentTextColor == errorColor) { + summary.setTextColor(ThemeUtils.getTextColorPrimary(context)) + pinCodeLayout.resetSummaryText() + } + + val fullLengthPin: String? = s?.toString()?.let { pin -> + //check to see if pin is the right length + if (pin.length == config.pinLength) pin else null + } + + if (fullLengthPin != null) { + + pincode.isEnabled = false + pinCodeLayout.showProgress(true) + //check to see if pin matches + + class CheckPinCodeTask(val pinCode: String) : AsyncTask() { + override fun doInBackground(vararg params: Void?): Boolean { + try { + authenticator.store.checkPasscode(pinCode) + return true + } + catch (e: PasscodeAuthenticator.PasscodeAuthenticatorException) { + e.printStackTrace() + return false + } + } + + override fun onPostExecute(result: Boolean) { + + if (result) { + callback!!.onAuthenticationSucceeded() + } + else { + toggleKeyboardAction?.invoke(true) + summary.setText(R.string.rsfa_pincode_enter_error) + summary.setTextColor(errorColor) + pinCodeLayout.showProgress(false) + callback!!.onAuthenticationFailed() + } + } + + } + + CheckPinCodeTask(fullLengthPin).execute() + + } + } + } + + pincode.addTextChangedListener(pinCodeWatcher) + + return pinCodeLayout + } + +} \ No newline at end of file diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/views/PinCodeLayout.java b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/ui/PinCodeLayout.java similarity index 79% rename from backbone/src/main/java/org/researchstack/backbone/ui/views/PinCodeLayout.java rename to authentication/src/main/java/org/researchstack/feature/authentication/pincode/ui/PinCodeLayout.java index b6c4a6518..f250866ea 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/views/PinCodeLayout.java +++ b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/ui/PinCodeLayout.java @@ -1,7 +1,7 @@ -package org.researchstack.backbone.ui.views; +package org.researchstack.feature.authentication.pincode.ui; import android.content.Context; -import android.support.annotation.CallSuper; +import androidx.annotation.CallSuper; import android.text.InputFilter; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -11,10 +11,10 @@ import android.widget.RelativeLayout; import android.widget.TextView; -import org.researchstack.backbone.R; -import org.researchstack.backbone.StorageAccess; -import org.researchstack.backbone.storage.file.PinCodeConfig; -import org.researchstack.backbone.utils.ViewUtils; +import org.researchstack.feature.authentication.R; +import org.researchstack.feature.authentication.pincode.PinCodeConfig; +import org.researchstack.feature.authentication.pincode.PinCodeConfigProvider; +import org.researchstack.foundation.components.utils.ViewUtils; import java.util.Arrays; @@ -44,13 +44,13 @@ public PinCodeLayout(Context context, AttributeSet attrs, int defStyleAttr) { @CallSuper protected void init() { - config = StorageAccess.getInstance().getPinCodeConfig(); + config = PinCodeConfigProvider.Companion.getPinCodeConfig(); imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - LayoutInflater.from(getContext()).inflate(R.layout.rsb_step_layout_pincode, this, true); + LayoutInflater.from(getContext()).inflate(R.layout.rsfa_step_layout_pincode, this, true); title = (TextView) findViewById(R.id.title); - title.setText(R.string.rsb_pincode_enter_title); + title.setText(R.string.rsfa_pincode_enter_title); resetSummaryText(); @@ -75,7 +75,7 @@ protected void init() { public void resetSummaryText() { summary = (TextView) findViewById(R.id.text); String characterType = getContext().getString(config.getPinType().getInputTypeStringId()); - String pinCodeInstructions = getContext().getString(R.string.rsb_pincode_enter_summary, + String pinCodeInstructions = getContext().getString(R.string.rsfa_pincode_enter_summary, config.getPinLength(), characterType); summary.setText(pinCodeInstructions); diff --git a/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpPinCodeCreationStepLayout.java b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/ui/SignUpPinCodeCreationStepLayout.java similarity index 68% rename from skin/src/main/java/org/researchstack/skin/ui/layout/SignUpPinCodeCreationStepLayout.java rename to authentication/src/main/java/org/researchstack/feature/authentication/pincode/ui/SignUpPinCodeCreationStepLayout.java index 03900bdaf..e45dbb227 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpPinCodeCreationStepLayout.java +++ b/authentication/src/main/java/org/researchstack/feature/authentication/pincode/ui/SignUpPinCodeCreationStepLayout.java @@ -1,23 +1,21 @@ -package org.researchstack.skin.ui.layout; +package org.researchstack.feature.authentication.pincode.ui; import android.content.Context; import android.content.res.Resources; import android.os.Handler; -import android.support.v4.content.ContextCompat; +import androidx.core.content.ContextCompat; +import android.text.Editable; +import android.text.TextWatcher; import android.util.AttributeSet; import android.view.View; import android.view.inputmethod.InputMethodManager; - -import com.jakewharton.rxbinding.widget.RxTextView; - -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.step.layout.StepLayout; -import org.researchstack.backbone.ui.views.PinCodeLayout; -import org.researchstack.backbone.utils.ThemeUtils; -import org.researchstack.skin.R; -import org.researchstack.skin.step.PassCodeCreationStep; +import org.researchstack.feature.authentication.R; +import org.researchstack.feature.authentication.pincode.step.PassCodeCreationStep; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.utils.ThemeUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; public class SignUpPinCodeCreationStepLayout extends PinCodeLayout implements StepLayout { public static final String RESULT_OLD_PIN = "PassCodeCreationStep.oldPin"; @@ -56,10 +54,22 @@ public void initialize(Step step, StepResult result) { private void initializeLayout() { refreshState(); - RxTextView.textChanges(editText) - .map(CharSequence::toString) - .filter(pin -> pin.length() == config.getPinLength()) - .subscribe(pin -> { + TextWatcher pinCodeWatcher = new TextWatcher() { + //JDK - 4/13/19 + //It appears that anonymous classes that implement interfaces + //MUST implement all methods. + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + //JDK - 4/13/19 + //do nothing + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + String pin = s.toString(); + if (pin.length() == config.getPinLength()) { + if (state == State.CHANGE) { result.setResultForIdentifier(RESULT_OLD_PIN, pin); @@ -85,7 +95,18 @@ private void initializeLayout() { refreshState(); } } - }); + } + + } + + @Override + public void afterTextChanged(Editable s) { + //JDK - 4/13/19 + //do nothing + } + }; + + editText.addTextChangedListener(pinCodeWatcher); editText.post(() -> imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY)); @@ -126,33 +147,33 @@ private void refreshState() { String characterType = res.getString(config.getPinType().getInputTypeStringId()); switch (state) { case CONFIRM: - pinCodeTitle = res.getString(R.string.rss_passcode_confirm_title); - pinCodeInstructions = res.getString(R.string.rss_passcode_confirm_summary, + pinCodeTitle = res.getString(R.string.rsfa_passcode_confirm_title); + pinCodeInstructions = res.getString(R.string.rsfa_passcode_confirm_summary, pinLength, characterType); summaryColor = ThemeUtils.getTextColorPrimary(getContext()); break; case RETRY: - pinCodeTitle = res.getString(R.string.rss_passcode_confirm_title); - pinCodeInstructions = res.getString(R.string.rss_passcode_confirm_error, + pinCodeTitle = res.getString(R.string.rsfa_passcode_confirm_title); + pinCodeInstructions = res.getString(R.string.rsfa_passcode_confirm_error, pinLength, characterType); - summaryColor = ContextCompat.getColor(getContext(), R.color.rsb_error); + summaryColor = ContextCompat.getColor(getContext(), R.color.rsf_error); break; case CREATE: default: - pinCodeTitle = res.getString(R.string.rss_passcode_create_title); - pinCodeInstructions = res.getString(R.string.rss_passcode_create_summary, + pinCodeTitle = res.getString(R.string.rsfa_passcode_create_title); + pinCodeInstructions = res.getString(R.string.rsfa_passcode_create_summary, pinLength, characterType); summaryColor = ThemeUtils.getTextColorPrimary(getContext()); break; case CHANGE: - pinCodeTitle = res.getString(R.string.rsb_pincode_enter_title); - pinCodeInstructions = res.getString(R.string.rsb_pincode_enter_summary, + pinCodeTitle = res.getString(R.string.rsfa_pincode_enter_title); + pinCodeInstructions = res.getString(R.string.rsfa_pincode_enter_summary, pinLength, characterType); summaryColor = ThemeUtils.getTextColorPrimary(getContext()); diff --git a/backbone/src/main/res/layout/rsb_step_layout_pincode.xml b/authentication/src/main/res/layout/rsfa_step_layout_pincode.xml similarity index 73% rename from backbone/src/main/res/layout/rsb_step_layout_pincode.xml rename to authentication/src/main/res/layout/rsfa_step_layout_pincode.xml index a5ec568a5..dd512e117 100644 --- a/backbone/src/main/res/layout/rsb_step_layout_pincode.xml +++ b/authentication/src/main/res/layout/rsfa_step_layout_pincode.xml @@ -6,26 +6,26 @@ + android:text="@string/rsfa_pincode_enter_title" /> - diff --git a/authentication/src/main/res/values/strings.xml b/authentication/src/main/res/values/strings.xml new file mode 100644 index 000000000..d4ad0454a --- /dev/null +++ b/authentication/src/main/res/values/strings.xml @@ -0,0 +1,22 @@ + + + Enter your passcode + Enter your %1$d-%2$s code to confirm your identity. + digit + letter + character + That code doesn’t match the one you entered, Try again! + + + Change Passcode + Passcode + Choose a passcode + Enter a secure, %1$d-%2$s code to protect your data and log in + faster. + + Confirm your passcode + Enter your %1$d-%2$s code one more time to confirm. + That code doesn’t match the one you entered. Try again + or go back to choose a different %1$d-%2$s code. + + diff --git a/authentication/src/test/java/org/researchstack/feature/authentication/ExampleUnitTest.java b/authentication/src/test/java/org/researchstack/feature/authentication/ExampleUnitTest.java new file mode 100644 index 000000000..4040ee842 --- /dev/null +++ b/authentication/src/test/java/org/researchstack/feature/authentication/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package org.researchstack.feature.authentication; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/backbone/build.gradle b/backbone/build.gradle index c4cbecdf9..b0f14a40d 100644 --- a/backbone/build.gradle +++ b/backbone/build.gradle @@ -1,21 +1,22 @@ apply plugin: 'com.android.library' -apply plugin: 'me.tatarka.retrolambda' -apply plugin: 'com.neenbedankt.android-apt' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' -version = '1.1.2' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +version = research_stack_version android { - compileSdkVersion 23 - buildToolsVersion "23.0.2" + compileSdkVersion 28 defaultConfig { - minSdkVersion 16 - targetSdkVersion 23 - versionCode 6 + minSdkVersion 19 + targetSdkVersion 28 + versionCode 7 versionName version } + buildTypes { release { minifyEnabled false @@ -52,7 +53,7 @@ ext { siteUrl = 'https://researchstack.org' gitUrl = 'https://github.com/ResearchStack/ResearchStack.git' - libraryVersion = version + libraryVersion = research_stack_version userOrgName = 'researchstack' developerId = properties.getProperty("bintray.user") @@ -65,27 +66,30 @@ ext { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:23.2.1' - compile 'com.android.support:cardview-v7:23.2.1' - compile 'com.android.support:preference-v14:23.2.1' - compile 'com.android.support:design:23.2.1' - compile 'com.google.code.gson:gson:2.4' - compile 'io.reactivex:rxjava:1.1.3' - compile 'io.reactivex:rxandroid:1.1.0' - compile 'com.jakewharton.rxbinding:rxbinding:0.2.0' - compile 'com.jakewharton.rxbinding:rxbinding-support-v4:0.2.0' - compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.2.0' - compile 'com.jakewharton.rxbinding:rxbinding-design:0.2.0' - compile 'com.github.PhilJay:MPAndroidChart:v2.2.3' - - compile 'com.scottyab:aes-crypto:0.0.3' - compile 'co.touchlab.squeaky:squeaky-query:0.4.0.0' - apt 'co.touchlab.squeaky:squeaky-processor:0.4.0.0' - compile 'net.zetetic:android-database-sqlcipher:3.5.4@aar' - testCompile 'junit:junit:4.12' - testCompile 'org.robolectric:robolectric:3.0' - testCompile 'org.mockito:mockito-core:1.10.19' + implementation fileTree(include: ['*.jar'], dir: 'libs') + + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.legacy:legacy-preference-v14:1.0.0' + implementation 'com.google.android.material:material:1.0.0' + + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation project(':foundation') + implementation project(':authentication') + implementation project(':storage') + + implementation "com.google.code.gson:gson:$gson_version" + implementation 'io.reactivex:rxjava:1.2.5' + implementation 'io.reactivex:rxandroid:1.2.1' + implementation 'com.jakewharton.rxbinding:rxbinding:0.4.0' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation 'com.jakewharton.rxbinding:rxbinding-support-v4:0.4.0' + implementation 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.4.0' + implementation 'com.jakewharton.rxbinding:rxbinding-design:0.4.0' + testImplementation 'junit:junit:4.12' + testImplementation 'org.robolectric:robolectric:3.0' + testImplementation 'org.mockito:mockito-core:1.10.19' } group = publishedGroupId // Maven Group ID for the artifact diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/PinCodeActivity.java b/backbone/src/main/java/org/researchstack/backbone/ui/PinCodeActivity.java index 08408b78d..2cf1c1832 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/PinCodeActivity.java +++ b/backbone/src/main/java/org/researchstack/backbone/ui/PinCodeActivity.java @@ -4,9 +4,9 @@ import android.graphics.Color; import android.os.Bundle; import android.os.Handler; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.appcompat.app.AppCompatActivity; import android.view.ContextThemeWrapper; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; @@ -16,13 +16,13 @@ import com.jakewharton.rxbinding.widget.RxTextView; import org.researchstack.backbone.R; -import org.researchstack.backbone.StorageAccess; -import org.researchstack.backbone.storage.file.PinCodeConfig; -import org.researchstack.backbone.storage.file.StorageAccessListener; -import org.researchstack.backbone.ui.views.PinCodeLayout; -import org.researchstack.backbone.utils.LogExt; import org.researchstack.backbone.utils.ObservableUtils; -import org.researchstack.backbone.utils.ThemeUtils; +import org.researchstack.feature.authentication.pincode.PinCodeConfig; +import org.researchstack.feature.authentication.pincode.ui.PinCodeLayout; +import org.researchstack.feature.storage.StorageAccess; +import org.researchstack.feature.storage.file.StorageAccessListener; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.components.utils.ThemeUtils; import java.util.List; @@ -140,7 +140,7 @@ public void onDataAuth() { pinCodeLayout = new PinCodeLayout(new ContextThemeWrapper(this, theme)); pinCodeLayout.setBackgroundColor(Color.WHITE); - int errorColor = getResources().getColor(R.color.rsb_error); + int errorColor = getResources().getColor(R.color.rsf_error); TextView summary = (TextView) pinCodeLayout.findViewById(R.id.text); EditText pincode = (EditText) pinCodeLayout.findViewById(R.id.pincode); @@ -169,7 +169,7 @@ public void onDataAuth() { }).compose(ObservableUtils.applyDefault()).doOnError(throwable -> { toggleKeyboardAction.call(true); throwable.printStackTrace(); - summary.setText(R.string.rsb_pincode_enter_error); + summary.setText(R.string.rsfa_pincode_enter_error); summary.setTextColor(errorColor); pinCodeLayout.showProgress(false); }).onErrorResumeNext(throwable1 -> { diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/ViewTaskActivity.java b/backbone/src/main/java/org/researchstack/backbone/ui/ViewTaskActivity.java index 6f07e2134..270b59fae 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/ViewTaskActivity.java +++ b/backbone/src/main/java/org/researchstack/backbone/ui/ViewTaskActivity.java @@ -4,27 +4,30 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AlertDialog; -import android.support.v7.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.Toolbar; import android.view.MenuItem; import android.view.inputmethod.InputMethodManager; import android.widget.Toast; +import org.jetbrains.annotations.Nullable; import org.researchstack.backbone.R; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.task.Task; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.step.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; import org.researchstack.backbone.ui.views.StepSwitcher; +import org.researchstack.foundation.core.interfaces.IResult; +import org.researchstack.foundation.core.interfaces.IStep; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.step.Step; +import org.researchstack.foundation.core.models.task.Task; import java.lang.reflect.Constructor; import java.util.Date; -public class ViewTaskActivity extends PinCodeActivity implements StepCallbacks { +public class ViewTaskActivity extends PinCodeActivity implements StepCallbacks, Task.TaskLifecycleObserver { public static final String EXTRA_TASK = "ViewTaskActivity.ExtraTask"; public static final String EXTRA_TASK_RESULT = "ViewTaskActivity.ExtraTaskResult"; public static final String EXTRA_STEP = "ViewTaskActivity.ExtraStep"; @@ -206,13 +209,15 @@ public void onDataReady() { @Override public void onDataFailed() { super.onDataFailed(); - Toast.makeText(this, R.string.rsb_error_data_failed, Toast.LENGTH_LONG).show(); + Toast.makeText(this, R.string.rsf_error_data_failed, Toast.LENGTH_LONG).show(); finish(); } @Override - public void onSaveStep(int action, Step step, StepResult result) { - onSaveStepResult(step.getIdentifier(), result); + public void onSaveStep(int action, IStep step, @Nullable IResult result) { + if (result instanceof StepResult) { + onSaveStepResult(step.getIdentifier(), (StepResult)result); + } onExecuteStepAction(action); } diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/callbacks/StepCallbacks.java b/backbone/src/main/java/org/researchstack/backbone/ui/callbacks/StepCallbacks.java deleted file mode 100644 index b18d79768..000000000 --- a/backbone/src/main/java/org/researchstack/backbone/ui/callbacks/StepCallbacks.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.researchstack.backbone.ui.callbacks; - -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; - -public interface StepCallbacks { - int ACTION_PREV = -1; - int ACTION_NONE = 0; - int ACTION_NEXT = 1; - int ACTION_END = 2; - - void onSaveStep(int action, Step step, StepResult result); - - @Deprecated - void onCancelStep(); -} diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/views/StepSwitcher.java b/backbone/src/main/java/org/researchstack/backbone/ui/views/StepSwitcher.java index b2b44daa8..1cc00a065 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/views/StepSwitcher.java +++ b/backbone/src/main/java/org/researchstack/backbone/ui/views/StepSwitcher.java @@ -28,7 +28,7 @@ import android.widget.FrameLayout; import org.researchstack.backbone.R; -import org.researchstack.backbone.ui.step.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; import java.security.InvalidParameterException; diff --git a/backbone/src/main/res/layout/rsb_activity_step_switcher.xml b/backbone/src/main/res/layout/rsb_activity_step_switcher.xml index b6c6b76e2..61d30b83a 100644 --- a/backbone/src/main/res/layout/rsb_activity_step_switcher.xml +++ b/backbone/src/main/res/layout/rsb_activity_step_switcher.xml @@ -4,7 +4,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/backbone/src/main/res/values/colors.xml b/backbone/src/main/res/values/colors.xml index 35770d03d..d781ec5f1 100644 --- a/backbone/src/main/res/values/colors.xml +++ b/backbone/src/main/res/values/colors.xml @@ -1,20 +1,4 @@ - #3F51B5 - #303F9F - #FF4081 - #cc3367 - #000 - #33000000 - #66000000 - #CCFFFFFF - #FF757575 - #33757575 - #EEEEEE - #979797 - #e5e5e5 - #ffff5722 - #2196f3 - #662196f3 diff --git a/backbone/src/main/res/values/dimens.xml b/backbone/src/main/res/values/dimens.xml index 861d46016..0d2c4cc40 100644 --- a/backbone/src/main/res/values/dimens.xml +++ b/backbone/src/main/res/values/dimens.xml @@ -1,23 +1,4 @@ - - 8dp - 12dp - 16dp - 24dp - - - 48dp - 56dp - @dimen/rsb_item_size_small - 1dp - - - 48dp - 16dp - - - 20sp - \ No newline at end of file diff --git a/backbone/src/main/res/values/strings.xml b/backbone/src/main/res/values/strings.xml index f4500d602..13e6f0480 100644 --- a/backbone/src/main/res/values/strings.xml +++ b/backbone/src/main/res/values/strings.xml @@ -1,164 +1,3 @@ - - Lorem Ipsum - Lorem ipsum dolor sit amet, consectetur - adipiscing elit. - - Lorem ipsum dolor sit amet, consectetur - adipiscing elit sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim. - - Lorem ipsum dolor sit amet, consectetur - adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis - nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute - irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit - anim id est laborum. - - - Consent - Welcome - Data Gathering - Privacy - Data Use - Time Commitment - Study Survey - Study Tasks - Withdrawing - Learn More - - - Learn more - Learn more about how data is - gathered - - Learn more about how data is used - Learn more about how your privacy and - identity are protected - - Learn more about the study first - Learn more about the study survey - - Learn more about the study\'s - impact on your time - - Learn more about the tasks involved - - Learn more about withdrawing - - - Sharing Options - Share my data with %1$s and qualified researchers - worldwide - - Not sharing your data - Only share my data with %1$s -
- Learn more about data sharing]]> -
- - - Review - Review - By agreeing you confirm that you read the information - and that you wish to take part in this research study. - - Review the form below, and tap Agree if you\'re - ready to continue. - - Cancel - - - Consent - Full Name - Date of Birth - Required - - - Signature - By agreeing you confirm that you read the consent - and that you wish to take part in this research study. - - Please sign using your finger on the line - below. - - Sign Here - Clear - - - Quiz - Quiz Evaluation - Try Again - Review Consent - Retake Quiz - Great Job! - - - Submit - Exit - Get Started - Done - Skip - next - What to Expect - Name - Email - Disagree - Agree - OK - Cancel - Yes - No - Step %1$s of %2$s - Hours - Minutes - - - Failed to load encrypted data, try again! - Signature Invalid - Invalid answer, try again! - Invalid answer, date must be before %1$s - Invalid answer, date must be after %1$s - Invalid answer, your value must be %1$s or lower - Invalid answer, your value must be %1$s or higher - Please select a value! - Please choose a date. - You must be %1$s years or younger - You must be at least %1$s years old - - - - Enter your passcode - Enter your %1$d-%2$s code to confirm your identity. - digit - letter - character - That code doesn’t match the one you entered, Try again! - - - Enter a number %1$d-%2$d - Enter a number %1$.2f-%2$.2f - Enter a number - Enter a date - Enter a time - Enter a date and a time - Answer - - - %1$s of %2$s - %1$s% - - - - Video problem - - This video isn\'t valid for streaming to this device. - - Can\'t play this video. - - OK
diff --git a/backbone/src/main/res/values/styles.xml b/backbone/src/main/res/values/styles.xml index 31d7b0abb..9953a6fea 100644 --- a/backbone/src/main/res/values/styles.xml +++ b/backbone/src/main/res/values/styles.xml @@ -2,131 +2,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/backbone/src/main/res/values/themes.xml b/backbone/src/main/res/values/themes.xml index 6ba784da7..e1fe522fa 100644 --- a/backbone/src/main/res/values/themes.xml +++ b/backbone/src/main/res/values/themes.xml @@ -9,14 +9,6 @@ @style/Theme.Backbone.Toolbar @style/Theme.AppCompat.Light.NoActionBar - @style/Widget.Backbone.SubmitBar - @style/Widget.Backbone.IconTabLayout - @style/Widget.Backbone.SignatureView - @style/Widget.Backbone.EmptyView - @style/Widget.Backbone.Chart.Progress - @style/Widget.Backbone.Chart.Pie - @style/Widget.Backbone.Chart.Line - @style/Widget.Backbone.Chart.Bar + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/chart/src/main/res/values/themes.xml b/chart/src/main/res/values/themes.xml new file mode 100644 index 000000000..b879397f6 --- /dev/null +++ b/chart/src/main/res/values/themes.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/chart/src/test/java/org/researchstack/feature/chart/ExampleUnitTest.java b/chart/src/test/java/org/researchstack/feature/chart/ExampleUnitTest.java new file mode 100644 index 000000000..4ca3c32e3 --- /dev/null +++ b/chart/src/test/java/org/researchstack/feature/chart/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package org.researchstack.feature.chart; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/consent/.gitignore b/consent/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/consent/.gitignore @@ -0,0 +1 @@ +/build diff --git a/consent/build.gradle b/consent/build.gradle new file mode 100644 index 000000000..6ad7ed4c4 --- /dev/null +++ b/consent/build.gradle @@ -0,0 +1,167 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +apply plugin: 'com.github.dcendents.android-maven' +apply plugin: 'com.jfrog.bintray' + +version = research_stack_version + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 19 + targetSdkVersion 28 + versionCode 1 + versionName version + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + resourcePrefix 'rsfc_' + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +Properties properties = new Properties() +properties.load(project.rootProject.file('local.properties').newDataInputStream()) + +ext { + bintrayRepo = 'ResearchStack' + bintrayName = 'Authentication' + + publishedGroupId = 'org.researchstack' + libraryName = 'Consent' + artifact = 'consent' + + libraryDescription = 'Consent' + + siteUrl = 'https://researchstack.org' + gitUrl = 'https://github.com/ResearchStack/ResearchStack.git' + + libraryVersion = version + + userOrgName = 'researchstack' + developerId = properties.getProperty("bintray.user") + developerName = properties.getProperty("bintray.developerName") + developerEmail = properties.getProperty("bintray.developerEmail") + + licenseName = 'The Apache Software License, Version 2.0' + licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + allLicenses = ["Apache-2.0"] +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.legacy:legacy-preference-v14:1.0.0' + implementation 'com.google.android.material:material:1.0.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation project(':foundation') + implementation "com.google.code.gson:gson:$gson_version" + + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} + +group = publishedGroupId // Maven Group ID for the artifact + +install { + repositories.mavenInstaller { + // This generates POM.xml with proper parameters + pom { + project { + packaging 'aar' + groupId publishedGroupId + artifactId artifact + + // Add your description here + name libraryName + description libraryDescription + url siteUrl + + // Set your license + licenses { + license { + name licenseName + url licenseUrl + } + } + developers { + developer { + id developerId + name developerName + email developerEmail + } + } + scm { + connection gitUrl + developerConnection gitUrl + url siteUrl + } + } + } + } +} + +if (project.hasProperty("android")) { // Android libraries + task sourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs + } + + task javadoc(type: Javadoc) { + failOnError false + source = android.sourceSets.main.java.srcDirs + } + + afterEvaluate { + javadoc.classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + javadoc.classpath += files(android.libraryVariants.collect { variant -> + variant.javaCompile.classpath.files + }) + } +} else { // Java libraries + task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from sourceSets.main.allSource + } +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives javadocJar + archives sourcesJar +} + +bintray { + user = properties.getProperty("bintray.user") + key = properties.getProperty("bintray.apikey") + + configurations = ['archives'] + pkg { + repo = bintrayRepo + name = bintrayName + userOrg = userOrgName + desc = libraryDescription + websiteUrl = siteUrl + vcsUrl = gitUrl + licenses = allLicenses + publish = true + } +} diff --git a/consent/proguard-rules.pro b/consent/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/consent/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/consent/src/androidTest/java/org/researchstack/feature/consent/ExampleInstrumentedTest.java b/consent/src/androidTest/java/org/researchstack/feature/consent/ExampleInstrumentedTest.java new file mode 100644 index 000000000..d5490dc3b --- /dev/null +++ b/consent/src/androidTest/java/org/researchstack/feature/consent/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package org.researchstack.feature.consent; + +import android.content.Context; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("org.researchstack.feature.consent.test", appContext.getPackageName()); + } +} diff --git a/consent/src/main/AndroidManifest.xml b/consent/src/main/AndroidManifest.xml new file mode 100644 index 000000000..181af0c26 --- /dev/null +++ b/consent/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/backbone/src/main/java/org/researchstack/backbone/model/ConsentDocument.java b/consent/src/main/java/org/researchstack/feature/consent/model/ConsentDocument.java similarity index 97% rename from backbone/src/main/java/org/researchstack/backbone/model/ConsentDocument.java rename to consent/src/main/java/org/researchstack/feature/consent/model/ConsentDocument.java index c83f713dc..fd0533227 100644 --- a/backbone/src/main/java/org/researchstack/backbone/model/ConsentDocument.java +++ b/consent/src/main/java/org/researchstack/feature/consent/model/ConsentDocument.java @@ -1,6 +1,6 @@ -package org.researchstack.backbone.model; +package org.researchstack.feature.consent.model; -import android.support.annotation.StringRes; +import androidx.annotation.StringRes; import java.io.Serializable; import java.util.ArrayList; diff --git a/backbone/src/main/java/org/researchstack/backbone/model/ConsentSection.java b/consent/src/main/java/org/researchstack/feature/consent/model/ConsentSection.java similarity index 83% rename from backbone/src/main/java/org/researchstack/backbone/model/ConsentSection.java rename to consent/src/main/java/org/researchstack/feature/consent/model/ConsentSection.java index 13f232117..976e34b2b 100644 --- a/backbone/src/main/java/org/researchstack/backbone/model/ConsentSection.java +++ b/consent/src/main/java/org/researchstack/feature/consent/model/ConsentSection.java @@ -1,9 +1,9 @@ -package org.researchstack.backbone.model; +package org.researchstack.feature.consent.model; import com.google.gson.annotations.SerializedName; -import org.researchstack.backbone.R; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.feature.consent.R; +import org.researchstack.foundation.components.utils.TextUtils; import java.io.Serializable; @@ -73,7 +73,7 @@ public class ConsentSection implements Serializable { * A custom illustration for the consent. *

* The custom image can override the image associated with any of the predefined section types - * for an {@link org.researchstack.backbone.step.ConsentVisualStep} object. It is ignored for a + * for an {@link org.researchstack.foundation.step.ConsentVisualStep} object. It is ignored for a * consent review step and for PDF generation. *

* The image is used in template rendering mode, and is tinted using the tint color. @@ -267,21 +267,21 @@ public enum Type implements Serializable { public int getTitleResId() { switch (this) { case Overview: - return R.string.rsb_consent_section_welcome; + return R.string.rsfc_consent_section_welcome; case DataGathering: - return R.string.rsb_consent_section_data_gathering; + return R.string.rsfc_consent_section_data_gathering; case Privacy: - return R.string.rsb_consent_section_privacy; + return R.string.rsfc_consent_section_privacy; case DataUse: - return R.string.rsb_consent_section_data_use; + return R.string.rsfc_consent_section_data_use; case TimeCommitment: - return R.string.rsb_consent_section_time_commitment; + return R.string.rsfc_consent_section_time_commitment; case StudySurvey: - return R.string.rsb_consent_section_study_survey; + return R.string.rsfc_consent_section_study_survey; case StudyTasks: - return R.string.rsb_consent_section_study_tasks; + return R.string.rsfc_consent_section_study_tasks; case Withdrawing: - return R.string.rsb_consent_section_withdrawing; + return R.string.rsfc_consent_section_withdrawing; default: return -1; } @@ -290,19 +290,19 @@ public int getTitleResId() { public String getImageName() { switch (this) { case DataGathering: - return "rsb_consent_section_data_gathering"; + return "rsfc_consent_section_data_gathering"; case Privacy: - return "rsb_consent_section_privacy"; + return "rsfc_consent_section_privacy"; case DataUse: - return "rsb_consent_section_data_use"; + return "rsfc_consent_section_data_use"; case TimeCommitment: - return "rsb_consent_section_time_commitment"; + return "rsfc_consent_section_time_commitment"; case StudySurvey: - return "rsb_consent_section_study_survey"; + return "rsfc_consent_section_study_survey"; case StudyTasks: - return "rsb_consent_section_study_tasks"; + return "rsfc_consent_section_study_tasks"; case Withdrawing: - return "rsb_consent_section_withdrawing"; + return "rsfc_consent_section_withdrawing"; default: return null; } @@ -311,23 +311,23 @@ public String getImageName() { public int getMoreInfoResId() { switch (this) { case Overview: - return R.string.rsb_consent_section_more_info_welcome; + return R.string.rsfc_consent_section_more_info_welcome; case DataGathering: - return R.string.rsb_consent_section_more_info_data_gathering; + return R.string.rsfc_consent_section_more_info_data_gathering; case Privacy: - return R.string.rsb_consent_section_more_info_privacy; + return R.string.rsfc_consent_section_more_info_privacy; case DataUse: - return R.string.rsb_consent_section_more_info_data_use; + return R.string.rsfc_consent_section_more_info_data_use; case TimeCommitment: - return R.string.rsb_consent_section_more_info_time_commitment; + return R.string.rsfc_consent_section_more_info_time_commitment; case StudySurvey: - return R.string.rsb_consent_section_more_info_study_survey; + return R.string.rsfc_consent_section_more_info_study_survey; case StudyTasks: - return R.string.rsb_consent_section_more_info_study_tasks; + return R.string.rsfc_consent_section_more_info_study_tasks; case Withdrawing: - return R.string.rsb_consent_section_more_info_withdrawing; + return R.string.rsfc_consent_section_more_info_withdrawing; default: - return R.string.rsb_consent_section_more_info; + return R.string.rsfc_consent_section_more_info; } } diff --git a/backbone/src/main/java/org/researchstack/backbone/model/ConsentSignature.java b/consent/src/main/java/org/researchstack/feature/consent/model/ConsentSignature.java similarity index 98% rename from backbone/src/main/java/org/researchstack/backbone/model/ConsentSignature.java rename to consent/src/main/java/org/researchstack/feature/consent/model/ConsentSignature.java index 1a27e7ea3..dc840a45b 100644 --- a/backbone/src/main/java/org/researchstack/backbone/model/ConsentSignature.java +++ b/consent/src/main/java/org/researchstack/feature/consent/model/ConsentSignature.java @@ -1,6 +1,6 @@ -package org.researchstack.backbone.model; +package org.researchstack.feature.consent.model; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import java.io.Serializable; import java.util.UUID; diff --git a/backbone/src/main/java/org/researchstack/backbone/step/ConsentDocumentStep.java b/consent/src/main/java/org/researchstack/feature/consent/step/ConsentDocumentStep.java similarity index 85% rename from backbone/src/main/java/org/researchstack/backbone/step/ConsentDocumentStep.java rename to consent/src/main/java/org/researchstack/feature/consent/step/ConsentDocumentStep.java index a587fe68b..b444b5e72 100644 --- a/backbone/src/main/java/org/researchstack/backbone/step/ConsentDocumentStep.java +++ b/consent/src/main/java/org/researchstack/feature/consent/step/ConsentDocumentStep.java @@ -1,7 +1,8 @@ -package org.researchstack.backbone.step; +package org.researchstack.feature.consent.step; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ui.step.layout.ConsentDocumentStepLayout; +import org.researchstack.feature.consent.R; +import org.researchstack.feature.consent.ui.layout.ConsentDocumentStepLayout; +import org.researchstack.foundation.core.models.step.Step; /** * This step shows an HTML version of your consent document to the user and allows them to indicate @@ -18,7 +19,7 @@ public ConsentDocumentStep(String identifier) { @Override public int getStepTitle() { - return R.string.rsb_consent; + return R.string.rsfc_consent; } @Override diff --git a/backbone/src/main/java/org/researchstack/backbone/step/ConsentSharingStep.java b/consent/src/main/java/org/researchstack/feature/consent/step/ConsentSharingStep.java similarity index 68% rename from backbone/src/main/java/org/researchstack/backbone/step/ConsentSharingStep.java rename to consent/src/main/java/org/researchstack/feature/consent/step/ConsentSharingStep.java index ca27ec0d1..00c051ad8 100644 --- a/backbone/src/main/java/org/researchstack/backbone/step/ConsentSharingStep.java +++ b/consent/src/main/java/org/researchstack/feature/consent/step/ConsentSharingStep.java @@ -1,6 +1,7 @@ -package org.researchstack.backbone.step; +package org.researchstack.feature.consent.step; -import org.researchstack.backbone.ui.step.body.SingleChoiceQuestionBody; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.components.survey.ui.body.SingleChoiceQuestionBody; /** * This class represents a question step that includes prepopulated content that asks users about diff --git a/backbone/src/main/java/org/researchstack/backbone/step/ConsentSignatureStep.java b/consent/src/main/java/org/researchstack/feature/consent/step/ConsentSignatureStep.java similarity index 92% rename from backbone/src/main/java/org/researchstack/backbone/step/ConsentSignatureStep.java rename to consent/src/main/java/org/researchstack/feature/consent/step/ConsentSignatureStep.java index 3cf36e23e..cd30f3581 100644 --- a/backbone/src/main/java/org/researchstack/backbone/step/ConsentSignatureStep.java +++ b/consent/src/main/java/org/researchstack/feature/consent/step/ConsentSignatureStep.java @@ -1,4 +1,6 @@ -package org.researchstack.backbone.step; +package org.researchstack.feature.consent.step; + +import org.researchstack.foundation.core.models.step.Step; /** * This class represents the final step in the consent process, collecting the signature from the diff --git a/backbone/src/main/java/org/researchstack/backbone/step/ConsentVisualStep.java b/consent/src/main/java/org/researchstack/feature/consent/step/ConsentVisualStep.java similarity index 81% rename from backbone/src/main/java/org/researchstack/backbone/step/ConsentVisualStep.java rename to consent/src/main/java/org/researchstack/feature/consent/step/ConsentVisualStep.java index 00ca0d6df..8e9f35440 100644 --- a/backbone/src/main/java/org/researchstack/backbone/step/ConsentVisualStep.java +++ b/consent/src/main/java/org/researchstack/feature/consent/step/ConsentVisualStep.java @@ -1,7 +1,9 @@ -package org.researchstack.backbone.step; +package org.researchstack.feature.consent.step; -import org.researchstack.backbone.model.ConsentSection; -import org.researchstack.backbone.ui.step.layout.ConsentVisualStepLayout; +import org.researchstack.feature.consent.R; +import org.researchstack.feature.consent.model.ConsentSection; +import org.researchstack.feature.consent.ui.layout.ConsentVisualStepLayout; +import org.researchstack.foundation.core.models.step.Step; /** * The {@link ConsentVisualStep} class represents a step in the visual consent sequence. @@ -21,7 +23,7 @@ public ConsentVisualStep(String identifier) { @Override public int getStepTitle() { - return org.researchstack.backbone.R.string.rsb_consent; + return R.string.rsfc_consent; } @Override diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/callbacks/SignatureCallbacks.java b/consent/src/main/java/org/researchstack/feature/consent/ui/callbacks/SignatureCallbacks.java similarity index 65% rename from backbone/src/main/java/org/researchstack/backbone/ui/callbacks/SignatureCallbacks.java rename to consent/src/main/java/org/researchstack/feature/consent/ui/callbacks/SignatureCallbacks.java index 096857845..e46fd1c76 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/callbacks/SignatureCallbacks.java +++ b/consent/src/main/java/org/researchstack/feature/consent/ui/callbacks/SignatureCallbacks.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.callbacks; +package org.researchstack.feature.consent.ui.callbacks; public interface SignatureCallbacks { void onSignatureStarted(); diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/ConsentDocumentStepLayout.java b/consent/src/main/java/org/researchstack/feature/consent/ui/layout/ConsentDocumentStepLayout.java similarity index 75% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/layout/ConsentDocumentStepLayout.java rename to consent/src/main/java/org/researchstack/feature/consent/ui/layout/ConsentDocumentStepLayout.java index fd1a297b1..34730d814 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/ConsentDocumentStepLayout.java +++ b/consent/src/main/java/org/researchstack/feature/consent/ui/layout/ConsentDocumentStepLayout.java @@ -1,19 +1,20 @@ -package org.researchstack.backbone.ui.step.layout; +package org.researchstack.feature.consent.ui.layout; import android.content.Context; -import android.support.v7.app.AlertDialog; +import androidx.appcompat.app.AlertDialog; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.webkit.WebView; import android.widget.LinearLayout; -import org.researchstack.backbone.R; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.ConsentDocumentStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.views.SubmitBar; +import org.researchstack.feature.consent.R; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.feature.consent.step.ConsentDocumentStep; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; /** * Implement saved state for the following objects: @@ -75,7 +76,7 @@ public void setCallbacks(StepCallbacks callbacks) { private void initializeStep() { setOrientation(VERTICAL); - LayoutInflater.from(getContext()).inflate(R.layout.rsb_step_layout_consent_doc, this, true); + LayoutInflater.from(getContext()).inflate(R.layout.rsfc_step_layout_consent_doc, this, true); WebView pdfView = (WebView) findViewById(R.id.webview); pdfView.loadData(htmlContent, "text/html; charset=UTF-8", null); @@ -86,14 +87,14 @@ private void initializeStep() { } private void showDialog() { - new AlertDialog.Builder(getContext()).setTitle(R.string.rsb_consent_review_alert_title) + new AlertDialog.Builder(getContext()).setTitle(R.string.rsfc_consent_review_alert_title) .setMessage(confirmationDialogBody) .setCancelable(false) - .setPositiveButton(R.string.rsb_agree, (dialog, which) -> { + .setPositiveButton(R.string.rsf_agree, (dialog, which) -> { stepResult.setResult(true); callbacks.onSaveStep(StepCallbacks.ACTION_NEXT, step, stepResult); }) - .setNegativeButton(R.string.rsb_consent_review_cancel, (dialog, which) -> { + .setNegativeButton(R.string.rsfc_consent_review_cancel, (dialog, which) -> { // Gives them a chance to read it again }) .show(); diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/ConsentSignatureStepLayout.java b/consent/src/main/java/org/researchstack/feature/consent/ui/layout/ConsentSignatureStepLayout.java similarity index 81% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/layout/ConsentSignatureStepLayout.java rename to consent/src/main/java/org/researchstack/feature/consent/ui/layout/ConsentSignatureStepLayout.java index 2c7ba7734..5c3300c1f 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/ConsentSignatureStepLayout.java +++ b/consent/src/main/java/org/researchstack/feature/consent/ui/layout/ConsentSignatureStepLayout.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.step.layout; +package org.researchstack.feature.consent.ui.layout; import android.content.Context; import android.graphics.Bitmap; @@ -10,18 +10,17 @@ import android.widget.TextView; import android.widget.Toast; -import com.jakewharton.rxbinding.view.RxView; - -import org.researchstack.backbone.R; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.ConsentSignatureStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.callbacks.SignatureCallbacks; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.views.SignatureView; -import org.researchstack.backbone.ui.views.SubmitBar; -import org.researchstack.backbone.utils.FormatHelper; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.feature.consent.R; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.feature.consent.step.ConsentSignatureStep; +import org.researchstack.feature.consent.ui.callbacks.SignatureCallbacks; +import org.researchstack.feature.consent.ui.views.SignatureView; +import org.researchstack.foundation.components.utils.FormatHelper; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import java.io.ByteArrayOutputStream; import java.text.DateFormat; @@ -76,7 +75,7 @@ public void setCallbacks(StepCallbacks callbacks) { private void initializeStep() { LayoutInflater.from(getContext()) - .inflate(R.layout.rsb_step_layout_consent_signature, this, true); + .inflate(R.layout.rsfc_step_layout_consent_signature, this, true); TextView title = (TextView) findViewById(R.id.title); title.setText(step.getTitle()); @@ -101,7 +100,7 @@ public void onSignatureCleared() { } }); - RxView.clicks(clear).subscribe(v -> { + clear.setOnClickListener(v -> { signatureView.clearSignature(); }); @@ -117,7 +116,7 @@ public void onSignatureCleared() { setDataToResult(); callbacks.onSaveStep(StepCallbacks.ACTION_NEXT, step, result); } else { - Toast.makeText(getContext(), R.string.rsb_error_invalid_signature, Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), R.string.rsf_error_invalid_signature, Toast.LENGTH_SHORT).show(); } }); } diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/ConsentVisualStepLayout.java b/consent/src/main/java/org/researchstack/feature/consent/ui/layout/ConsentVisualStepLayout.java similarity index 77% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/layout/ConsentVisualStepLayout.java rename to consent/src/main/java/org/researchstack/feature/consent/ui/layout/ConsentVisualStepLayout.java index 815c13095..cfa39cd6e 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/ConsentVisualStepLayout.java +++ b/consent/src/main/java/org/researchstack/feature/consent/ui/layout/ConsentVisualStepLayout.java @@ -1,29 +1,28 @@ -package org.researchstack.backbone.ui.step.layout; +package org.researchstack.feature.consent.ui.layout; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; -import android.support.v4.graphics.drawable.DrawableCompat; +import androidx.core.graphics.drawable.DrawableCompat; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.widget.ImageView; import android.widget.TextView; -import com.jakewharton.rxbinding.view.RxView; - -import org.researchstack.backbone.R; -import org.researchstack.backbone.model.ConsentSection; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.ConsentVisualStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.ViewWebDocumentActivity; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.views.FixedSubmitBarLayout; -import org.researchstack.backbone.ui.views.SubmitBar; -import org.researchstack.backbone.utils.ResUtils; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.feature.consent.R; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.FixedSubmitBarLayout; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.feature.consent.model.ConsentSection; +import org.researchstack.feature.consent.step.ConsentVisualStep; +import org.researchstack.foundation.components.utils.ResUtils; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.components.web.ui.activities.ViewWebDocumentActivity; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; public class ConsentVisualStepLayout extends FixedSubmitBarLayout implements StepLayout { @@ -66,7 +65,7 @@ public void setCallbacks(StepCallbacks callbacks) { @Override public int getContentResourceId() { - return R.layout.rsb_step_layout_consent_visual; + return R.layout.rsfc_step_layout_consent_visual; } private void initializeStep() { @@ -117,8 +116,8 @@ private void initializeStep() { moreInfoView.setText(data.getType().getMoreInfoResId()); } - RxView.clicks(moreInfoView).subscribe(v -> { - String webTitle = getResources().getString(R.string.rsb_consent_section_more_info); + moreInfoView.setOnClickListener(v -> { + String webTitle = getResources().getString(R.string.rsfc_consent_section_more_info); Intent webDoc = ViewWebDocumentActivity.newIntentForContent(getContext(), webTitle, TextUtils.isEmpty(data.getContent()) ? data.getHtmlContent() : data.getContent()); getContext().startActivity(webDoc); @@ -127,7 +126,7 @@ private void initializeStep() { moreInfoView.setVisibility(View.GONE); } - SubmitBar submitBar = (SubmitBar) findViewById(R.id.rsb_submit_bar); + SubmitBar submitBar = (SubmitBar) findViewById(R.id.rsf_submit_bar); submitBar.setPositiveTitle(step.getNextButtonString()); submitBar.setPositiveAction(v -> callbacks.onSaveStep(StepCallbacks.ACTION_NEXT, step, diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/views/SignatureView.java b/consent/src/main/java/org/researchstack/feature/consent/ui/views/SignatureView.java similarity index 97% rename from backbone/src/main/java/org/researchstack/backbone/ui/views/SignatureView.java rename to consent/src/main/java/org/researchstack/feature/consent/ui/views/SignatureView.java index c06faa3d1..fe4b4ab22 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/views/SignatureView.java +++ b/consent/src/main/java/org/researchstack/feature/consent/ui/views/SignatureView.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.views; +package org.researchstack.feature.consent.ui.views; import android.content.Context; import android.content.res.TypedArray; @@ -14,13 +14,13 @@ import android.graphics.drawable.shapes.PathShape; import android.os.Parcel; import android.os.Parcelable; -import android.support.v4.view.ViewCompat; +import androidx.core.view.ViewCompat; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ui.callbacks.SignatureCallbacks; +import org.researchstack.feature.consent.R; +import org.researchstack.feature.consent.ui.callbacks.SignatureCallbacks; import java.util.ArrayList; import java.util.List; @@ -78,7 +78,7 @@ private void init(Context context, AttributeSet attrs, int defStyleAttr) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SignatureView, defStyleAttr, - R.style.Widget_Backbone_SignatureView); + R.style.Widget_Feature_Consent_SignatureView); int signatureColor = a.getColor(R.styleable.SignatureView_signatureColor, Color.BLACK); diff --git a/backbone/src/main/res/drawable-hdpi/rsb_consent_section_data_gathering.png b/consent/src/main/res/drawable-hdpi/rsfc_consent_section_data_gathering.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_consent_section_data_gathering.png rename to consent/src/main/res/drawable-hdpi/rsfc_consent_section_data_gathering.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_consent_section_data_use.png b/consent/src/main/res/drawable-hdpi/rsfc_consent_section_data_use.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_consent_section_data_use.png rename to consent/src/main/res/drawable-hdpi/rsfc_consent_section_data_use.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_consent_section_potential_benefits_alt.png b/consent/src/main/res/drawable-hdpi/rsfc_consent_section_potential_benefits_alt.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_consent_section_potential_benefits_alt.png rename to consent/src/main/res/drawable-hdpi/rsfc_consent_section_potential_benefits_alt.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_consent_section_privacy.png b/consent/src/main/res/drawable-hdpi/rsfc_consent_section_privacy.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_consent_section_privacy.png rename to consent/src/main/res/drawable-hdpi/rsfc_consent_section_privacy.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_consent_section_recontact.png b/consent/src/main/res/drawable-hdpi/rsfc_consent_section_recontact.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_consent_section_recontact.png rename to consent/src/main/res/drawable-hdpi/rsfc_consent_section_recontact.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_consent_section_study_survey.png b/consent/src/main/res/drawable-hdpi/rsfc_consent_section_study_survey.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_consent_section_study_survey.png rename to consent/src/main/res/drawable-hdpi/rsfc_consent_section_study_survey.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_consent_section_study_tasks.png b/consent/src/main/res/drawable-hdpi/rsfc_consent_section_study_tasks.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_consent_section_study_tasks.png rename to consent/src/main/res/drawable-hdpi/rsfc_consent_section_study_tasks.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_consent_section_time_commitment.png b/consent/src/main/res/drawable-hdpi/rsfc_consent_section_time_commitment.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_consent_section_time_commitment.png rename to consent/src/main/res/drawable-hdpi/rsfc_consent_section_time_commitment.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_consent_section_visiting_doctor.png b/consent/src/main/res/drawable-hdpi/rsfc_consent_section_visiting_doctor.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_consent_section_visiting_doctor.png rename to consent/src/main/res/drawable-hdpi/rsfc_consent_section_visiting_doctor.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_consent_section_withdrawing.png b/consent/src/main/res/drawable-hdpi/rsfc_consent_section_withdrawing.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_consent_section_withdrawing.png rename to consent/src/main/res/drawable-hdpi/rsfc_consent_section_withdrawing.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_consent_section_data_gathering.png b/consent/src/main/res/drawable-mdpi/rsfc_consent_section_data_gathering.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_consent_section_data_gathering.png rename to consent/src/main/res/drawable-mdpi/rsfc_consent_section_data_gathering.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_consent_section_data_use.png b/consent/src/main/res/drawable-mdpi/rsfc_consent_section_data_use.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_consent_section_data_use.png rename to consent/src/main/res/drawable-mdpi/rsfc_consent_section_data_use.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_consent_section_potential_benefits_alt.png b/consent/src/main/res/drawable-mdpi/rsfc_consent_section_potential_benefits_alt.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_consent_section_potential_benefits_alt.png rename to consent/src/main/res/drawable-mdpi/rsfc_consent_section_potential_benefits_alt.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_consent_section_privacy.png b/consent/src/main/res/drawable-mdpi/rsfc_consent_section_privacy.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_consent_section_privacy.png rename to consent/src/main/res/drawable-mdpi/rsfc_consent_section_privacy.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_consent_section_recontact.png b/consent/src/main/res/drawable-mdpi/rsfc_consent_section_recontact.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_consent_section_recontact.png rename to consent/src/main/res/drawable-mdpi/rsfc_consent_section_recontact.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_consent_section_study_survey.png b/consent/src/main/res/drawable-mdpi/rsfc_consent_section_study_survey.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_consent_section_study_survey.png rename to consent/src/main/res/drawable-mdpi/rsfc_consent_section_study_survey.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_consent_section_study_tasks.png b/consent/src/main/res/drawable-mdpi/rsfc_consent_section_study_tasks.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_consent_section_study_tasks.png rename to consent/src/main/res/drawable-mdpi/rsfc_consent_section_study_tasks.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_consent_section_time_commitment.png b/consent/src/main/res/drawable-mdpi/rsfc_consent_section_time_commitment.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_consent_section_time_commitment.png rename to consent/src/main/res/drawable-mdpi/rsfc_consent_section_time_commitment.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_consent_section_visiting_doctor.png b/consent/src/main/res/drawable-mdpi/rsfc_consent_section_visiting_doctor.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_consent_section_visiting_doctor.png rename to consent/src/main/res/drawable-mdpi/rsfc_consent_section_visiting_doctor.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_consent_section_withdrawing.png b/consent/src/main/res/drawable-mdpi/rsfc_consent_section_withdrawing.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_consent_section_withdrawing.png rename to consent/src/main/res/drawable-mdpi/rsfc_consent_section_withdrawing.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_consent_section_data_gathering.png b/consent/src/main/res/drawable-xhdpi/rsfc_consent_section_data_gathering.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_consent_section_data_gathering.png rename to consent/src/main/res/drawable-xhdpi/rsfc_consent_section_data_gathering.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_consent_section_data_use.png b/consent/src/main/res/drawable-xhdpi/rsfc_consent_section_data_use.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_consent_section_data_use.png rename to consent/src/main/res/drawable-xhdpi/rsfc_consent_section_data_use.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_consent_section_potential_benefits_alt.png b/consent/src/main/res/drawable-xhdpi/rsfc_consent_section_potential_benefits_alt.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_consent_section_potential_benefits_alt.png rename to consent/src/main/res/drawable-xhdpi/rsfc_consent_section_potential_benefits_alt.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_consent_section_privacy.png b/consent/src/main/res/drawable-xhdpi/rsfc_consent_section_privacy.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_consent_section_privacy.png rename to consent/src/main/res/drawable-xhdpi/rsfc_consent_section_privacy.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_consent_section_recontact.png b/consent/src/main/res/drawable-xhdpi/rsfc_consent_section_recontact.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_consent_section_recontact.png rename to consent/src/main/res/drawable-xhdpi/rsfc_consent_section_recontact.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_consent_section_study_survey.png b/consent/src/main/res/drawable-xhdpi/rsfc_consent_section_study_survey.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_consent_section_study_survey.png rename to consent/src/main/res/drawable-xhdpi/rsfc_consent_section_study_survey.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_consent_section_study_tasks.png b/consent/src/main/res/drawable-xhdpi/rsfc_consent_section_study_tasks.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_consent_section_study_tasks.png rename to consent/src/main/res/drawable-xhdpi/rsfc_consent_section_study_tasks.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_consent_section_time_commitment.png b/consent/src/main/res/drawable-xhdpi/rsfc_consent_section_time_commitment.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_consent_section_time_commitment.png rename to consent/src/main/res/drawable-xhdpi/rsfc_consent_section_time_commitment.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_consent_section_visiting_doctor.png b/consent/src/main/res/drawable-xhdpi/rsfc_consent_section_visiting_doctor.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_consent_section_visiting_doctor.png rename to consent/src/main/res/drawable-xhdpi/rsfc_consent_section_visiting_doctor.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_consent_section_withdrawing.png b/consent/src/main/res/drawable-xhdpi/rsfc_consent_section_withdrawing.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_consent_section_withdrawing.png rename to consent/src/main/res/drawable-xhdpi/rsfc_consent_section_withdrawing.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_data_gathering.png b/consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_data_gathering.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_data_gathering.png rename to consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_data_gathering.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_data_use.png b/consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_data_use.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_data_use.png rename to consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_data_use.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_potential_benefits_alt.png b/consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_potential_benefits_alt.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_potential_benefits_alt.png rename to consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_potential_benefits_alt.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_privacy.png b/consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_privacy.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_privacy.png rename to consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_privacy.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_recontact.png b/consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_recontact.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_recontact.png rename to consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_recontact.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_study_survey.png b/consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_study_survey.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_study_survey.png rename to consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_study_survey.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_study_tasks.png b/consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_study_tasks.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_study_tasks.png rename to consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_study_tasks.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_time_commitment.png b/consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_time_commitment.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_time_commitment.png rename to consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_time_commitment.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_visiting_doctor.png b/consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_visiting_doctor.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_visiting_doctor.png rename to consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_visiting_doctor.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_withdrawing.png b/consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_withdrawing.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_consent_section_withdrawing.png rename to consent/src/main/res/drawable-xxhdpi/rsfc_consent_section_withdrawing.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_data_gathering.png b/consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_data_gathering.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_data_gathering.png rename to consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_data_gathering.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_data_use.png b/consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_data_use.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_data_use.png rename to consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_data_use.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_potential_benefits_alt.png b/consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_potential_benefits_alt.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_potential_benefits_alt.png rename to consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_potential_benefits_alt.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_privacy.png b/consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_privacy.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_privacy.png rename to consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_privacy.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_recontact.png b/consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_recontact.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_recontact.png rename to consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_recontact.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_study_survey.png b/consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_study_survey.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_study_survey.png rename to consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_study_survey.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_study_tasks.png b/consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_study_tasks.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_study_tasks.png rename to consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_study_tasks.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_time_commitment.png b/consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_time_commitment.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_time_commitment.png rename to consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_time_commitment.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_visiting_doctor.png b/consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_visiting_doctor.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_visiting_doctor.png rename to consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_visiting_doctor.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_withdrawing.png b/consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_withdrawing.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_consent_section_withdrawing.png rename to consent/src/main/res/drawable-xxxhdpi/rsfc_consent_section_withdrawing.png diff --git a/backbone/src/main/res/layout/rsb_step_layout_consent_doc.xml b/consent/src/main/res/layout/rsfc_step_layout_consent_doc.xml similarity index 77% rename from backbone/src/main/res/layout/rsb_step_layout_consent_doc.xml rename to consent/src/main/res/layout/rsfc_step_layout_consent_doc.xml index fbba22e12..85102ad1b 100644 --- a/backbone/src/main/res/layout/rsb_step_layout_consent_doc.xml +++ b/consent/src/main/res/layout/rsfc_step_layout_consent_doc.xml @@ -11,11 +11,11 @@ android:layout_height="0dp" android:layout_weight="1" /> - + app:negativeActionTitle="@string/rsf_disagree" + app:positiveActionTitle="@string/rsf_agree" /> \ No newline at end of file diff --git a/backbone/src/main/res/layout/rsb_step_layout_consent_signature.xml b/consent/src/main/res/layout/rsfc_step_layout_consent_signature.xml similarity index 74% rename from backbone/src/main/res/layout/rsb_step_layout_consent_signature.xml rename to consent/src/main/res/layout/rsfc_step_layout_consent_signature.xml index 8cd2c3a5f..9f47175a2 100644 --- a/backbone/src/main/res/layout/rsb_step_layout_consent_signature.xml +++ b/consent/src/main/res/layout/rsfc_step_layout_consent_signature.xml @@ -10,8 +10,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/image" - android:layout_marginLeft="@dimen/rsb_margin_left" - android:layout_marginRight="@dimen/rsb_margin_right" + android:layout_marginLeft="@dimen/rsf_margin_left" + android:layout_marginRight="@dimen/rsf_margin_right" android:layout_marginTop="20dp" android:textColor="?attr/colorAccent" @@ -25,32 +25,32 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/title" - android:layout_marginLeft="@dimen/rsb_margin_left" - android:layout_marginRight="@dimen/rsb_margin_right" + android:layout_marginLeft="@dimen/rsf_margin_left" + android:layout_marginRight="@dimen/rsf_margin_right" android:layout_marginTop="36dp" tools:text="@string/lorem_medium" /> - - - + android:text="@string/rsfc_consent_signature_clear" + android:textColor="@color/rsf_submit_bar_negative" /> diff --git a/backbone/src/main/res/layout/rsb_step_layout_consent_visual.xml b/consent/src/main/res/layout/rsfc_step_layout_consent_visual.xml similarity index 75% rename from backbone/src/main/res/layout/rsb_step_layout_consent_visual.xml rename to consent/src/main/res/layout/rsfc_step_layout_consent_visual.xml index 5a4dcf88f..c5f33512a 100644 --- a/backbone/src/main/res/layout/rsb_step_layout_consent_visual.xml +++ b/consent/src/main/res/layout/rsfc_step_layout_consent_visual.xml @@ -11,15 +11,15 @@ android:layout_height="180dp" android:layout_centerHorizontal="true" android:scaleType="centerInside" - tools:src="@drawable/rsb_debug_gray" /> + tools:src="@drawable/rsf_debug_gray" /> @@ -45,10 +45,10 @@ android:layout_height="wrap_content" android:layout_below="@+id/summary" android:layout_marginLeft="48dp" - android:layout_marginRight="@dimen/rsb_margin_right" - android:paddingBottom="@dimen/rsb_padding_medium" - android:paddingRight="@dimen/rsb_padding_medium" - android:paddingTop="@dimen/rsb_padding_medium" + android:layout_marginRight="@dimen/rsf_margin_right" + android:paddingBottom="@dimen/rsf_padding_medium" + android:paddingRight="@dimen/rsf_padding_medium" + android:paddingTop="@dimen/rsf_padding_medium" android:textColor="?attr/colorAccent" tools:text="More Info" /> diff --git a/consent/src/main/res/values/attrs.xml b/consent/src/main/res/values/attrs.xml new file mode 100644 index 000000000..7c32f3f3b --- /dev/null +++ b/consent/src/main/res/values/attrs.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/consent/src/main/res/values/strings.xml b/consent/src/main/res/values/strings.xml new file mode 100644 index 000000000..b44d202d9 --- /dev/null +++ b/consent/src/main/res/values/strings.xml @@ -0,0 +1,83 @@ + + + + Consent + Welcome + Data Gathering + Privacy + Data Use + Time Commitment + Study Survey + Study Tasks + Withdrawing + Learn More + + + Learn more + Learn more about how data is + gathered + + Learn more about how data is used + Learn more about how your privacy and + identity are protected + + Learn more about the study first + Learn more about the study survey + + Learn more about the study\'s + impact on your time + + Learn more about the tasks involved + + Learn more about withdrawing + + + Sharing Options + Share my data with %1$s and qualified researchers + worldwide + + Not sharing your data + Only share my data with %1$s +
+ Learn more about data sharing]]> +
+ + + Review + Review + By agreeing you confirm that you read the information + and that you wish to take part in this research study. + + Review the form below, and tap Agree if you\'re + ready to continue. + + Cancel + + + Consent + Full Name + Date of Birth + Required + + + Signature + By agreeing you confirm that you read the consent + and that you wish to take part in this research study. + + Please sign using your finger on the line + below. + + Sign Here + Clear + + + Quiz + Quiz Evaluation + Try Again + Review Consent + Retake Quiz + Great Job! + +
diff --git a/consent/src/main/res/values/styles.xml b/consent/src/main/res/values/styles.xml new file mode 100644 index 000000000..2e0460f14 --- /dev/null +++ b/consent/src/main/res/values/styles.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/consent/src/test/java/org/researchstack/feature/consent/ExampleUnitTest.java b/consent/src/test/java/org/researchstack/feature/consent/ExampleUnitTest.java new file mode 100644 index 000000000..bcdf8f5dd --- /dev/null +++ b/consent/src/test/java/org/researchstack/feature/consent/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package org.researchstack.feature.consent; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/foundation/.gitignore b/foundation/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/foundation/.gitignore @@ -0,0 +1 @@ +/build diff --git a/foundation/build.gradle b/foundation/build.gradle new file mode 100644 index 000000000..428d564a4 --- /dev/null +++ b/foundation/build.gradle @@ -0,0 +1,170 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +apply plugin: 'com.github.dcendents.android-maven' +apply plugin: 'com.jfrog.bintray' + +version = research_stack_version + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 19 + targetSdkVersion 28 + versionCode 1 + versionName version + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + resourcePrefix 'rsf_' + compileOptions { + sourceCompatibility = '1.8' + targetCompatibility = '1.8' + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + buildToolsVersion '28.0.3' +} + +Properties properties = new Properties() +properties.load(project.rootProject.file('local.properties').newDataInputStream()) + +ext { + bintrayRepo = 'ResearchStack' + bintrayName = 'Foundation' + + publishedGroupId = 'org.researchstack' + libraryName = 'Foundation' + artifact = 'foundation' + + libraryDescription = 'Foundation' + + siteUrl = 'https://researchstack.org' + gitUrl = 'https://github.com/ResearchStack/ResearchStack.git' + + libraryVersion = version + + userOrgName = 'researchstack' + developerId = properties.getProperty("bintray.user") + developerName = properties.getProperty("bintray.developerName") + developerEmail = properties.getProperty("bintray.developerEmail") + + licenseName = 'The Apache Software License, Version 2.0' + licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + allLicenses = ["Apache-2.0"] +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.legacy:legacy-preference-v14:1.0.0' + implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.core:core:1.0.1' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation "com.google.code.gson:gson:$gson_version" + +} + +group = publishedGroupId // Maven Group ID for the artifact + +install { + repositories.mavenInstaller { + // This generates POM.xml with proper parameters + pom { + project { + packaging 'aar' + groupId publishedGroupId + artifactId artifact + + // Add your description here + name libraryName + description libraryDescription + url siteUrl + + // Set your license + licenses { + license { + name licenseName + url licenseUrl + } + } + developers { + developer { + id developerId + name developerName + email developerEmail + } + } + scm { + connection gitUrl + developerConnection gitUrl + url siteUrl + } + } + } + } +} + +if (project.hasProperty("android")) { // Android libraries + task sourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs + } + + task javadoc(type: Javadoc) { + failOnError false + source = android.sourceSets.main.java.srcDirs + } + + afterEvaluate { + javadoc.classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + javadoc.classpath += files(android.libraryVariants.collect { variant -> + variant.javaCompile.classpath.files + }) + } +} else { // Java libraries + task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from sourceSets.main.allSource + } +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives javadocJar + archives sourcesJar +} + +bintray { + user = properties.getProperty("bintray.user") + key = properties.getProperty("bintray.apikey") + + configurations = ['archives'] + pkg { + repo = bintrayRepo + name = bintrayName + userOrg = userOrgName + desc = libraryDescription + websiteUrl = siteUrl + vcsUrl = gitUrl + licenses = allLicenses + publish = true + } +} diff --git a/foundation/proguard-rules.pro b/foundation/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/foundation/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/foundation/src/androidTest/java/org/researchstack/foundation/ExampleInstrumentedTest.java b/foundation/src/androidTest/java/org/researchstack/foundation/ExampleInstrumentedTest.java new file mode 100644 index 000000000..797eabc7f --- /dev/null +++ b/foundation/src/androidTest/java/org/researchstack/foundation/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package org.researchstack.foundation; + +import android.content.Context; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("org.researchstack.foundation.test", appContext.getPackageName()); + } +} diff --git a/foundation/src/main/AndroidManifest.xml b/foundation/src/main/AndroidManifest.xml new file mode 100644 index 000000000..8c59fe33a --- /dev/null +++ b/foundation/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/backbone/src/main/java/org/researchstack/backbone/task/OrderedTask.java b/foundation/src/main/java/org/researchstack/foundation/components/common/task/OrderedTask.java similarity index 90% rename from backbone/src/main/java/org/researchstack/backbone/task/OrderedTask.java rename to foundation/src/main/java/org/researchstack/foundation/components/common/task/OrderedTask.java index b2850676a..d3e094206 100644 --- a/backbone/src/main/java/org/researchstack/backbone/task/OrderedTask.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/common/task/OrderedTask.java @@ -1,11 +1,12 @@ -package org.researchstack.backbone.task; +package org.researchstack.foundation.components.common.task; import android.content.Context; -import org.researchstack.backbone.R; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.step.Step; +import org.researchstack.foundation.core.models.task.Task; import java.io.Serializable; import java.util.ArrayList; @@ -122,7 +123,7 @@ public String getTitleForStep(Context context, Step step) { String title = super.getTitleForStep(context, step); if (TextUtils.isEmpty(title)) { int currentIndex = steps.indexOf(step); - title = context.getString(R.string.rsb_format_step_title, + title = context.getString(R.string.rsf_format_step_title, currentIndex + 1, steps.size()); } @@ -132,7 +133,7 @@ public String getTitleForStep(Context context, Step step) { /** * Validates that there are no duplicate identifiers in the list of steps * - * @throws org.researchstack.backbone.task.Task.InvalidTaskException + * @throws org.researchstack.foundation.task.Task.InvalidTaskException */ @Override public void validateParameters() { diff --git a/foundation/src/main/java/org/researchstack/foundation/components/common/ui/callbacks/StepCallbacks.java b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/callbacks/StepCallbacks.java new file mode 100644 index 000000000..b62c76447 --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/callbacks/StepCallbacks.java @@ -0,0 +1,17 @@ +package org.researchstack.foundation.components.common.ui.callbacks; + +import org.jetbrains.annotations.Nullable; +import org.researchstack.foundation.core.interfaces.IResult; +import org.researchstack.foundation.core.interfaces.IStep; + +public interface StepCallbacks { + int ACTION_PREV = -1; + int ACTION_NONE = 0; + int ACTION_NEXT = 1; + int ACTION_END = 2; + + void onSaveStep(int action, IStep step, @Nullable IResult result); + + @Deprecated + void onCancelStep(); +} diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/views/FixedSubmitBarLayout.java b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/layout/FixedSubmitBarLayout.java similarity index 83% rename from backbone/src/main/java/org/researchstack/backbone/ui/views/FixedSubmitBarLayout.java rename to foundation/src/main/java/org/researchstack/foundation/components/common/ui/layout/FixedSubmitBarLayout.java index bc5125378..762b7aa34 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/views/FixedSubmitBarLayout.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/layout/FixedSubmitBarLayout.java @@ -1,8 +1,8 @@ -package org.researchstack.backbone.ui.views; +package org.researchstack.foundation.components.common.ui.layout; import android.annotation.TargetApi; import android.content.Context; -import android.support.v4.view.ViewCompat; +import androidx.core.view.ViewCompat; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -11,8 +11,9 @@ import android.widget.FrameLayout; import android.widget.ScrollView; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ui.step.layout.StepLayout; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.foundation.components.common.ui.views.ObservableScrollView; public abstract class FixedSubmitBarLayout extends FrameLayout implements StepLayout { public FixedSubmitBarLayout(Context context) { @@ -41,17 +42,17 @@ public FixedSubmitBarLayout(Context context, AttributeSet attrs, int defStyleAtt private void init() { // Init root LayoutInflater inflater = LayoutInflater.from(getContext()); - inflater.inflate(R.layout.rsb_layout_fixed_submit_bar, this, true); + inflater.inflate(R.layout.rsf_layout_fixed_submit_bar, this, true); // Add contentContainer to the layout - ViewGroup contentContainer = (ViewGroup) findViewById(R.id.rsb_content_container); + ViewGroup contentContainer = (ViewGroup) findViewById(R.id.rsf_content_container); View content = inflater.inflate(getContentResourceId(), contentContainer, false); contentContainer.addView(content, 0); // Init scrollview and submit bar guide positioning - final View submitBarGuide = findViewById(R.id.rsb_submit_bar_guide); - final SubmitBar submitBar = (SubmitBar) findViewById(R.id.rsb_submit_bar); - ObservableScrollView scrollView = (ObservableScrollView) findViewById(R.id.rsb_content_container_scrollview); + final View submitBarGuide = findViewById(R.id.rsf_submit_bar_guide); + final SubmitBar submitBar = (SubmitBar) findViewById(R.id.rsf_submit_bar); + final ObservableScrollView scrollView = (ObservableScrollView) findViewById(R.id.rsf_content_container_scrollview); scrollView.setScrollListener(scrollY -> onScrollChanged(scrollView, submitBarGuide, submitBar)); scrollView.getViewTreeObserver() .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/StepLayout.java b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/layout/StepLayout.java similarity index 53% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/layout/StepLayout.java rename to foundation/src/main/java/org/researchstack/foundation/components/common/ui/layout/StepLayout.java index 49f87245a..66936bd94 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/StepLayout.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/layout/StepLayout.java @@ -1,10 +1,10 @@ -package org.researchstack.backbone.ui.step.layout; +package org.researchstack.foundation.components.common.ui.layout; import android.view.View; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; public interface StepLayout { void initialize(Step step, StepResult result); diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/views/IconTab.java b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/IconTab.java similarity index 94% rename from backbone/src/main/java/org/researchstack/backbone/ui/views/IconTab.java rename to foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/IconTab.java index 772edb7d0..312fc5b7b 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/views/IconTab.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/IconTab.java @@ -1,11 +1,11 @@ -package org.researchstack.backbone.ui.views; +package org.researchstack.foundation.components.common.ui.views; import android.annotation.TargetApi; import android.content.Context; import android.graphics.drawable.Drawable; -import android.support.annotation.DrawableRes; -import android.support.annotation.StringRes; -import android.support.v4.graphics.drawable.DrawableCompat; +import androidx.annotation.DrawableRes; +import androidx.annotation.StringRes; +import androidx.core.graphics.drawable.DrawableCompat; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; @@ -17,8 +17,7 @@ import android.widget.TextView; import android.widget.Toast; -import org.researchstack.backbone.R; - +import org.researchstack.foundation.R; public class IconTab extends RelativeLayout implements View.OnLongClickListener { private TextView title; @@ -47,7 +46,7 @@ public IconTab(Context context, AttributeSet attrs, int defStyleAttr, int defSty } private void init() { - LayoutInflater.from(getContext()).inflate(R.layout.rsb_view_icon_tab, this, true); + LayoutInflater.from(getContext()).inflate(R.layout.rsf_view_icon_tab, this, true); title = (TextView) findViewById(R.id.title); icon = (ImageView) findViewById(R.id.icon); diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/views/IconTabLayout.java b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/IconTabLayout.java similarity index 90% rename from backbone/src/main/java/org/researchstack/backbone/ui/views/IconTabLayout.java rename to foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/IconTabLayout.java index 65f598a09..10bdeb195 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/views/IconTabLayout.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/IconTabLayout.java @@ -1,14 +1,14 @@ -package org.researchstack.backbone.ui.views; +package org.researchstack.foundation.components.common.ui.views; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Drawable; -import android.support.annotation.Nullable; -import android.support.design.widget.TabLayout; +import androidx.annotation.Nullable; +import com.google.android.material.tabs.TabLayout; import android.util.AttributeSet; -import org.researchstack.backbone.R; +import org.researchstack.foundation.R; public class IconTabLayout extends TabLayout { private int tabIconColor = Color.WHITE; @@ -29,7 +29,7 @@ public IconTabLayout(Context context, @Nullable AttributeSet attrs, int defStyle final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.IconTabLayout, defStyleAttr, - R.style.Widget_Backbone_IconTabLayout); + R.style.Widget_Foundation_IconTabLayout); Drawable background = a.getDrawable(R.styleable.IconTabLayout_android_background); setBackground(background); diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/views/ObservableScrollView.java b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/ObservableScrollView.java similarity index 94% rename from backbone/src/main/java/org/researchstack/backbone/ui/views/ObservableScrollView.java rename to foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/ObservableScrollView.java index 02065466a..04b689814 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/views/ObservableScrollView.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/ObservableScrollView.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.views; +package org.researchstack.foundation.components.common.ui.views; import android.annotation.TargetApi; import android.content.Context; diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/views/SubmitBar.java b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/SubmitBar.java similarity index 78% rename from backbone/src/main/java/org/researchstack/backbone/ui/views/SubmitBar.java rename to foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/SubmitBar.java index a927b53f9..2553a9a04 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/views/SubmitBar.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/SubmitBar.java @@ -1,21 +1,17 @@ -package org.researchstack.backbone.ui.views; +package org.researchstack.foundation.components.common.ui.views; import android.content.Context; import android.content.res.TypedArray; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; -import com.jakewharton.rxbinding.view.RxView; - -import org.researchstack.backbone.R; -import org.researchstack.backbone.utils.ThemeUtils; - -import rx.functions.Action1; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.utils.ThemeUtils; public class SubmitBar extends LinearLayout { private TextView positiveView; @@ -32,12 +28,12 @@ public SubmitBar(Context context, @Nullable AttributeSet attrs) { public SubmitBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - LayoutInflater.from(getContext()).inflate(R.layout.rsb_view_submitbar, this, true); + LayoutInflater.from(getContext()).inflate(R.layout.rsf_view_submitbar, this, true); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SubmitBar, defStyleAttr, - R.style.Widget_Backbone_SubmitBar); + R.style.Widget_Foundation_SubmitBar); setBackground(a.getDrawable(R.styleable.SubmitBar_android_background)); @@ -49,7 +45,7 @@ public SubmitBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr negativeView = (TextView) findViewById(R.id.bar_submit_negative); negativeView.setText(a.getString(R.styleable.SubmitBar_negativeActionTitle)); negativeView.setTextColor(a.getColor(R.styleable.SubmitBar_negativeActionColor, - ContextCompat.getColor(context, R.color.rsb_submit_bar_negative))); + ContextCompat.getColor(context, R.color.rsf_submit_bar_negative))); a.recycle(); } @@ -66,8 +62,8 @@ public void setPositiveTitle(String title) { positiveView.setText(title); } - public void setPositiveAction(Action1 submit) { - RxView.clicks(this.positiveView).subscribe(submit); + public void setPositiveAction(OnClickListener listener) { + this.positiveView.setOnClickListener(listener); } public View getPositiveActionView() { @@ -87,8 +83,8 @@ public void setNegativeTitle(String title) { negativeView.setText(title); } - public void setNegativeAction(Action1 submit) { - RxView.clicks(this.negativeView).subscribe(submit); + public void setNegativeAction(OnClickListener listener) { + this.negativeView.setOnClickListener(listener); } public View getNegativeActionView() { diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/TextViewLinkHandler.java b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/TextViewLinkHandler.java similarity index 94% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/layout/TextViewLinkHandler.java rename to foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/TextViewLinkHandler.java index 725e103af..ca334daa9 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/TextViewLinkHandler.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/common/ui/views/TextViewLinkHandler.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.step.layout; +package org.researchstack.foundation.components.common.ui.views; import android.text.Layout; import android.text.Spannable; diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/ITaskProvider.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/ITaskProvider.kt new file mode 100644 index 000000000..56c950349 --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/ITaskProvider.kt @@ -0,0 +1,7 @@ +package org.researchstack.foundation.components.presentation + +import org.researchstack.foundation.core.interfaces.ITask + +interface ITaskProvider { + fun task(identifier: String): ITask? +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/TaskPresentationCallback.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/TaskPresentationCallback.kt new file mode 100644 index 000000000..ecad3e41c --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/TaskPresentationCallback.kt @@ -0,0 +1,8 @@ +package org.researchstack.foundation.components.presentation + +import org.researchstack.foundation.core.interfaces.IResult +import org.researchstack.foundation.core.interfaces.ITask + +abstract class TaskPresentationCallback { + abstract fun onTaskPresentationFinished(task: TaskType, result: ResultType?) +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/TaskPresentationFragment.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/TaskPresentationFragment.kt new file mode 100644 index 000000000..f51726462 --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/TaskPresentationFragment.kt @@ -0,0 +1,237 @@ +package org.researchstack.foundation.components.presentation + +import android.content.Context +import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.Toolbar +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import org.researchstack.foundation.R +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks +import org.researchstack.foundation.components.presentation.interfaces.IStepFragment +import org.researchstack.foundation.components.presentation.interfaces.IStepFragmentProvider +import org.researchstack.foundation.components.presentation.interfaces.ITaskNavigator +import org.researchstack.foundation.core.interfaces.IResult +import org.researchstack.foundation.core.interfaces.IStep +import org.researchstack.foundation.core.interfaces.ITask +import java.lang.RuntimeException +import java.util.* + +abstract class TaskPresentationFragment(): androidx.fragment.app.Fragment(), StepCallbacks { + + public var taskProvider: ITaskProvider? = null + public var stepFragmentProvider: IStepFragmentProvider? = null + + protected var _task: TaskType? = null + public val task: TaskType + get() = this._task!! + + protected var _taskNavigator: ITaskNavigator? = null + public val taskNavigator: ITaskNavigator + get() = this._taskNavigator!! + + public var callback: TaskPresentationCallback? = null + + var _currentStep: StepType? = null + var _currentFragment: IStepFragment? = null + + val currentStep: StepType? + get() = this._currentStep + + var _result: ResultType? = null + val result: ResultType + get() = this._result!! + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + + val view = inflater.inflate(R.layout.rsf_fragment_task_presentation, container, false); + + val toolbar = view.findViewById(R.id.toolbar) as Toolbar? + + val appCompatActivity: AppCompatActivity = this.activity as AppCompatActivity + appCompatActivity.setSupportActionBar(toolbar) + appCompatActivity.supportActionBar!!.setDisplayHomeAsUpEnabled(true) + + this.initialize(savedInstanceState) + + return view + } + + abstract fun initialize(savedInstanceState: Bundle?) + + override fun onResume() { + + val currentStep = this.currentStep + + if (currentStep == null) { + this.taskNavigator.getStepAfterStep(null, this.result)?.let { firstStep -> + showStep(firstStep) + } + } + else { + showStep(currentStep) + } + + super.onResume() + } + + protected fun showNextStep() { + val nextStep = this.taskNavigator.getStepAfterStep(this.currentStep, this.result) + if (nextStep == null) { + this.saveAndFinish(false) + } else { + showStep(nextStep) + } + } + + protected fun showPreviousStep() { + val previousStep = this.taskNavigator.getStepBeforeStep(this.currentStep, this.result) + if (previousStep == null) { + saveAndFinish(true) + } else { + showStep(previousStep) + } + } + + private fun showStep(step: StepType) { + val currentStepPosition = this.currentStep?.let { + this.taskNavigator.getProgressOfCurrentStep(it, this.result).current + } + + val newStepPosition = this.taskNavigator.getProgressOfCurrentStep(step, this.result).current + + val stepFragment = this.getFragmentForStep(step) + this._currentFragment = stepFragment + + val transaction = childFragmentManager.beginTransaction() + + if (currentStepPosition != null) { + if (newStepPosition > currentStepPosition) { + transaction.setCustomAnimations(R.anim.rsf_slide_in_right, R.anim.rsf_slide_out_left) + } + else { + transaction.setCustomAnimations(R.anim.rsf_slide_in_left, R.anim.rsf_slide_out_right) + } + + transaction + .replace(R.id.rsf_content_step, stepFragment.fragment) + .commit() + } + else { + transaction + .add(R.id.rsf_content_step, stepFragment.fragment) + .commit() + } + + childFragmentManager.executePendingTransactions() + + Log.d("DEBUG", ""+childFragmentManager.fragments.size) + + this._currentStep = step + } + + abstract fun getStepResult(taskResult: ResultType, stepIdentifier: String): IResult? + abstract fun setStepResult(taskResult: ResultType, stepIdentifier: String, stepResult: IResult) + + protected fun getFragmentForStep(step: StepType): IStepFragment { + + val hostFragment = this + + // Change the title on the activity + val title: String = { + val title = this.taskNavigator.getTitleForStep(step) + if (title != "") { + title + } + else { + this.taskNavigator.getTitleForStep(this.activity!!, step) + } + + }() + + setActionBarTitle(title) + + // Get result from the TaskResult, can be null + + val stepResult: IResult? = this.getStepResult(this.result, step.identifier) + + val fragment = createFragmentFromStep(step) + if (fragment == null) { + throw RuntimeException("Cannot create fragment for step ${step.identifier}") + } + + val stepFragment: IStepFragment = fragment.apply { + this.initialize(step, stepResult) + this.setCallbacks(hostFragment) + } + + return stepFragment + } + + private fun createFragmentFromStep(step: IStep): IStepFragment? { + return this.stepFragmentProvider?.stepFragment(this.activity!! as Context, step) + } + + protected abstract fun saveAndFinish(clearResult: Boolean) + + fun setActionBarTitle(title: String) { + + val appCompatActivity: AppCompatActivity = this.activity as AppCompatActivity + + val actionBar = appCompatActivity.supportActionBar + if (actionBar != null) { + actionBar.setTitle(title) + } + } + + //JDK - 4/16/19 - as part of future work, we will be removing conformance to StepCallbacks + //This means that onSaveStep, onCancelStep, onExecuteStepAction and showConfirmExitDialog will + //probably all go away + protected fun onExecuteStepAction(action: Int) { + if (action == StepCallbacks.ACTION_NEXT) { + showNextStep() + } else if (action == StepCallbacks.ACTION_PREV) { + showPreviousStep() + } else if (action == StepCallbacks.ACTION_END) { + showConfirmExitDialog() + } else if (action == StepCallbacks.ACTION_NONE) { + // Used when onSaveInstanceState is called of a view. No action is taken. + } else { + throw IllegalArgumentException("Action with value " + action + " is invalid. " + + "See StepCallbacks for allowable arguments") + } + } + + private fun showConfirmExitDialog() { + val alertDialog = AlertDialog.Builder(this.activity!!).setTitle( + "Are you sure you want to exit?") + .setMessage(R.string.lorem_medium) + .setPositiveButton("End Task") { dialog, which -> saveAndFinish(true) } + .setNegativeButton("Cancel", null) + .create() + alertDialog.show() + } + + public fun onBackPressed() { + notifyStepOfBackPress() + } + + private fun notifyStepOfBackPress() { + this._currentFragment?.onBackPressed() + } + + + override fun onSaveStep(action: Int, step: IStep, result: IResult?) { + result?.let { setStepResult(this.result, step.identifier, it) } + onExecuteStepAction(action) + } + + override fun onCancelStep() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleStepFragment.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleStepFragment.kt new file mode 100644 index 000000000..2bf52f60c --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleStepFragment.kt @@ -0,0 +1,69 @@ +package org.researchstack.foundation.components.presentation.compatibility + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import org.researchstack.foundation.R +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks +import org.researchstack.foundation.components.common.ui.layout.StepLayout +import org.researchstack.foundation.components.presentation.interfaces.IStepFragment +import org.researchstack.foundation.core.interfaces.IResult +import org.researchstack.foundation.core.interfaces.IStep +import org.researchstack.foundation.core.models.result.StepResult +import org.researchstack.foundation.core.models.step.Step + +public class BackwardsCompatibleStepFragment(): androidx.fragment.app.Fragment(), IStepFragment { + + companion object { + + fun newInstance(stepLayout: StepLayout): BackwardsCompatibleStepFragment { + val fragment = BackwardsCompatibleStepFragment() + fragment.stepLayout = stepLayout + return fragment + } + } + + //this will implement the traditional step layout + var stepLayout: StepLayout? = null + + override val fragment: androidx.fragment.app.Fragment + get() = this + + private fun getLayoutParams(stepLayout: StepLayout): FrameLayout.LayoutParams { + var lp: FrameLayout.LayoutParams? = stepLayout.layout.layoutParams?.let { + it as? FrameLayout.LayoutParams + } + if (lp == null) { + lp = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) + } + return lp + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + + val layout = this.stepLayout!! + val view = inflater.inflate(R.layout.rsf_fragment_step_compat, container, false) + val containerView: FrameLayout = view.findViewById(R.id.rsf_content_layout) as FrameLayout + + val lp = getLayoutParams(layout) + containerView.addView(layout.layout, 0, lp) + + return view + } + + override fun onBackPressed() { + this.stepLayout!!.isBackEventConsumed + } + + override fun initialize(step: IStep, result: IResult?) { + this.stepLayout!!.initialize(step as Step, result?.let { it as? StepResult<*> }) + } + + override fun setCallbacks(callbacks: StepCallbacks) { + this.stepLayout!!.setCallbacks(callbacks) + } + +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleStepFragmentProvider.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleStepFragmentProvider.kt new file mode 100644 index 000000000..fab849d94 --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleStepFragmentProvider.kt @@ -0,0 +1,34 @@ +package org.researchstack.foundation.components.presentation.compatibility + +import android.content.Context +import org.researchstack.foundation.components.common.ui.layout.StepLayout +import org.researchstack.foundation.components.presentation.interfaces.IStepFragment +import org.researchstack.foundation.components.presentation.interfaces.IStepFragmentProvider +import org.researchstack.foundation.core.interfaces.IStep + + +public class BackwardsCompatibleStepFragmentProvider(val stepLayoutProvider: IStepLayoutProvider): IStepFragmentProvider { + + override fun stepFragment(context: Context, step: IStep): IStepFragment? { + + try { + + val stepLayout = this.stepLayoutProvider.stepLayout(step)?.let { + val constructor = it.getConstructor(Context::class.java) + constructor.newInstance(context) + } as? StepLayout + + if (stepLayout != null) { + val fragment = BackwardsCompatibleStepFragment.newInstance(stepLayout) + return fragment + } + else { + throw RuntimeException("Could not instantiate Step Layout") + } + + } catch (e: Exception) { + throw RuntimeException(e) + } + + } +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleStepLayoutProvider.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleStepLayoutProvider.kt new file mode 100644 index 000000000..0fccb89f7 --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleStepLayoutProvider.kt @@ -0,0 +1,10 @@ +package org.researchstack.foundation.components.presentation.compatibility + +import org.researchstack.foundation.core.interfaces.IStep +import org.researchstack.foundation.core.models.step.Step + +public class BackwardsCompatibleStepLayoutProvider(): IStepLayoutProvider { + override fun stepLayout(step: IStep): Class<*>? { + return (step as? Step)?.stepLayoutClass + } +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleTaskPresentationFragment.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleTaskPresentationFragment.kt new file mode 100644 index 000000000..4205cca85 --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/BackwardsCompatibleTaskPresentationFragment.kt @@ -0,0 +1,74 @@ +package org.researchstack.foundation.components.presentation.compatibility + +import android.os.Bundle +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks +import org.researchstack.foundation.components.presentation.TaskPresentationCallback +import org.researchstack.foundation.components.presentation.TaskPresentationFragment +import org.researchstack.foundation.components.presentation.interfaces.IStepFragmentProvider +import org.researchstack.foundation.core.interfaces.IResult +import org.researchstack.foundation.core.models.result.StepResult +import org.researchstack.foundation.core.models.result.TaskResult +import org.researchstack.foundation.core.models.step.Step +import org.researchstack.foundation.core.models.task.Task +import java.util.* + +open class BackwardsCompatibleTaskPresentationFragment: TaskPresentationFragment(), StepCallbacks { + + companion object { + val EXTRA_TASK_IDENTIFIER = "BackwardsCompatibleTaskPresentationFragment.ExtraTaskIdentifier" + val EXTRA_TASK_RESULT = "BackwardsCompatibleTaskPresentationFragment.ExtraTaskResult" + val EXTRA_STEP = "BackwardsCompatibleTaskPresentationFragment.ExtraStep" + + fun newInstance( + taskIdentifier: String, + stepFragmentProvider: IStepFragmentProvider, + callback: TaskPresentationCallback + ): BackwardsCompatibleTaskPresentationFragment { + val fragment = BackwardsCompatibleTaskPresentationFragment() + val args = Bundle() + args.putString(EXTRA_TASK_IDENTIFIER, taskIdentifier) + fragment.setArguments(args) + fragment.stepFragmentProvider = stepFragmentProvider + fragment.callback = callback + return fragment + } + + } + + override fun initialize(savedInstanceState: Bundle?) { + + if (savedInstanceState == null) { + val taskIdentifier: String = this.arguments!!.getString(BackwardsCompatibleTaskPresentationFragment.EXTRA_TASK_IDENTIFIER)!! + this._task = this.taskProvider!!.task(taskIdentifier) as Task + this._taskNavigator = this.task + this._result = TaskResult(this.task.identifier) + this.result.setStartDate(Date()) + } else { + val taskIdentifier: String = savedInstanceState.getString(BackwardsCompatibleTaskPresentationFragment.EXTRA_TASK_IDENTIFIER)!! + this._task = this.taskProvider!!.task(taskIdentifier) as Task + this._taskNavigator = this.task + this._result = savedInstanceState.getSerializable(BackwardsCompatibleTaskPresentationFragment.EXTRA_TASK_RESULT) as TaskResult + this._currentStep = savedInstanceState.getSerializable(BackwardsCompatibleTaskPresentationFragment.EXTRA_STEP) as Step + } + + this.task.validateParameters() + } + + override fun getStepResult(taskResult: TaskResult, stepIdentifier: String): IResult? { + return taskResult.getStepResult(stepIdentifier) + } + + override fun setStepResult(taskResult: TaskResult, stepIdentifier: String, stepResult: IResult) { + taskResult.setStepResultForStepIdentifier(stepIdentifier, stepResult as StepResult<*>) + } + + override fun saveAndFinish(clearResult: Boolean) { + if (clearResult) { + this.callback!!.onTaskPresentationFinished(this.task, null) + } + else { + this.result.setEndDate(Date()) + this.callback!!.onTaskPresentationFinished(this.task, this.result) + } + } +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/IStepLayoutProvider.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/IStepLayoutProvider.kt new file mode 100644 index 000000000..497192c92 --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/compatibility/IStepLayoutProvider.kt @@ -0,0 +1,7 @@ +package org.researchstack.foundation.components.presentation.compatibility + +import org.researchstack.foundation.core.interfaces.IStep + +interface IStepLayoutProvider { + fun stepLayout(step: IStep): Class<*>? +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/interfaces/IStepFragment.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/interfaces/IStepFragment.kt new file mode 100644 index 000000000..1bacb507c --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/interfaces/IStepFragment.kt @@ -0,0 +1,15 @@ +package org.researchstack.foundation.components.presentation.interfaces + +import androidx.fragment.app.Fragment +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks +import org.researchstack.foundation.core.interfaces.IResult +import org.researchstack.foundation.core.interfaces.IStep + +interface IStepFragment { + fun initialize(step: IStep, result: IResult?) + //TODO: JDK - 4/13/19 - Understand if we need to change StepCallbacks + //This interface may change depending on work on Actions + fun setCallbacks(callbacks: StepCallbacks) + fun onBackPressed() + val fragment: androidx.fragment.app.Fragment +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/interfaces/IStepFragmentProvider.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/interfaces/IStepFragmentProvider.kt new file mode 100644 index 000000000..6cdcde6d3 --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/interfaces/IStepFragmentProvider.kt @@ -0,0 +1,8 @@ +package org.researchstack.foundation.components.presentation.interfaces + +import android.content.Context +import org.researchstack.foundation.core.interfaces.IStep + +interface IStepFragmentProvider { + fun stepFragment(context: Context, step: IStep): IStepFragment? +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/components/presentation/interfaces/ITaskNavigator.kt b/foundation/src/main/java/org/researchstack/foundation/components/presentation/interfaces/ITaskNavigator.kt new file mode 100644 index 000000000..dff1fa42f --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/presentation/interfaces/ITaskNavigator.kt @@ -0,0 +1,17 @@ +package org.researchstack.foundation.components.presentation.interfaces + +import android.content.Context +import org.researchstack.foundation.core.interfaces.IResult +import org.researchstack.foundation.core.interfaces.IStep +import org.researchstack.foundation.core.models.task.Task + +interface ITaskNavigator { + @Deprecated("Only here for backwards compatibilty. Will be removed soon") + fun getTitleForStep(context: Context, step: StepType): String + fun getTitleForStep(step: StepType): String + fun getStepWithIdentifier(identifier: String): StepType? + fun getStepAfterStep(step: StepType?, result: ResultType): StepType? + fun getStepBeforeStep(step: StepType?, result: ResultType): StepType? + fun getProgressOfCurrentStep(step: StepType, result: ResultType): Task.TaskProgress + fun validateParameters() +} \ No newline at end of file diff --git a/backbone/src/main/java/org/researchstack/backbone/ResourcePathManager.java b/foundation/src/main/java/org/researchstack/foundation/components/singletons/ResourcePathManager.java similarity index 98% rename from backbone/src/main/java/org/researchstack/backbone/ResourcePathManager.java rename to foundation/src/main/java/org/researchstack/foundation/components/singletons/ResourcePathManager.java index 3943deef6..0a7d60aca 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ResourcePathManager.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/singletons/ResourcePathManager.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone; +package org.researchstack.foundation.components.singletons; import android.app.Application; import android.content.Context; @@ -8,7 +8,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import org.researchstack.backbone.utils.LogExt; +import org.researchstack.foundation.components.utils.LogExt; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/foundation/src/main/java/org/researchstack/foundation/components/singletons/TextViewLinkManager.kt b/foundation/src/main/java/org/researchstack/foundation/components/singletons/TextViewLinkManager.kt new file mode 100644 index 000000000..a3497fadd --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/components/singletons/TextViewLinkManager.kt @@ -0,0 +1,48 @@ +package org.researchstack.foundation.components.singletons + +import android.content.Context +import org.researchstack.foundation.components.common.ui.views.TextViewLinkHandler +import org.researchstack.foundation.components.web.ui.activities.ViewWebDocumentActivity +import java.lang.RuntimeException + +public abstract class TextViewLinkManager { + + companion object { + + private var _sharedManager: TextViewLinkManager? = LegacyTextViewLinkManager() + + fun setSharedManager(manager: TextViewLinkManager) { + this._sharedManager = manager + } + + fun getSharedManager(): TextViewLinkManager { + val manager = this._sharedManager + if (manager == null) { + throw RuntimeException("Shared Manager instance is null. Make sure you configure this by calling TextViewLinkManager.init()") + } + return manager + } + + } + + abstract fun getHandler(context: Context, title: String): TextViewLinkHandler + +} + +public class LegacyTextViewLinkManager: TextViewLinkManager() { + + public class LegacyTextViewLinkHandler(val context: Context, val title: String): TextViewLinkHandler() { + override fun onLinkClick(url: String?) { + val path = ResourcePathManager.getInstance().generateAbsolutePath(ResourcePathManager.Resource.TYPE_HTML, url) + val intent = ViewWebDocumentActivity.newIntentForPath( + context, + title, + path) + context.startActivity(intent) + } + } + + override fun getHandler(context: Context, title: String): TextViewLinkHandler { + return LegacyTextViewLinkHandler(context, title) + } +} \ No newline at end of file diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/AnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/AnswerFormat.java similarity index 72% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/AnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/AnswerFormat.java index d489242bd..7b96f0163 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/AnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/AnswerFormat.java @@ -1,26 +1,26 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; -import org.researchstack.backbone.ui.step.body.DateQuestionBody; -import org.researchstack.backbone.ui.step.body.DecimalQuestionBody; -import org.researchstack.backbone.ui.step.body.DurationQuestionBody; -import org.researchstack.backbone.ui.step.body.FormBody; -import org.researchstack.backbone.ui.step.body.IntegerQuestionBody; -import org.researchstack.backbone.ui.step.body.MultiChoiceQuestionBody; -import org.researchstack.backbone.ui.step.body.NotImplementedStepBody; -import org.researchstack.backbone.ui.step.body.SingleChoiceQuestionBody; -import org.researchstack.backbone.ui.step.body.TextQuestionBody; +import org.researchstack.foundation.components.survey.ui.body.DateQuestionBody; +import org.researchstack.foundation.components.survey.ui.body.DecimalQuestionBody; +import org.researchstack.foundation.components.survey.ui.body.DurationQuestionBody; +import org.researchstack.foundation.components.survey.ui.body.FormBody; +import org.researchstack.foundation.components.survey.ui.body.IntegerQuestionBody; +import org.researchstack.foundation.components.survey.ui.body.MultiChoiceQuestionBody; +import org.researchstack.foundation.components.survey.ui.body.NotImplementedStepBody; +import org.researchstack.foundation.components.survey.ui.body.SingleChoiceQuestionBody; +import org.researchstack.foundation.components.survey.ui.body.TextQuestionBody; import java.io.Serializable; /** * The AnswerFormat class is the abstract base class for classes that describe the format in which a * survey question should be answered. The ResearchStack framework uses {@link - * org.researchstack.backbone.step.QuestionStep} to represent questions to ask the user. Each + * org.researchstack.foundation.step.QuestionStep} to represent questions to ask the user. Each * question must have an associated answer format. *

* To use an answer format, instantiate the appropriate answer format subclass and attach it to a * question step or form item. Incorporate the resulting step into a task, and present the task with - * a {@link org.researchstack.backbone.ui.ViewTaskActivity}. + * a {@link org.researchstack.foundation.ui.ViewTaskActivity}. */ public abstract class AnswerFormat implements Serializable { /** @@ -42,7 +42,7 @@ public QuestionType getQuestionType() { /** * The type of question. (read-only) *

- * The type provides a default {@link org.researchstack.backbone.ui.step.body.StepBody} for that + * The type provides a default {@link org.researchstack.foundation.ui.step.body.StepBody} for that * type of question. A custom StepLayout implementation may provide it's own StepBody rather * than using the default provided by this AnswerFormat. */ @@ -105,7 +105,7 @@ public enum DateAnswerStyle { /** * Interface that {@link Type} implements. Since you cannot add a value to an existing enum, you * may implement this interface instead to provide your own QuestionType that provides a {@link - * org.researchstack.backbone.ui.step.body.StepBody} class. + * org.researchstack.foundation.ui.step.body.StepBody} class. */ public interface QuestionType { Class getStepBodyClass(); diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/BirthDateAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/BirthDateAnswerFormat.java similarity index 83% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/BirthDateAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/BirthDateAnswerFormat.java index a7c3a55f0..5a5dc9f59 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/BirthDateAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/BirthDateAnswerFormat.java @@ -1,7 +1,7 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ui.step.body.BodyAnswer; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.ui.body.BodyAnswer; import java.util.Calendar; import java.util.Date; @@ -32,11 +32,11 @@ public BodyAnswer validateAnswer(Date resultDate) { Date maxDate = getMaximumDate(); if (minDate != null && isOnOrBefore(resultDate, minDate)) { - return new BodyAnswer(false, R.string.rsb_birth_date_too_old, String.valueOf(maxAge)); + return new BodyAnswer(false, R.string.rsf_birth_date_too_old, String.valueOf(maxAge)); } if (maxDate != null && !isOnOrBefore(resultDate, maxDate)) { - return new BodyAnswer(false, R.string.rsb_birth_date_too_young, String.valueOf(minAge)); + return new BodyAnswer(false, R.string.rsf_birth_date_too_young, String.valueOf(minAge)); } return BodyAnswer.VALID; diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/BooleanAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/BooleanAnswerFormat.java similarity index 87% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/BooleanAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/BooleanAnswerFormat.java index d4d40eae9..f8c67d2ef 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/BooleanAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/BooleanAnswerFormat.java @@ -1,7 +1,7 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; -import org.researchstack.backbone.model.Choice; +import org.researchstack.foundation.components.survey.model.Choice; /** * A convenience subclass of {@link ChoiceAnswerFormat} that provides a simple true/false single diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/ChoiceAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/ChoiceAnswerFormat.java similarity index 85% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/ChoiceAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/ChoiceAnswerFormat.java index d87ae7296..450d51fab 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/ChoiceAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/ChoiceAnswerFormat.java @@ -1,7 +1,6 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; - -import org.researchstack.backbone.model.Choice; +import org.researchstack.foundation.components.survey.model.Choice; /** * The ChoiceAnswerFormat class represents an answer format that lets participants choose from a @@ -25,7 +24,7 @@ public ChoiceAnswerFormat(AnswerFormat.ChoiceAnswerStyle answerStyle, Choice... /** * Returns a multiple choice or single choice question type, which will decide which {@link - * org.researchstack.backbone.ui.step.body.StepBody} to use to display this question. + * org.researchstack.foundation.ui.step.body.StepBody} to use to display this question. * * @return the question type for this answer format */ diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/DateAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/DateAnswerFormat.java similarity index 87% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/DateAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/DateAnswerFormat.java index f4c06047c..e8a05c180 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/DateAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/DateAnswerFormat.java @@ -1,8 +1,8 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ui.step.body.BodyAnswer; -import org.researchstack.backbone.utils.FormatHelper; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.ui.body.BodyAnswer; +import org.researchstack.foundation.components.utils.FormatHelper; import java.util.Date; @@ -86,13 +86,13 @@ public QuestionType getQuestionType() { public BodyAnswer validateAnswer(Date resultDate) { if (minimumDate != null && resultDate.getTime() < minimumDate.getTime()) { return new BodyAnswer(false, - R.string.rsb_invalid_answer_date_under, + R.string.rsf_invalid_answer_date_under, FormatHelper.SIMPLE_FORMAT_DATE.format(minimumDate)); } if (maximumDate != null && resultDate.getTime() > maximumDate.getTime()) { return new BodyAnswer(false, - R.string.rsb_invalid_answer_date_over, + R.string.rsf_invalid_answer_date_over, FormatHelper.SIMPLE_FORMAT_DATE.format(maximumDate)); } diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/DecimalAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/DecimalAnswerFormat.java similarity index 83% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/DecimalAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/DecimalAnswerFormat.java index 5c7714f50..c425d2eb6 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/DecimalAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/DecimalAnswerFormat.java @@ -1,8 +1,9 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ui.step.body.BodyAnswer; -import org.researchstack.backbone.utils.TextUtils; + +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.ui.body.BodyAnswer; +import org.researchstack.foundation.components.utils.TextUtils; /** * This class defines the attributes for a decimal answer format that participants enter using a @@ -59,10 +60,10 @@ public BodyAnswer validateAnswer(String inputString) { Float floatAnswer = Float.valueOf(inputString); if (floatAnswer < minValue) { return new BodyAnswer(false, - R.string.rsb_invalid_answer_integer_under, String.valueOf(getMinValue())); + R.string.rsf_invalid_answer_integer_under, String.valueOf(getMinValue())); } else if (floatAnswer > maxValue) { return new BodyAnswer(false, - R.string.rsb_invalid_answer_integer_over, String.valueOf(getMaxValue())); + R.string.rsf_invalid_answer_integer_over, String.valueOf(getMaxValue())); } } diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/DurationAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/DurationAnswerFormat.java similarity index 90% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/DurationAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/DurationAnswerFormat.java index 94a6c3fd5..8da181ea4 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/DurationAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/DurationAnswerFormat.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; /** * Created by Dario Salvi on 29/04/2016. diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/EmailAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/EmailAnswerFormat.java similarity index 71% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/EmailAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/EmailAnswerFormat.java index 5b7585b33..f15eead49 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/EmailAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/EmailAnswerFormat.java @@ -1,7 +1,6 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; - -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.foundation.components.utils.TextUtils; public class EmailAnswerFormat extends TextAnswerFormat { private static final int MAX_EMAIL_LENGTH = 255; diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/FormAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/FormAnswerFormat.java similarity index 86% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/FormAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/FormAnswerFormat.java index dcd6fb85d..a0a0191b9 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/FormAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/FormAnswerFormat.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; /** * AnswerFormat indicating that the QuestionStep is a form step. This lets the layout know that it diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/IntegerAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/IntegerAnswerFormat.java similarity index 80% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/IntegerAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/IntegerAnswerFormat.java index 7ccaae7dd..1a5205989 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/IntegerAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/IntegerAnswerFormat.java @@ -1,15 +1,15 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ui.step.body.BodyAnswer; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.ui.body.BodyAnswer; +import org.researchstack.foundation.components.utils.TextUtils; /** * This class defines the attributes for an integer answer format that participants enter using a * numeric keyboard. *

* If you specify maximum or minimum values and the user enters a value outside the specified range, - * the {@link org.researchstack.backbone.ui.step.body.IntegerQuestionBody} does not allow navigation + * the {@link org.researchstack.foundation.ui.step.body.IntegerQuestionBody} does not allow navigation * until the participant provides a value that is within the valid range. */ public class IntegerAnswerFormat extends AnswerFormat { @@ -60,11 +60,11 @@ public BodyAnswer validateAnswer(String inputString) { Integer intAnswer = Integer.valueOf(inputString); if (intAnswer < getMinValue()) { return new BodyAnswer(false, - R.string.rsb_invalid_answer_integer_under, + R.string.rsf_invalid_answer_integer_under, String.valueOf(getMinValue())); } else if (intAnswer > getMaxValue()) { return new BodyAnswer(false, - R.string.rsb_invalid_answer_integer_over, + R.string.rsf_invalid_answer_integer_over, String.valueOf(getMaxValue())); } diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/TextAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/TextAnswerFormat.java similarity index 96% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/TextAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/TextAnswerFormat.java index 3cdda7726..2a29e3543 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/TextAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/TextAnswerFormat.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; /** diff --git a/backbone/src/main/java/org/researchstack/backbone/answerformat/UnknownAnswerFormat.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/UnknownAnswerFormat.java similarity index 74% rename from backbone/src/main/java/org/researchstack/backbone/answerformat/UnknownAnswerFormat.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/UnknownAnswerFormat.java index 299dea72e..eac000ec3 100644 --- a/backbone/src/main/java/org/researchstack/backbone/answerformat/UnknownAnswerFormat.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/answerformat/UnknownAnswerFormat.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.answerformat; +package org.researchstack.foundation.components.survey.answerformat; @Deprecated diff --git a/backbone/src/main/java/org/researchstack/backbone/model/Choice.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/model/Choice.java similarity index 93% rename from backbone/src/main/java/org/researchstack/backbone/model/Choice.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/model/Choice.java index e4c820e9b..361820b1f 100644 --- a/backbone/src/main/java/org/researchstack/backbone/model/Choice.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/model/Choice.java @@ -1,9 +1,9 @@ -package org.researchstack.backbone.model; +package org.researchstack.foundation.components.survey.model; import java.io.Serializable; /** - * Choice objects for use in {@link org.researchstack.backbone.answerformat.ChoiceAnswerFormat}. + * Choice objects for use in {@link org.researchstack.foundation.answerformat.ChoiceAnswerFormat}. * They typically have an integer or string value, always with a string text representation of the * choice for the user. * diff --git a/backbone/src/main/java/org/researchstack/backbone/step/FormStep.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/step/FormStep.java similarity index 80% rename from backbone/src/main/java/org/researchstack/backbone/step/FormStep.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/step/FormStep.java index 94db97656..5af2d5bd7 100644 --- a/backbone/src/main/java/org/researchstack/backbone/step/FormStep.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/step/FormStep.java @@ -1,6 +1,6 @@ -package org.researchstack.backbone.step; +package org.researchstack.foundation.components.survey.step; -import org.researchstack.backbone.answerformat.FormAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.FormAnswerFormat; import java.util.Arrays; import java.util.List; @@ -12,7 +12,7 @@ * To use FormStep, instantiate the object, give it a list of {@link QuestionStep}s, and include it * in a task. *

- * The result of a form step is an {@link org.researchstack.backbone.result.StepResult} object that + * The result of a form step is an {@link org.researchstack.foundation.result.StepResult} object that * includes a child StepResult object for each form item. */ public class FormStep extends QuestionStep { diff --git a/backbone/src/main/java/org/researchstack/backbone/step/InstructionStep.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/step/InstructionStep.java similarity index 75% rename from backbone/src/main/java/org/researchstack/backbone/step/InstructionStep.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/step/InstructionStep.java index 8efbec31f..22bf1b98a 100644 --- a/backbone/src/main/java/org/researchstack/backbone/step/InstructionStep.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/step/InstructionStep.java @@ -1,6 +1,7 @@ -package org.researchstack.backbone.step; +package org.researchstack.foundation.components.survey.step; -import org.researchstack.backbone.ui.step.layout.InstructionStepLayout; +import org.researchstack.foundation.components.survey.ui.layout.InstructionStepLayout; +import org.researchstack.foundation.core.models.step.Step; /** * An InstructionStep object gives the participant instructions for a task. diff --git a/backbone/src/main/java/org/researchstack/backbone/step/QuestionStep.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/step/QuestionStep.java similarity index 87% rename from backbone/src/main/java/org/researchstack/backbone/step/QuestionStep.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/step/QuestionStep.java index 014541465..bdb859fb3 100644 --- a/backbone/src/main/java/org/researchstack/backbone/step/QuestionStep.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/step/QuestionStep.java @@ -1,7 +1,8 @@ -package org.researchstack.backbone.step; +package org.researchstack.foundation.components.survey.step; -import org.researchstack.backbone.answerformat.AnswerFormat; -import org.researchstack.backbone.ui.step.layout.SurveyStepLayout; +import org.researchstack.foundation.components.survey.answerformat.AnswerFormat; +import org.researchstack.foundation.components.survey.ui.layout.SurveyStepLayout; +import org.researchstack.foundation.core.models.step.Step; /** * The {@link QuestionStep} class is a concrete subclass of {@link Step} that represents a step in @@ -9,16 +10,16 @@ *

* To use a question step, instantiate an QuestionStep object, fill in its properties, and include * it in a task. When the task completes, the user's answer is encoded in the result hierarchy - * returned from the {@link org.researchstack.backbone.ui.ViewTaskActivity}. + * returned from the {@link org.researchstack.foundation.ui.ViewTaskActivity}. *

* When the ViewTaskActivity presents a QuestionStep object, it instantiates a {@link * SurveyStepLayout} object to present the step. The actual visual presentation depends on the - * answer format and its {@link org.researchstack.backbone.ui.step.body.StepBody}. + * answer format and its {@link org.researchstack.foundation.ui.step.body.StepBody}. *

* When you need to present more than one question at the same time, it can be appropriate to use * {@link FormStep} instead of QuestionStep. *

- * The result of a question step is an {@link org.researchstack.backbone.result.StepResult} object. + * The result of a question step is an {@link org.researchstack.foundation.result.StepResult} object. */ public class QuestionStep extends Step { private AnswerFormat answerFormat; @@ -61,7 +62,7 @@ public QuestionStep(String identifier, String title, AnswerFormat format) { } /** - * Returns a special {@link org.researchstack.backbone.ui.step.layout.StepLayout} that is used + * Returns a special {@link org.researchstack.foundation.ui.step.layout.StepLayout} that is used * for all question steps. *

* This step layout uses the {@link #getStepBodyClass()} to fill in the user interaction portion @@ -75,7 +76,7 @@ public Class getStepLayoutClass() { } /** - * Returns a subclass of {@link org.researchstack.backbone.ui.step.body.StepBody} responsible + * Returns a subclass of {@link org.researchstack.foundation.ui.step.body.StepBody} responsible * for creating the ui for answering the question, base on the AnswerFormat. *

* This class is used by {@link SurveyStepLayout} to create the part of the layout where the @@ -96,7 +97,7 @@ public Class getStepBodyClass() { *

* For example, the answer format might include the type of data to collect, the constraints to * place on the answer, or a list of available choices (in the case of single or multiple select - * questions). It also provides the default {@link org.researchstack.backbone.ui.step.body.StepBody} + * questions). It also provides the default {@link org.researchstack.foundation.ui.step.body.StepBody} * for questions of its type. * * @return the answer format for this question step diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/BodyAnswer.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/BodyAnswer.java similarity index 82% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/BodyAnswer.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/BodyAnswer.java index 08c14361d..db71d35e9 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/BodyAnswer.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/BodyAnswer.java @@ -1,14 +1,14 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; import android.content.Context; -import android.support.annotation.StringRes; +import androidx.annotation.StringRes; -import org.researchstack.backbone.R; +import org.researchstack.foundation.R; public class BodyAnswer { public static final BodyAnswer VALID = new BodyAnswer(true, 0); public static final BodyAnswer INVALID = new BodyAnswer(false, - R.string.rsb_invalid_answer_default); + R.string.rsf_invalid_answer_default); private boolean isValid; private int reason; diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/DateQuestionBody.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/DateQuestionBody.java similarity index 88% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/DateQuestionBody.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/DateQuestionBody.java index fcdb5fd73..195d60cf2 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/DateQuestionBody.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/DateQuestionBody.java @@ -1,22 +1,23 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; import android.app.DatePickerDialog; import android.app.TimePickerDialog; import android.content.res.Resources; -import android.support.v7.view.ContextThemeWrapper; +import androidx.appcompat.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; -import org.researchstack.backbone.R; -import org.researchstack.backbone.answerformat.AnswerFormat; -import org.researchstack.backbone.answerformat.DateAnswerFormat; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.utils.FormatHelper; + +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.answerformat.AnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.DateAnswerFormat; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.components.utils.FormatHelper; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import java.text.DateFormat; import java.util.Calendar; @@ -73,7 +74,7 @@ else if (format.getDefaultDate() != null) { @Override public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) { - View view = inflater.inflate(R.layout.rsb_item_date_view, parent, false); + View view = inflater.inflate(R.layout.rsf_item_date_view, parent, false); TextView title = (TextView) view.findViewById(R.id.label); if (viewType == VIEW_TYPE_COMPACT) { @@ -88,11 +89,11 @@ public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) textView.setHint(step.getPlaceholder()); } else { if (format.getStyle() == AnswerFormat.DateAnswerStyle.Date) { - textView.setHint(R.string.rsb_hint_step_body_date); + textView.setHint(R.string.rsf_hint_step_body_date); } else if (format.getStyle() == AnswerFormat.DateAnswerStyle.TimeOfDay) { - textView.setHint(R.string.rsb_hint_step_body_time); + textView.setHint(R.string.rsf_hint_step_body_time); } else if (format.getStyle() == AnswerFormat.DateAnswerStyle.DateAndTime) { - textView.setHint(R.string.rsb_hint_step_body_datetime); + textView.setHint(R.string.rsf_hint_step_body_datetime); } } @@ -115,8 +116,8 @@ public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) Resources res = parent.getResources(); LinearLayout.MarginLayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_left); - layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_right); + layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_left); + layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_right); view.setLayoutParams(layoutParams); return view; @@ -140,7 +141,7 @@ public StepResult getStepResult(boolean skipped) { @Override public BodyAnswer getBodyAnswerState() { if (!hasChosenDate) { - return new BodyAnswer(false, R.string.rsb_invalid_answer_date_none); + return new BodyAnswer(false, R.string.rsf_invalid_answer_date_none); } return format.validateAnswer(calendar.getTime()); @@ -149,7 +150,7 @@ public BodyAnswer getBodyAnswerState() { private void showDialog(TextView tv) { // need to find a material date picker, since it's not in the support library ContextThemeWrapper contextWrapper = new ContextThemeWrapper(tv.getContext(), - R.style.Theme_Backbone); + R.style.Theme_Foundation); if (format.getStyle() == AnswerFormat.DateAnswerStyle.Date) { new DatePickerDialog(contextWrapper, (view, year, monthOfYear, dayOfMonth) -> { diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/DecimalQuestionBody.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/DecimalQuestionBody.java similarity index 85% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/DecimalQuestionBody.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/DecimalQuestionBody.java index c88bea5ba..16e305693 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/DecimalQuestionBody.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/DecimalQuestionBody.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; import android.content.Context; import android.content.res.Resources; @@ -11,13 +11,13 @@ import android.widget.LinearLayout; import android.widget.TextView; -import org.researchstack.backbone.R; -import org.researchstack.backbone.answerformat.DecimalAnswerFormat; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.utils.TextUtils; -import org.researchstack.backbone.utils.ViewUtils; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.answerformat.DecimalAnswerFormat; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.components.utils.ViewUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; public class DecimalQuestionBody implements StepBody { //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* @@ -48,8 +48,8 @@ public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) Resources res = parent.getResources(); LinearLayout.MarginLayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_left); - layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_right); + layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_left); + layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_right); view.setLayoutParams(layoutParams); return view; @@ -66,14 +66,14 @@ private View getViewForType(int viewType, LayoutInflater inflater, ViewGroup par } private View initViewDefault(LayoutInflater inflater, ViewGroup parent) { - editText = (EditText) inflater.inflate(R.layout.rsb_item_edit_text, parent, false); + editText = (EditText) inflater.inflate(R.layout.rsf_item_edit_text, parent, false); setFilters(parent.getContext()); return editText; } private View initViewCompact(LayoutInflater inflater, ViewGroup parent) { - View formItemView = inflater.inflate(R.layout.rsb_item_edit_text_compact, parent, false); + View formItemView = inflater.inflate(R.layout.rsf_item_edit_text_compact, parent, false); TextView title = (TextView) formItemView.findViewById(R.id.label); title.setText(step.getTitle()); @@ -93,9 +93,9 @@ private void setFilters(Context context) { if (step.getPlaceholder() != null) { editText.setHint(step.getPlaceholder()); } else if (maxValue == Integer.MAX_VALUE) { - editText.setHint(context.getString(R.string.rsb_hint_step_body_int_no_max)); + editText.setHint(context.getString(R.string.rsf_hint_step_body_int_no_max)); } else { - editText.setHint(context.getString(R.string.rsb_hint_step_body_dec, + editText.setHint(context.getString(R.string.rsf_hint_step_body_dec, minValue, maxValue)); } diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/DurationQuestionBody.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/DurationQuestionBody.java similarity index 89% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/DurationQuestionBody.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/DurationQuestionBody.java index 73a1e3bed..fd6ea5c45 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/DurationQuestionBody.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/DurationQuestionBody.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; import android.content.res.Resources; import android.view.LayoutInflater; @@ -8,11 +8,11 @@ import android.widget.LinearLayout; import android.widget.Spinner; -import org.researchstack.backbone.R; -import org.researchstack.backbone.answerformat.DurationAnswerFormat; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.answerformat.DurationAnswerFormat; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; /** * Implementation of the question type "duration". @@ -59,8 +59,8 @@ public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) Resources res = parent.getResources(); LinearLayout.MarginLayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_left); - layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_right); + layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_left); + layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_right); view.setLayoutParams(layoutParams); return view; @@ -75,7 +75,7 @@ private View getViewForType(int viewType, LayoutInflater inflater, ViewGroup par } private View initView(LayoutInflater inflater, ViewGroup parent) { - View v = inflater.inflate(R.layout.rsb_item_edit_duration, parent, false); + View v = inflater.inflate(R.layout.rsf_item_edit_duration, parent, false); String[] hoursStrs = new String[24]; for (int i = 0; i < 24; i++) hoursStrs[i] = String.valueOf(i); diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/FormBody.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/FormBody.java similarity index 86% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/FormBody.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/FormBody.java index d6c85f7e5..96fffaff9 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/FormBody.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/FormBody.java @@ -1,17 +1,18 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; -import org.researchstack.backbone.R; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.FormStep; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.utils.LogExt; + +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.step.FormStep; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import java.lang.reflect.Constructor; import java.util.ArrayList; @@ -37,7 +38,7 @@ public FormBody(Step step, StepResult result) { @Override public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) { // Inflate our container for each compact child StepBody - LinearLayout body = (LinearLayout) inflater.inflate(R.layout.rsb_step_layout_form_body, + LinearLayout body = (LinearLayout) inflater.inflate(R.layout.rsf_step_layout_form_body, parent, false); diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/IntegerQuestionBody.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/IntegerQuestionBody.java similarity index 85% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/IntegerQuestionBody.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/IntegerQuestionBody.java index d06575237..112f0272b 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/IntegerQuestionBody.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/IntegerQuestionBody.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; import android.content.Context; import android.content.res.Resources; @@ -11,13 +11,13 @@ import android.widget.LinearLayout; import android.widget.TextView; -import org.researchstack.backbone.R; -import org.researchstack.backbone.answerformat.IntegerAnswerFormat; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.utils.TextUtils; -import org.researchstack.backbone.utils.ViewUtils; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.answerformat.IntegerAnswerFormat; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.components.utils.ViewUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; public class IntegerQuestionBody implements StepBody { //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* @@ -48,8 +48,8 @@ public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) Resources res = parent.getResources(); LinearLayout.MarginLayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_left); - layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_right); + layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_left); + layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_right); view.setLayoutParams(layoutParams); return view; @@ -66,14 +66,14 @@ private View getViewForType(int viewType, LayoutInflater inflater, ViewGroup par } private View initViewDefault(LayoutInflater inflater, ViewGroup parent) { - editText = (EditText) inflater.inflate(R.layout.rsb_item_edit_text, parent, false); + editText = (EditText) inflater.inflate(R.layout.rsf_item_edit_text, parent, false); setFilters(parent.getContext()); return editText; } private View initViewCompact(LayoutInflater inflater, ViewGroup parent) { - View formItemView = inflater.inflate(R.layout.rsb_item_edit_text_compact, parent, false); + View formItemView = inflater.inflate(R.layout.rsf_item_edit_text_compact, parent, false); TextView title = (TextView) formItemView.findViewById(R.id.label); title.setText(step.getTitle()); @@ -93,9 +93,9 @@ private void setFilters(Context context) { if (step.getPlaceholder() != null) { editText.setHint(step.getPlaceholder()); } else if (maxValue == Integer.MAX_VALUE) { - editText.setHint(context.getString(R.string.rsb_hint_step_body_int_no_max)); + editText.setHint(context.getString(R.string.rsf_hint_step_body_int_no_max)); } else { - editText.setHint(context.getString(R.string.rsb_hint_step_body_int, + editText.setHint(context.getString(R.string.rsf_hint_step_body_int, minValue, maxValue)); } diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/MultiChoiceQuestionBody.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/MultiChoiceQuestionBody.java similarity index 85% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/MultiChoiceQuestionBody.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/MultiChoiceQuestionBody.java index 2499de7aa..99a31dc94 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/MultiChoiceQuestionBody.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/MultiChoiceQuestionBody.java @@ -1,8 +1,8 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; import android.content.res.Resources; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.AppCompatCheckBox; +import androidx.core.content.ContextCompat; +import androidx.appcompat.widget.AppCompatCheckBox; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -10,12 +10,13 @@ import android.widget.RadioGroup; import android.widget.TextView; -import org.researchstack.backbone.R; -import org.researchstack.backbone.answerformat.ChoiceAnswerFormat; -import org.researchstack.backbone.model.Choice; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; + +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.answerformat.ChoiceAnswerFormat; +import org.researchstack.foundation.components.survey.model.Choice; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import java.util.Arrays; import java.util.HashSet; @@ -53,8 +54,8 @@ public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) Resources res = parent.getResources(); LinearLayout.MarginLayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_left); - layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_right); + layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_left); + layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_right); view.setLayoutParams(layoutParams); return view; @@ -74,13 +75,13 @@ private View initViewDefault(LayoutInflater inflater, ViewGroup parent) { RadioGroup radioGroup = new RadioGroup(inflater.getContext()); radioGroup.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); radioGroup.setDividerDrawable(ContextCompat.getDrawable(parent.getContext(), - R.drawable.rsb_divider_empty_8dp)); + R.drawable.rsf_divider_empty_8dp)); for (int i = 0; i < choices.length; i++) { Choice item = choices[i]; // Create & add the View to our body-view - AppCompatCheckBox checkBox = (AppCompatCheckBox) inflater.inflate(R.layout.rsb_item_checkbox, + AppCompatCheckBox checkBox = (AppCompatCheckBox) inflater.inflate(R.layout.rsf_item_checkbox, radioGroup, false); checkBox.setText(item.getText()); @@ -109,7 +110,7 @@ private View initViewDefault(LayoutInflater inflater, ViewGroup parent) { private View initViewCompact(LayoutInflater inflater, ViewGroup parent) { ViewGroup compactView = (ViewGroup) initViewDefault(inflater, parent); - TextView label = (TextView) inflater.inflate(R.layout.rsb_item_text_view_title_compact, + TextView label = (TextView) inflater.inflate(R.layout.rsf_item_text_view_title_compact, compactView, false); label.setText(step.getTitle()); @@ -133,7 +134,7 @@ public StepResult getStepResult(boolean skipped) { @Override public BodyAnswer getBodyAnswerState() { if (currentSelected.isEmpty()) { - return new BodyAnswer(false, R.string.rsb_invalid_answer_choice); + return new BodyAnswer(false, R.string.rsf_invalid_answer_choice); } else { return BodyAnswer.VALID; } diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/NotImplementedStepBody.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/NotImplementedStepBody.java similarity index 85% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/NotImplementedStepBody.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/NotImplementedStepBody.java index 3d59fb387..70b0f261b 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/NotImplementedStepBody.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/NotImplementedStepBody.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; import android.content.Context; import android.view.LayoutInflater; @@ -6,8 +6,9 @@ import android.view.ViewGroup; import android.widget.TextView; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.QuestionStep; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.core.models.result.StepResult; + @Deprecated public class NotImplementedStepBody implements StepBody { diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/SingleChoiceQuestionBody.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/SingleChoiceQuestionBody.java similarity index 85% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/SingleChoiceQuestionBody.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/SingleChoiceQuestionBody.java index d7a2ced1c..bd6212eaf 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/SingleChoiceQuestionBody.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/SingleChoiceQuestionBody.java @@ -1,7 +1,7 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; import android.content.res.Resources; -import android.support.v4.content.ContextCompat; +import androidx.core.content.ContextCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -10,12 +10,13 @@ import android.widget.RadioGroup; import android.widget.TextView; -import org.researchstack.backbone.R; -import org.researchstack.backbone.answerformat.ChoiceAnswerFormat; -import org.researchstack.backbone.model.Choice; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.answerformat.ChoiceAnswerFormat; +import org.researchstack.foundation.components.survey.model.Choice; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; + public class SingleChoiceQuestionBody implements StepBody { //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* @@ -51,8 +52,8 @@ public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) Resources res = parent.getResources(); LinearLayout.MarginLayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_left); - layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_right); + layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_left); + layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_right); view.setLayoutParams(layoutParams); return view; @@ -72,11 +73,11 @@ private View initViewDefault(LayoutInflater inflater, ViewGroup parent) { RadioGroup radioGroup = new RadioGroup(parent.getContext()); radioGroup.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); radioGroup.setDividerDrawable(ContextCompat.getDrawable(parent.getContext(), - R.drawable.rsb_divider_empty_8dp)); + R.drawable.rsf_divider_empty_8dp)); for (int i = 0; i < choices.length; i++) { Choice choice = choices[i]; - RadioButton radioButton = (RadioButton) inflater.inflate(R.layout.rsb_item_radio, + RadioButton radioButton = (RadioButton) inflater.inflate(R.layout.rsf_item_radio, radioGroup, false); radioButton.setText(choice.getText()); @@ -100,7 +101,7 @@ private View initViewDefault(LayoutInflater inflater, ViewGroup parent) { private View initViewCompact(LayoutInflater inflater, ViewGroup parent) { ViewGroup compactView = (ViewGroup) initViewDefault(inflater, parent); - TextView label = (TextView) inflater.inflate(R.layout.rsb_item_text_view_title_compact, + TextView label = (TextView) inflater.inflate(R.layout.rsf_item_text_view_title_compact, compactView, false); label.setText(step.getTitle()); @@ -124,7 +125,7 @@ public StepResult getStepResult(boolean skipped) { @Override public BodyAnswer getBodyAnswerState() { if (currentSelected == null) { - return new BodyAnswer(false, R.string.rsb_invalid_answer_choice); + return new BodyAnswer(false, R.string.rsf_invalid_answer_choice); } else { return BodyAnswer.VALID; } diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/StepBody.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/StepBody.java similarity index 73% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/StepBody.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/StepBody.java index d1658a7cd..e42b2afe3 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/StepBody.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/StepBody.java @@ -1,10 +1,10 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import org.researchstack.backbone.result.StepResult; +import org.researchstack.foundation.core.models.result.StepResult; public interface StepBody { int VIEW_TYPE_DEFAULT = 0; diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/TextQuestionBody.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/TextQuestionBody.java similarity index 72% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/body/TextQuestionBody.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/TextQuestionBody.java index ad4a83505..2188a6b0d 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/body/TextQuestionBody.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/body/TextQuestionBody.java @@ -1,7 +1,9 @@ -package org.researchstack.backbone.ui.step.body; +package org.researchstack.foundation.components.survey.ui.body; import android.content.res.Resources; +import android.text.Editable; import android.text.InputFilter; +import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -9,15 +11,14 @@ import android.widget.LinearLayout; import android.widget.TextView; -import com.jakewharton.rxbinding.widget.RxTextView; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.survey.answerformat.TextAnswerFormat; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.components.utils.ViewUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; -import org.researchstack.backbone.R; -import org.researchstack.backbone.answerformat.TextAnswerFormat; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.utils.TextUtils; -import org.researchstack.backbone.utils.ViewUtils; public class TextQuestionBody implements StepBody { //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* @@ -38,13 +39,13 @@ public TextQuestionBody(Step step, StepResult result) { @Override public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) { - View body = inflater.inflate(R.layout.rsb_item_edit_text_compact, parent, false); + View body = inflater.inflate(R.layout.rsf_item_edit_text_compact, parent, false); editText = (EditText) body.findViewById(R.id.value); if (step.getPlaceholder() != null) { editText.setHint(step.getPlaceholder()); } else { - editText.setHint(R.string.rsb_hint_step_body_text); + editText.setHint(R.string.rsf_hint_step_body_text); } TextView title = (TextView) body.findViewById(R.id.label); @@ -62,8 +63,21 @@ public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) } // Set result on text change - RxTextView.textChanges(editText).subscribe(text -> { - result.setResult(text.toString()); + editText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + result.setResult(s.toString()); + } + + @Override + public void afterTextChanged(Editable s) { + + } }); // Format EditText from TextAnswerFormat @@ -80,8 +94,8 @@ public View getBodyView(int viewType, LayoutInflater inflater, ViewGroup parent) Resources res = parent.getResources(); LinearLayout.MarginLayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_left); - layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsb_margin_right); + layoutParams.leftMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_left); + layoutParams.rightMargin = res.getDimensionPixelSize(R.dimen.rsf_margin_right); body.setLayoutParams(layoutParams); return body; diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/InstructionStepLayout.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/layout/InstructionStepLayout.java similarity index 63% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/layout/InstructionStepLayout.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/layout/InstructionStepLayout.java index 6e967df95..63526ef82 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/InstructionStepLayout.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/layout/InstructionStepLayout.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.step.layout; +package org.researchstack.foundation.components.survey.ui.layout; import android.content.Context; import android.content.Intent; @@ -7,15 +7,15 @@ import android.view.View; import android.widget.TextView; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ResourcePathManager; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.ViewWebDocumentActivity; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.views.FixedSubmitBarLayout; -import org.researchstack.backbone.ui.views.SubmitBar; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.FixedSubmitBarLayout; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.foundation.components.singletons.TextViewLinkManager; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; public class InstructionStepLayout extends FixedSubmitBarLayout implements StepLayout { private StepCallbacks callbacks; @@ -57,7 +57,7 @@ public void setCallbacks(StepCallbacks callbacks) { @Override public int getContentResourceId() { - return R.layout.rsb_step_layout_instruction; + return R.layout.rsf_step_layout_instruction; } private void initializeStep() { @@ -65,38 +65,30 @@ private void initializeStep() { // Set Title if (!TextUtils.isEmpty(step.getTitle())) { - TextView title = (TextView) findViewById(R.id.rsb_intruction_title); + TextView title = (TextView) findViewById(R.id.rsf_intruction_title); title.setVisibility(View.VISIBLE); title.setText(step.getTitle()); } // Set Summary if (!TextUtils.isEmpty(step.getText())) { - TextView summary = (TextView) findViewById(R.id.rsb_intruction_text); + TextView summary = (TextView) findViewById(R.id.rsf_intruction_text); summary.setVisibility(View.VISIBLE); summary.setText(Html.fromHtml(step.getText())); - summary.setMovementMethod(new TextViewLinkHandler() { - @Override - public void onLinkClick(String url) { - String path = ResourcePathManager.getInstance(). - generateAbsolutePath(ResourcePathManager.Resource.TYPE_HTML, url); - Intent intent = ViewWebDocumentActivity.newIntentForPath(getContext(), - step.getTitle(), - path); - getContext().startActivity(intent); - } - }); + summary.setMovementMethod( + TextViewLinkManager.Companion.getSharedManager().getHandler(getContext(), step.getTitle()) + ); } // Set Next / Skip - SubmitBar submitBar = (SubmitBar) findViewById(R.id.rsb_submit_bar); - submitBar.setPositiveTitle(R.string.rsb_next); + SubmitBar submitBar = (SubmitBar) findViewById(R.id.rsf_submit_bar); + submitBar.setPositiveTitle(R.string.rsf_next); submitBar.setPositiveAction(v -> callbacks.onSaveStep(StepCallbacks.ACTION_NEXT, step, null)); if (step.isOptional()) { - submitBar.setNegativeTitle(R.string.rsb_step_skip); + submitBar.setNegativeTitle(R.string.rsf_step_skip); submitBar.setNegativeAction(v -> { if (callbacks != null) { callbacks.onSaveStep(StepCallbacks.ACTION_NEXT, step, null); diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/SurveyStepLayout.java b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/layout/SurveyStepLayout.java similarity index 74% rename from backbone/src/main/java/org/researchstack/backbone/ui/step/layout/SurveyStepLayout.java rename to foundation/src/main/java/org/researchstack/foundation/components/survey/ui/layout/SurveyStepLayout.java index 4d27c1b4b..95849ecda 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/step/layout/SurveyStepLayout.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/survey/ui/layout/SurveyStepLayout.java @@ -1,10 +1,9 @@ -package org.researchstack.backbone.ui.step.layout; +package org.researchstack.foundation.components.survey.ui.layout; import android.content.Context; -import android.content.Intent; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.StringRes; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; import android.text.Html; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -13,19 +12,19 @@ import android.widget.TextView; import android.widget.Toast; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ResourcePathManager; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.ViewWebDocumentActivity; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.step.body.BodyAnswer; -import org.researchstack.backbone.ui.step.body.StepBody; -import org.researchstack.backbone.ui.views.FixedSubmitBarLayout; -import org.researchstack.backbone.ui.views.SubmitBar; -import org.researchstack.backbone.utils.LogExt; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.foundation.components.singletons.TextViewLinkManager; +import org.researchstack.foundation.components.survey.ui.body.BodyAnswer; +import org.researchstack.foundation.components.common.ui.layout.FixedSubmitBarLayout; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.components.survey.ui.body.StepBody; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import java.lang.reflect.Constructor; @@ -100,7 +99,7 @@ public void setCallbacks(StepCallbacks callbacks) { @Override public int getContentResourceId() { - return R.layout.rsb_step_layout; + return R.layout.rsf_step_layout; } public void initializeStep() { @@ -111,10 +110,10 @@ public void initializeStep() { public void initStepLayout() { LogExt.i(getClass(), "initStepLayout()"); - container = (LinearLayout) findViewById(R.id.rsb_survey_content_container); - TextView title = (TextView) findViewById(R.id.rsb_survey_title); - TextView summary = (TextView) findViewById(R.id.rsb_survey_text); - SubmitBar submitBar = (SubmitBar) findViewById(R.id.rsb_submit_bar); + container = (LinearLayout) findViewById(R.id.rsf_survey_content_container); + TextView title = (TextView) findViewById(R.id.rsf_survey_title); + TextView summary = (TextView) findViewById(R.id.rsf_survey_text); + SubmitBar submitBar = (SubmitBar) findViewById(R.id.rsf_submit_bar); submitBar.setPositiveAction(v -> onNextClicked()); if (questionStep != null) { @@ -126,21 +125,13 @@ public void initStepLayout() { if (!TextUtils.isEmpty(questionStep.getText())) { summary.setVisibility(View.VISIBLE); summary.setText(Html.fromHtml(questionStep.getText())); - summary.setMovementMethod(new TextViewLinkHandler() { - @Override - public void onLinkClick(String url) { - String path = ResourcePathManager.getInstance(). - generateAbsolutePath(ResourcePathManager.Resource.TYPE_HTML, url); - Intent intent = ViewWebDocumentActivity.newIntentForPath(getContext(), - questionStep.getTitle(), - path); - getContext().startActivity(intent); - } - }); + summary.setMovementMethod( + TextViewLinkManager.Companion.getSharedManager().getHandler(getContext(), questionStep.getTitle()) + ); } if (questionStep.isOptional()) { - submitBar.setNegativeTitle(R.string.rsb_step_skip); + submitBar.setNegativeTitle(R.string.rsf_step_skip); submitBar.setNegativeAction(v -> onSkipClicked()); } else { submitBar.getNegativeActionView().setVisibility(View.GONE); @@ -156,11 +147,11 @@ public void initStepBody() { View body = stepBody.getBodyView(StepBody.VIEW_TYPE_DEFAULT, inflater, this); if (body != null) { - View oldView = container.findViewById(R.id.rsb_survey_step_body); + View oldView = container.findViewById(R.id.rsf_survey_step_body); int bodyIndex = container.indexOfChild(oldView); container.removeView(oldView); container.addView(body, bodyIndex); - body.setId(R.id.rsb_survey_step_body); + body.setId(R.id.rsf_survey_step_body); } } diff --git a/backbone/src/main/java/org/researchstack/backbone/utils/FormatHelper.java b/foundation/src/main/java/org/researchstack/foundation/components/utils/FormatHelper.java similarity index 94% rename from backbone/src/main/java/org/researchstack/backbone/utils/FormatHelper.java rename to foundation/src/main/java/org/researchstack/foundation/components/utils/FormatHelper.java index 721cdfbdc..f0d07bd7d 100644 --- a/backbone/src/main/java/org/researchstack/backbone/utils/FormatHelper.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/utils/FormatHelper.java @@ -1,6 +1,4 @@ -package org.researchstack.backbone.utils; - -import org.researchstack.backbone.ui.step.layout.ConsentSignatureStepLayout; +package org.researchstack.foundation.components.utils; import java.text.DateFormat; import java.text.SimpleDateFormat; diff --git a/backbone/src/main/java/org/researchstack/backbone/utils/LogExt.java b/foundation/src/main/java/org/researchstack/foundation/components/utils/LogExt.java similarity index 98% rename from backbone/src/main/java/org/researchstack/backbone/utils/LogExt.java rename to foundation/src/main/java/org/researchstack/foundation/components/utils/LogExt.java index 991adcc8c..bafc04e26 100644 --- a/backbone/src/main/java/org/researchstack/backbone/utils/LogExt.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/utils/LogExt.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.utils; +package org.researchstack.foundation.components.utils; import android.util.Log; diff --git a/backbone/src/main/java/org/researchstack/backbone/utils/ResUtils.java b/foundation/src/main/java/org/researchstack/foundation/components/utils/ResUtils.java similarity index 94% rename from backbone/src/main/java/org/researchstack/backbone/utils/ResUtils.java rename to foundation/src/main/java/org/researchstack/foundation/components/utils/ResUtils.java index 07010fae8..7436e76f9 100644 --- a/backbone/src/main/java/org/researchstack/backbone/utils/ResUtils.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/utils/ResUtils.java @@ -1,10 +1,7 @@ -package org.researchstack.backbone.utils; +package org.researchstack.foundation.components.utils; import android.content.Context; -import org.researchstack.backbone.StorageAccess; - - public class ResUtils { private ResUtils() { diff --git a/backbone/src/main/java/org/researchstack/backbone/utils/TextUtils.java b/foundation/src/main/java/org/researchstack/foundation/components/utils/TextUtils.java similarity index 97% rename from backbone/src/main/java/org/researchstack/backbone/utils/TextUtils.java rename to foundation/src/main/java/org/researchstack/foundation/components/utils/TextUtils.java index c658096cf..987dfd0f0 100644 --- a/backbone/src/main/java/org/researchstack/backbone/utils/TextUtils.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/utils/TextUtils.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.utils; +package org.researchstack.foundation.components.utils; import android.text.InputFilter; import android.text.Spanned; diff --git a/backbone/src/main/java/org/researchstack/backbone/utils/ThemeUtils.java b/foundation/src/main/java/org/researchstack/foundation/components/utils/ThemeUtils.java similarity index 92% rename from backbone/src/main/java/org/researchstack/backbone/utils/ThemeUtils.java rename to foundation/src/main/java/org/researchstack/foundation/components/utils/ThemeUtils.java index b9df9c894..d2a93e329 100644 --- a/backbone/src/main/java/org/researchstack/backbone/utils/ThemeUtils.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/utils/ThemeUtils.java @@ -1,11 +1,11 @@ -package org.researchstack.backbone.utils; +package org.researchstack.foundation.components.utils; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; import android.util.TypedValue; -import org.researchstack.backbone.R; +import org.researchstack.foundation.R; import java.lang.reflect.Method; @@ -38,7 +38,7 @@ public static int getPassCodeTheme(Context context) { new int[]{R.attr.passcodeTheme}); int themeResId = a.getResourceId(0, 0); if (themeResId == 0) { - throw new RuntimeException("Theme must define attribute passCodeTheme or extend from @style/Base.Theme.Backbone"); + throw new RuntimeException("Theme must define attribute passCodeTheme or extend from @style/Base.Theme.Foundation"); } a.recycle(); diff --git a/backbone/src/main/java/org/researchstack/backbone/utils/UiThreadContext.java b/foundation/src/main/java/org/researchstack/foundation/components/utils/UiThreadContext.java similarity index 93% rename from backbone/src/main/java/org/researchstack/backbone/utils/UiThreadContext.java rename to foundation/src/main/java/org/researchstack/foundation/components/utils/UiThreadContext.java index 918d6453e..90e0dda15 100644 --- a/backbone/src/main/java/org/researchstack/backbone/utils/UiThreadContext.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/utils/UiThreadContext.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.utils; +package org.researchstack.foundation.components.utils; import android.os.Looper; diff --git a/backbone/src/main/java/org/researchstack/backbone/utils/ViewUtils.java b/foundation/src/main/java/org/researchstack/foundation/components/utils/ViewUtils.java similarity index 97% rename from backbone/src/main/java/org/researchstack/backbone/utils/ViewUtils.java rename to foundation/src/main/java/org/researchstack/foundation/components/utils/ViewUtils.java index 2eb753cd3..744a15315 100644 --- a/backbone/src/main/java/org/researchstack/backbone/utils/ViewUtils.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/utils/ViewUtils.java @@ -1,9 +1,9 @@ -package org.researchstack.backbone.utils; +package org.researchstack.foundation.components.utils; import android.app.Activity; import android.content.Context; import android.os.Build; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.text.InputFilter; import android.text.InputType; import android.view.View; diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/ViewVideoActivity.java b/foundation/src/main/java/org/researchstack/foundation/components/web/ui/activities/ViewVideoActivity.java similarity index 83% rename from backbone/src/main/java/org/researchstack/backbone/ui/ViewVideoActivity.java rename to foundation/src/main/java/org/researchstack/foundation/components/web/ui/activities/ViewVideoActivity.java index a5db40bee..00ad23486 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/ViewVideoActivity.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/web/ui/activities/ViewVideoActivity.java @@ -1,14 +1,14 @@ -package org.researchstack.backbone.ui; +package org.researchstack.foundation.components.web.ui.activities; import android.content.Context; import android.content.Intent; import android.content.res.AssetFileDescriptor; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.widget.MediaController; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ui.views.AssetVideoView; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.web.ui.views.AssetVideoView; import java.io.IOException; @@ -27,7 +27,7 @@ public static Intent newIntent(Context context, String relativeVideoPath) { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - super.setContentView(R.layout.rsb_activity_video_viewer); + super.setContentView(R.layout.rsf_activity_video_viewer); videoView = (AssetVideoView) findViewById(R.id.videoView); diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/ViewWebDocumentActivity.java b/foundation/src/main/java/org/researchstack/foundation/components/web/ui/activities/ViewWebDocumentActivity.java similarity index 89% rename from backbone/src/main/java/org/researchstack/backbone/ui/ViewWebDocumentActivity.java rename to foundation/src/main/java/org/researchstack/foundation/components/web/ui/activities/ViewWebDocumentActivity.java index 8c9bbaffe..0236a2884 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/ViewWebDocumentActivity.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/web/ui/activities/ViewWebDocumentActivity.java @@ -1,16 +1,16 @@ -package org.researchstack.backbone.ui; +package org.researchstack.foundation.components.web.ui.activities; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; import android.view.MenuItem; -import org.researchstack.backbone.R; -import org.researchstack.backbone.ui.views.LocalWebView; -import org.researchstack.backbone.utils.ThemeUtils; +import org.researchstack.foundation.R; +import org.researchstack.foundation.components.utils.ThemeUtils; +import org.researchstack.foundation.components.web.ui.views.LocalWebView; /** * The ViewWebDocumentActivity is used for viewing both local and network HTML docs. This activity @@ -62,7 +62,7 @@ protected void onCreate(Bundle savedInstanceState) { setTheme(getIntent().getIntExtra(KEY_THEME, 0)); } super.onCreate(savedInstanceState); - super.setContentView(R.layout.rsb_activity_web_document); + super.setContentView(R.layout.rsf_activity_web_document); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/views/AssetVideoView.java b/foundation/src/main/java/org/researchstack/foundation/components/web/ui/views/AssetVideoView.java similarity index 98% rename from backbone/src/main/java/org/researchstack/backbone/ui/views/AssetVideoView.java rename to foundation/src/main/java/org/researchstack/foundation/components/web/ui/views/AssetVideoView.java index 65c5777a7..d718d388d 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/views/AssetVideoView.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/web/ui/views/AssetVideoView.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.researchstack.backbone.ui.views; +package org.researchstack.foundation.components.web.ui.views; import android.annotation.TargetApi; import android.app.AlertDialog; @@ -33,7 +33,7 @@ import android.widget.MediaController; import android.widget.VideoView; -import org.researchstack.backbone.R; +import org.researchstack.foundation.R; import java.io.FileDescriptor; import java.io.IOException; @@ -192,13 +192,13 @@ public boolean onError(MediaPlayer mp, int framework_err, int impl_err) { int messageId; if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { - messageId = R.string.rsb_error_assetvideoview_invalid_progressive_playback; + messageId = R.string.rsf_error_assetvideoview_invalid_progressive_playback; } else { - messageId = R.string.rsb_error_assetvideoview_unknown; + messageId = R.string.rsf_error_assetvideoview_unknown; } new AlertDialog.Builder(getContext()).setMessage(messageId) - .setPositiveButton(R.string.rsb_error_assetvideoview_button, + .setPositiveButton(R.string.rsf_error_assetvideoview_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { /* If we get here, there is no onError listener, so diff --git a/backbone/src/main/java/org/researchstack/backbone/ui/views/LocalWebView.java b/foundation/src/main/java/org/researchstack/foundation/components/web/ui/views/LocalWebView.java similarity index 89% rename from backbone/src/main/java/org/researchstack/backbone/ui/views/LocalWebView.java rename to foundation/src/main/java/org/researchstack/foundation/components/web/ui/views/LocalWebView.java index 80574090d..a9e7f6018 100644 --- a/backbone/src/main/java/org/researchstack/backbone/ui/views/LocalWebView.java +++ b/foundation/src/main/java/org/researchstack/foundation/components/web/ui/views/LocalWebView.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.ui.views; +package org.researchstack.foundation.components.web.ui.views; import android.content.Context; import android.content.Intent; @@ -9,10 +9,10 @@ import android.webkit.WebView; import android.webkit.WebViewClient; -import org.researchstack.backbone.ResourcePathManager; -import org.researchstack.backbone.ui.ViewVideoActivity; -import org.researchstack.backbone.ui.ViewWebDocumentActivity; -import org.researchstack.backbone.utils.LogExt; +import org.researchstack.foundation.components.singletons.ResourcePathManager; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.components.web.ui.activities.ViewVideoActivity; +import org.researchstack.foundation.components.web.ui.activities.ViewWebDocumentActivity; import java.io.File; diff --git a/foundation/src/main/java/org/researchstack/foundation/core/interfaces/IResult.kt b/foundation/src/main/java/org/researchstack/foundation/core/interfaces/IResult.kt new file mode 100644 index 000000000..1d27e84b1 --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/core/interfaces/IResult.kt @@ -0,0 +1,5 @@ +package org.researchstack.foundation.core.interfaces + +interface IResult { + val identifier: String +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/core/interfaces/IStep.kt b/foundation/src/main/java/org/researchstack/foundation/core/interfaces/IStep.kt new file mode 100644 index 000000000..73b80619a --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/core/interfaces/IStep.kt @@ -0,0 +1,5 @@ +package org.researchstack.foundation.core.interfaces + +interface IStep { + val identifier: String +} \ No newline at end of file diff --git a/foundation/src/main/java/org/researchstack/foundation/core/interfaces/ITask.kt b/foundation/src/main/java/org/researchstack/foundation/core/interfaces/ITask.kt new file mode 100644 index 000000000..a99d6498a --- /dev/null +++ b/foundation/src/main/java/org/researchstack/foundation/core/interfaces/ITask.kt @@ -0,0 +1,5 @@ +package org.researchstack.foundation.core.interfaces + +interface ITask { + val identifier: String +} \ No newline at end of file diff --git a/backbone/src/main/java/org/researchstack/backbone/result/Result.java b/foundation/src/main/java/org/researchstack/foundation/core/models/result/Result.java similarity index 84% rename from backbone/src/main/java/org/researchstack/backbone/result/Result.java rename to foundation/src/main/java/org/researchstack/foundation/core/models/result/Result.java index b64ff5571..97e8e9274 100644 --- a/backbone/src/main/java/org/researchstack/backbone/result/Result.java +++ b/foundation/src/main/java/org/researchstack/foundation/core/models/result/Result.java @@ -1,4 +1,6 @@ -package org.researchstack.backbone.result; +package org.researchstack.foundation.core.models.result; + +import org.researchstack.foundation.core.interfaces.IResult; import java.io.Serializable; import java.util.Date; @@ -6,8 +8,8 @@ /** * The Result class defines the attributes of a result from one step or a group of steps. When you * use the ResearchStack framework APIs, you typically get a result from the Result property of - * either {@link org.researchstack.backbone.ui.ViewTaskActivity} or {@link - * org.researchstack.backbone.ui.step.layout.StepLayout}. Certain types of results can contain other + * either {@link org.researchstack.foundation.ui.ViewTaskActivity} or {@link + * org.researchstack.foundation.ui.step.layout.StepLayout}. Certain types of results can contain other * results, which together express a hierarchy; examples of these types of results are {@link * StepResult} and {@link TaskResult}. *

@@ -21,7 +23,7 @@ * hold the type of result data the step can generate, unless it makes sense to use an existing * subclass. */ -public class Result implements Serializable { +public class Result implements Serializable, IResult { private String identifier; private Date startDate; @@ -34,8 +36,8 @@ public class Result implements Serializable { /** * Returns an initialized result using the specified identifier. *

- * Typically, objects such as {@link org.researchstack.backbone.ui.ViewTaskActivity} and {@link - * org.researchstack.backbone.ui.step.layout.StepLayout} instantiate result (and Result + * Typically, objects such as {@link org.researchstack.foundation.ui.ViewTaskActivity} and {@link + * org.researchstack.foundation.ui.step.layout.StepLayout} instantiate result (and Result * subclass) objects; you seldom need to instantiate a result object in your code. * * @param identifier The unique identifier of the result. diff --git a/backbone/src/main/java/org/researchstack/backbone/result/StepResult.java b/foundation/src/main/java/org/researchstack/foundation/core/models/result/StepResult.java similarity index 82% rename from backbone/src/main/java/org/researchstack/backbone/result/StepResult.java rename to foundation/src/main/java/org/researchstack/foundation/core/models/result/StepResult.java index 603beb1db..a2dad1984 100644 --- a/backbone/src/main/java/org/researchstack/backbone/result/StepResult.java +++ b/foundation/src/main/java/org/researchstack/foundation/core/models/result/StepResult.java @@ -1,15 +1,17 @@ -package org.researchstack.backbone.result; +package org.researchstack.foundation.core.models.result; -import org.researchstack.backbone.answerformat.AnswerFormat; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; +import androidx.annotation.Nullable; + +import org.researchstack.foundation.components.survey.answerformat.AnswerFormat; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.core.models.step.Step; import java.util.Date; import java.util.HashMap; import java.util.Map; /** - * The StepResult class represents a result produced by a {@link org.researchstack.backbone.ui.step.layout.StepLayout} + * The StepResult class represents a result produced by a {@link org.researchstack.foundation.ui.step.layout.StepLayout} * to hold all child results of type T produced by the step. *

* A step result is typically generated by the framework as the task proceeds. When the task @@ -27,7 +29,7 @@ public class StepResult extends Result { private Map results; - private AnswerFormat answerFormat; + private Step step; /** * Creates a StepResult from a {@link Step}. @@ -40,10 +42,8 @@ public class StepResult extends Result { public StepResult(Step step) { super(step.getIdentifier()); this.results = new HashMap<>(); + this.step = step; - if (step instanceof QuestionStep) { - answerFormat = ((QuestionStep) step).getAnswerFormat(); - } setStartDate(new Date()); // this will be updated when the result is set setEndDate(new Date()); @@ -105,7 +105,21 @@ public void setResultForIdentifier(String identifier, T result) { * * @return the answer format associated with the step */ + + @Deprecated + @Nullable public AnswerFormat getAnswerFormat() { - return answerFormat; + if (step instanceof QuestionStep) { + AnswerFormat answerFormat = ((QuestionStep) step).getAnswerFormat(); + return answerFormat; + } + else { + return null; + } + } + + public Step getStep() { + return this.step; } } + diff --git a/backbone/src/main/java/org/researchstack/backbone/result/TaskResult.java b/foundation/src/main/java/org/researchstack/foundation/core/models/result/TaskResult.java similarity index 88% rename from backbone/src/main/java/org/researchstack/backbone/result/TaskResult.java rename to foundation/src/main/java/org/researchstack/foundation/core/models/result/TaskResult.java index f7abc5249..4b33f7cac 100644 --- a/backbone/src/main/java/org/researchstack/backbone/result/TaskResult.java +++ b/foundation/src/main/java/org/researchstack/foundation/core/models/result/TaskResult.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.result; +package org.researchstack.foundation.core.models.result; import android.net.Uri; @@ -8,8 +8,8 @@ /** * An TaskResult object is a result that contains all the step results generated from one run of a - * task or ordered task (that is, {@link org.researchstack.backbone.task.Task} or {@link - * org.researchstack.backbone.task.OrderedTask}). + * task or ordered task (that is, {@link org.researchstack.foundation.task.Task} or {@link + * org.researchstack.foundation.task.OrderedTask}). *

* A task result is typically generated by the framework as the task proceeds. When the task * completes, it may be appropriate to serialize it for transmission to a server, or to immediately @@ -20,6 +20,7 @@ public class TaskResult extends Result { private Map results; + //TODO: JDK - 4/13/19 add support for this // unimplemented but exists in RK, implement or delete if not needed private UUID uuidTask; diff --git a/backbone/src/main/java/org/researchstack/backbone/step/Step.java b/foundation/src/main/java/org/researchstack/foundation/core/models/step/Step.java similarity index 78% rename from backbone/src/main/java/org/researchstack/backbone/step/Step.java rename to foundation/src/main/java/org/researchstack/foundation/core/models/step/Step.java index af059ab52..899aa08d6 100644 --- a/backbone/src/main/java/org/researchstack/backbone/step/Step.java +++ b/foundation/src/main/java/org/researchstack/foundation/core/models/step/Step.java @@ -1,31 +1,34 @@ -package org.researchstack.backbone.step; +package org.researchstack.foundation.core.models.step; -import org.researchstack.backbone.task.Task; +import org.researchstack.foundation.core.interfaces.IStep; +import org.researchstack.foundation.core.models.task.Task; import java.io.Serializable; /** * Step is the base class for the steps that can compose a task for presentation in an {@link - * org.researchstack.backbone.ui.ViewTaskActivity} object. Each Step object represents one logical + * org.researchstack.foundation.ui.ViewTaskActivity} object. Each Step object represents one logical * piece of data entry or activity in a larger task. *

* A step can be a question, an active test, or a simple instruction. An Step subclass is usually - * paired with an {@link org.researchstack.backbone.ui.step.layout.StepLayout} subclass that + * paired with an {@link org.researchstack.foundation.ui.step.layout.StepLayout} subclass that * displays the step. *

* To use a step, instantiate an Step object and populate its properties. Add the step to a task, - * such as an {@link org.researchstack.backbone.task.OrderedTask} object, and then present the task + * such as an {@link org.researchstack.foundation.task.OrderedTask} object, and then present the task * using a ViewTaskActivity. *

* To implement a new type of step, subclass Step and add your additional properties. Separately, * subclass StepLayout and implement your user interface. */ -public class Step implements Serializable { +public class Step implements Serializable, IStep { private String identifier; private Class stepLayoutClass; + @Deprecated() private int stepTitle; + private String stepTitleString; private boolean optional = true; @@ -66,7 +69,7 @@ public Step(String identifier, String title) { * A short string that uniquely identifies the step within the task. *

* The identifier is reproduced in the results of a step. In fact, the only way to link a result - * (a {@link org.researchstack.backbone.result.StepResult} object) to the step that generated it + * (a {@link org.researchstack.foundation.result.StepResult} object) to the step that generated it * is to look at the value of identifier. To accurately identify step results, you * need to ensure that step identifiers are unique within each task. *

@@ -152,6 +155,7 @@ public void setText(String text) { * * @return the id for the title to display in the action bar */ + @Deprecated public int getStepTitle() { return stepTitle; } @@ -161,12 +165,31 @@ public int getStepTitle() { * * @param stepTitle the Android resource id for the title */ + @Deprecated public void setStepTitle(int stepTitle) { this.stepTitle = stepTitle; } /** - * Returns the class that the {@link org.researchstack.backbone.ui.ViewTaskActivity} should + * Gets the string the title to display in the action bar (optional). + * + * @return the string for the title to display in the action bar + */ + public String getStepTitleString() { + return stepTitleString; + } + + /** + * Gets the string for the title to display in the action bar (optional). + * + * @param stepTitle the string for the title + */ + public void setStepTitle(String stepTitle) { + this.stepTitleString = stepTitle; + } + + /** + * Returns the class that the {@link org.researchstack.foundation.ui.ViewTaskActivity} should * instantiate to display this step. *

* This method is used within the framework so that steps can define their step view controller @@ -175,7 +198,7 @@ public void setStepTitle(int stepTitle) { * Outside the framework, developers should instantiate the required view controller in their * ViewTaskActivity delegate to override the ViewTaskActivity's default. * - * @return the class of the {@link org.researchstack.backbone.ui.step.layout.StepLayout} for + * @return the class of the {@link org.researchstack.foundation.ui.step.layout.StepLayout} for * this step */ public Class getStepLayoutClass() { @@ -185,7 +208,7 @@ public Class getStepLayoutClass() { /** * Sets the class that should be used to display this step * - * @param stepLayoutClass the {@link org.researchstack.backbone.ui.step.layout.StepLayout} class + * @param stepLayoutClass the {@link org.researchstack.foundation.ui.step.layout.StepLayout} class * to be used to display this step */ public void setStepLayoutClass(Class stepLayoutClass) { diff --git a/backbone/src/main/java/org/researchstack/backbone/task/Task.java b/foundation/src/main/java/org/researchstack/foundation/core/models/task/Task.java similarity index 77% rename from backbone/src/main/java/org/researchstack/backbone/task/Task.java rename to foundation/src/main/java/org/researchstack/foundation/core/models/task/Task.java index ea21b3e5a..4c8d57912 100644 --- a/backbone/src/main/java/org/researchstack/backbone/task/Task.java +++ b/foundation/src/main/java/org/researchstack/foundation/core/models/task/Task.java @@ -1,10 +1,12 @@ -package org.researchstack.backbone.task; +package org.researchstack.foundation.core.models.task; import android.content.Context; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.ViewTaskActivity; +import org.jetbrains.annotations.NotNull; +import org.researchstack.foundation.components.presentation.interfaces.ITaskNavigator; +import org.researchstack.foundation.core.interfaces.ITask; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.step.Step; import java.io.Serializable; @@ -13,19 +15,24 @@ *

* To present the ResearchStack framework UI in your app, instantiate an object that extends the * Task class (such as {@link OrderedTask}) and provide it to a {@link - * org.researchstack.backbone.ui.ViewTaskActivity}. + * org.researchstack.foundation.ui.ViewTaskActivity}. *

* Implement this protocol to enable dynamic selection of the steps for a given task. By default, * OrderedTask implements this protocol for simple sequential tasks. *

* Each {@link Step} in a task roughly corresponds to one screen, and represents the primary unit of - * work in any task. For example, a {@link org.researchstack.backbone.step.QuestionStep} object + * work in any task. For example, a {@link org.researchstack.foundation.step.QuestionStep} object * corresponds to a single question presented on screen, together with controls the participant uses - * to answer the question. Another example is {@link org.researchstack.backbone.step.FormStep}, + * to answer the question. Another example is {@link org.researchstack.foundation.step.FormStep}, * which corresponds to a single screen that displays multiple questions or items for which * participants provide information, such as first name, last name, and birth date. */ -public abstract class Task implements Serializable { +public abstract class Task implements Serializable, ITask, ITaskNavigator { + + public interface TaskLifecycleObserver { + + } + private String identifier; /** @@ -69,16 +76,22 @@ public String getIdentifier() { * @param step the current step * @return the title to display */ + @Deprecated public String getTitleForStep(Context context, Step step) { return step.getStepTitle() != 0 ? context.getString(step.getStepTitle()) : ""; } + public String getTitleForStep(Step step) { + String titleString = step.getStepTitleString(); + return titleString != null ? titleString : ""; + } + /** * Returns the step after the specified step, if there is one. *

* This method lets you use a result to determine the next step. *

- * The {@link org.researchstack.backbone.ui.ViewTaskActivity} calls this method to determine + * The {@link org.researchstack.foundation.ui.ViewTaskActivity} calls this method to determine * the step to display after the specified step. The ViewTaskActivity can also call this * method every time the result updates, to determine if the new result changes which steps are * available. @@ -95,7 +108,7 @@ public String getTitleForStep(Context context, Step step) { /** * Returns the step that precedes the specified step, if there is one. *

- * The {@link org.researchstack.backbone.ui.ViewTaskActivity} calls this method to determine the + * The {@link org.researchstack.foundation.ui.ViewTaskActivity} calls this method to determine the * step to display before the specified step. The ViewTaskActivity * can also call this method every time the result changes, to determine if the new result * changes which steps are available. @@ -121,7 +134,7 @@ public String getTitleForStep(Context context, Step step) { /** * Returns the progress of the current step. *

- * During a task, the {@link org.researchstack.backbone.ui.ViewTaskActivity} can display the + * During a task, the {@link org.researchstack.foundation.ui.ViewTaskActivity} can display the * progress (that is, the current step number out of the total number of steps) in the * navigation bar. Implement this method to control what is displayed; if you don't implement * this method, the progress label does not appear. @@ -144,23 +157,30 @@ public String getTitleForStep(Context context, Step step) { * implementation makes sure that all its step identifiers are unique, throwing an exception * otherwise. *

- * This method is usually called by {@link org.researchstack.backbone.ui.ViewTaskActivity} when + * This method is usually called by {@link org.researchstack.foundation.ui.ViewTaskActivity} when * its task is set. * * @throws InvalidTaskException */ public abstract void validateParameters(); - /** - * Function that can be overridden in order to access the low level changes in the view. - * The function is called at Activity lifecycle events (creation, pause, resume, stop and whenever - * the content of the activity is changed, according to the step. - * - * @param type lifecycle event - * @param activity current activity - * @param currentStep the current step being shown - */ - public void onViewChange(ViewChangeType type, ViewTaskActivity activity, Step currentStep) { + //JDK - 4/13/19 - changed this interface from + //onViewChange(ViewChangeType type, ViewTaskActivity activity, Step currentStep) + //to + //onViewChange(ViewChangeType type, TaskLifecycleObserver observer, Step currentStep) + //this was done to remove the circular dependency on ViewTaskActivity + //Note that this method is invoked by ViewTaskActivity, which was modified to implement TaskLifecycleObserver + //This is not (yet) invoked by TaskPresentationFragment, but this potentially change at some point +// /** +// * Function that can be overridden in order to access the low level changes in the view. +// * The function is called at Activity lifecycle events (creation, pause, resume, stop and whenever +// * the content of the activity is changed, according to the step. +// * +// * @param type lifecycle event +// * @param observer current activity +// * @param currentStep the current step being shown +// */ + public void onViewChange(ViewChangeType type, TaskLifecycleObserver observer, Step currentStep) { } @@ -176,7 +196,7 @@ public static enum ViewChangeType { * A structure that represents how far a task has progressed. *

* Objects that extend Task return the task progress structure to indicate to the {@link - * org.researchstack.backbone.ui.ViewTaskActivity} how far the task has progressed. + * org.researchstack.foundation.ui.ViewTaskActivity} how far the task has progressed. *

* Note that the values in an {@link TaskProgress} structure are used only for display; you * don't use the values to access the steps in a task. diff --git a/backbone/src/main/res/anim/rsb_interpolator_step_layout.xml b/foundation/src/main/res/anim/rsf_interpolator_step_layout.xml similarity index 100% rename from backbone/src/main/res/anim/rsb_interpolator_step_layout.xml rename to foundation/src/main/res/anim/rsf_interpolator_step_layout.xml diff --git a/backbone/src/main/res/anim/rsb_slide_in_left.xml b/foundation/src/main/res/anim/rsf_slide_in_left.xml similarity index 87% rename from backbone/src/main/res/anim/rsb_slide_in_left.xml rename to foundation/src/main/res/anim/rsf_slide_in_left.xml index a3239933b..c70afe17a 100644 --- a/backbone/src/main/res/anim/rsb_slide_in_left.xml +++ b/foundation/src/main/res/anim/rsf_slide_in_left.xml @@ -18,7 +18,7 @@ --> diff --git a/backbone/src/main/res/anim/rsb_slide_in_right.xml b/foundation/src/main/res/anim/rsf_slide_in_right.xml similarity index 87% rename from backbone/src/main/res/anim/rsb_slide_in_right.xml rename to foundation/src/main/res/anim/rsf_slide_in_right.xml index d42bf20c3..725324da8 100644 --- a/backbone/src/main/res/anim/rsb_slide_in_right.xml +++ b/foundation/src/main/res/anim/rsf_slide_in_right.xml @@ -18,7 +18,7 @@ --> diff --git a/backbone/src/main/res/anim/rsb_slide_in_up.xml b/foundation/src/main/res/anim/rsf_slide_in_up.xml similarity index 89% rename from backbone/src/main/res/anim/rsb_slide_in_up.xml rename to foundation/src/main/res/anim/rsf_slide_in_up.xml index 309e7c884..e2a1435d6 100644 --- a/backbone/src/main/res/anim/rsb_slide_in_up.xml +++ b/foundation/src/main/res/anim/rsf_slide_in_up.xml @@ -21,11 +21,11 @@ android:interpolator="@android:interpolator/decelerate_cubic"> diff --git a/backbone/src/main/res/anim/rsb_slide_out_down.xml b/foundation/src/main/res/anim/rsf_slide_out_down.xml similarity index 89% rename from backbone/src/main/res/anim/rsb_slide_out_down.xml rename to foundation/src/main/res/anim/rsf_slide_out_down.xml index 7b5382c6e..16d4feb50 100644 --- a/backbone/src/main/res/anim/rsb_slide_out_down.xml +++ b/foundation/src/main/res/anim/rsf_slide_out_down.xml @@ -20,11 +20,11 @@ diff --git a/backbone/src/main/res/anim/rsb_slide_out_left.xml b/foundation/src/main/res/anim/rsf_slide_out_left.xml similarity index 87% rename from backbone/src/main/res/anim/rsb_slide_out_left.xml rename to foundation/src/main/res/anim/rsf_slide_out_left.xml index 961697cfe..11b5c53c3 100644 --- a/backbone/src/main/res/anim/rsb_slide_out_left.xml +++ b/foundation/src/main/res/anim/rsf_slide_out_left.xml @@ -18,7 +18,7 @@ --> diff --git a/backbone/src/main/res/anim/rsb_slide_out_right.xml b/foundation/src/main/res/anim/rsf_slide_out_right.xml similarity index 87% rename from backbone/src/main/res/anim/rsb_slide_out_right.xml rename to foundation/src/main/res/anim/rsf_slide_out_right.xml index 7692f5a45..7c545a366 100644 --- a/backbone/src/main/res/anim/rsb_slide_out_right.xml +++ b/foundation/src/main/res/anim/rsf_slide_out_right.xml @@ -18,7 +18,7 @@ --> diff --git a/backbone/src/main/res/drawable-hdpi/rsb_ic_check.png b/foundation/src/main/res/drawable-hdpi/rsf_ic_check.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_ic_check.png rename to foundation/src/main/res/drawable-hdpi/rsf_ic_check.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_ic_fullscreen.png b/foundation/src/main/res/drawable-hdpi/rsf_ic_fullscreen.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_ic_fullscreen.png rename to foundation/src/main/res/drawable-hdpi/rsf_ic_fullscreen.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_ic_x.png b/foundation/src/main/res/drawable-hdpi/rsf_ic_x.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_ic_x.png rename to foundation/src/main/res/drawable-hdpi/rsf_ic_x.png diff --git a/backbone/src/main/res/drawable-hdpi/rsb_illo_dashboard_empty.png b/foundation/src/main/res/drawable-hdpi/rsf_illo_dashboard_empty.png similarity index 100% rename from backbone/src/main/res/drawable-hdpi/rsb_illo_dashboard_empty.png rename to foundation/src/main/res/drawable-hdpi/rsf_illo_dashboard_empty.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_ic_check.png b/foundation/src/main/res/drawable-mdpi/rsf_ic_check.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_ic_check.png rename to foundation/src/main/res/drawable-mdpi/rsf_ic_check.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_ic_fullscreen.png b/foundation/src/main/res/drawable-mdpi/rsf_ic_fullscreen.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_ic_fullscreen.png rename to foundation/src/main/res/drawable-mdpi/rsf_ic_fullscreen.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_ic_x.png b/foundation/src/main/res/drawable-mdpi/rsf_ic_x.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_ic_x.png rename to foundation/src/main/res/drawable-mdpi/rsf_ic_x.png diff --git a/backbone/src/main/res/drawable-mdpi/rsb_illo_dashboard_empty.png b/foundation/src/main/res/drawable-mdpi/rsf_illo_dashboard_empty.png similarity index 100% rename from backbone/src/main/res/drawable-mdpi/rsb_illo_dashboard_empty.png rename to foundation/src/main/res/drawable-mdpi/rsf_illo_dashboard_empty.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_ic_check.png b/foundation/src/main/res/drawable-xhdpi/rsf_ic_check.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_ic_check.png rename to foundation/src/main/res/drawable-xhdpi/rsf_ic_check.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_ic_fullscreen.png b/foundation/src/main/res/drawable-xhdpi/rsf_ic_fullscreen.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_ic_fullscreen.png rename to foundation/src/main/res/drawable-xhdpi/rsf_ic_fullscreen.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_ic_x.png b/foundation/src/main/res/drawable-xhdpi/rsf_ic_x.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_ic_x.png rename to foundation/src/main/res/drawable-xhdpi/rsf_ic_x.png diff --git a/backbone/src/main/res/drawable-xhdpi/rsb_illo_dashboard_empty.png b/foundation/src/main/res/drawable-xhdpi/rsf_illo_dashboard_empty.png similarity index 100% rename from backbone/src/main/res/drawable-xhdpi/rsb_illo_dashboard_empty.png rename to foundation/src/main/res/drawable-xhdpi/rsf_illo_dashboard_empty.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_ic_check.png b/foundation/src/main/res/drawable-xxhdpi/rsf_ic_check.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_ic_check.png rename to foundation/src/main/res/drawable-xxhdpi/rsf_ic_check.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_ic_fullscreen.png b/foundation/src/main/res/drawable-xxhdpi/rsf_ic_fullscreen.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_ic_fullscreen.png rename to foundation/src/main/res/drawable-xxhdpi/rsf_ic_fullscreen.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_ic_x.png b/foundation/src/main/res/drawable-xxhdpi/rsf_ic_x.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_ic_x.png rename to foundation/src/main/res/drawable-xxhdpi/rsf_ic_x.png diff --git a/backbone/src/main/res/drawable-xxhdpi/rsb_illo_dashboard_empty.png b/foundation/src/main/res/drawable-xxhdpi/rsf_illo_dashboard_empty.png similarity index 100% rename from backbone/src/main/res/drawable-xxhdpi/rsb_illo_dashboard_empty.png rename to foundation/src/main/res/drawable-xxhdpi/rsf_illo_dashboard_empty.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_ic_check.png b/foundation/src/main/res/drawable-xxxhdpi/rsf_ic_check.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_ic_check.png rename to foundation/src/main/res/drawable-xxxhdpi/rsf_ic_check.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_ic_fullscreen.png b/foundation/src/main/res/drawable-xxxhdpi/rsf_ic_fullscreen.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_ic_fullscreen.png rename to foundation/src/main/res/drawable-xxxhdpi/rsf_ic_fullscreen.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_ic_x.png b/foundation/src/main/res/drawable-xxxhdpi/rsf_ic_x.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_ic_x.png rename to foundation/src/main/res/drawable-xxxhdpi/rsf_ic_x.png diff --git a/backbone/src/main/res/drawable-xxxhdpi/rsb_illo_dashboard_empty.png b/foundation/src/main/res/drawable-xxxhdpi/rsf_illo_dashboard_empty.png similarity index 100% rename from backbone/src/main/res/drawable-xxxhdpi/rsb_illo_dashboard_empty.png rename to foundation/src/main/res/drawable-xxxhdpi/rsf_illo_dashboard_empty.png diff --git a/backbone/src/main/res/drawable/rsb_debug_gray.xml b/foundation/src/main/res/drawable/rsf_debug_gray.xml similarity index 100% rename from backbone/src/main/res/drawable/rsb_debug_gray.xml rename to foundation/src/main/res/drawable/rsf_debug_gray.xml diff --git a/backbone/src/main/res/drawable/rsb_divider_empty_16dp.xml b/foundation/src/main/res/drawable/rsf_divider_empty_16dp.xml similarity index 100% rename from backbone/src/main/res/drawable/rsb_divider_empty_16dp.xml rename to foundation/src/main/res/drawable/rsf_divider_empty_16dp.xml diff --git a/backbone/src/main/res/drawable/rsb_divider_empty_8dp.xml b/foundation/src/main/res/drawable/rsf_divider_empty_8dp.xml similarity index 100% rename from backbone/src/main/res/drawable/rsb_divider_empty_8dp.xml rename to foundation/src/main/res/drawable/rsf_divider_empty_8dp.xml diff --git a/backbone/src/main/res/drawable/rsb_ic_circle_8dp.xml b/foundation/src/main/res/drawable/rsf_ic_circle_8dp.xml similarity index 81% rename from backbone/src/main/res/drawable/rsb_ic_circle_8dp.xml rename to foundation/src/main/res/drawable/rsf_ic_circle_8dp.xml index a8500cdb3..ed7548e86 100644 --- a/backbone/src/main/res/drawable/rsb_ic_circle_8dp.xml +++ b/foundation/src/main/res/drawable/rsf_ic_circle_8dp.xml @@ -6,6 +6,6 @@ android:width="8dp" android:height="8dp" /> - + \ No newline at end of file diff --git a/backbone/src/main/res/layout/rsb_activity_video_viewer.xml b/foundation/src/main/res/layout/rsf_activity_video_viewer.xml similarity index 83% rename from backbone/src/main/res/layout/rsb_activity_video_viewer.xml rename to foundation/src/main/res/layout/rsf_activity_video_viewer.xml index 84c6707cd..31546d464 100644 --- a/backbone/src/main/res/layout/rsb_activity_video_viewer.xml +++ b/foundation/src/main/res/layout/rsf_activity_video_viewer.xml @@ -3,7 +3,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - + - + + + + + \ No newline at end of file diff --git a/foundation/src/main/res/layout/rsf_fragment_task_presentation.xml b/foundation/src/main/res/layout/rsf_fragment_task_presentation.xml new file mode 100644 index 000000000..26e62852a --- /dev/null +++ b/foundation/src/main/res/layout/rsf_fragment_task_presentation.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/backbone/src/main/res/layout/rsb_item_checkbox.xml b/foundation/src/main/res/layout/rsf_item_checkbox.xml similarity index 72% rename from backbone/src/main/res/layout/rsb_item_checkbox.xml rename to foundation/src/main/res/layout/rsf_item_checkbox.xml index eab13322f..231aa349f 100644 --- a/backbone/src/main/res/layout/rsb_item_checkbox.xml +++ b/foundation/src/main/res/layout/rsf_item_checkbox.xml @@ -1,9 +1,9 @@ - diff --git a/backbone/src/main/res/layout/rsb_item_date_view.xml b/foundation/src/main/res/layout/rsf_item_date_view.xml similarity index 80% rename from backbone/src/main/res/layout/rsb_item_date_view.xml rename to foundation/src/main/res/layout/rsf_item_date_view.xml index c223e3748..358737762 100644 --- a/backbone/src/main/res/layout/rsb_item_date_view.xml +++ b/foundation/src/main/res/layout/rsf_item_date_view.xml @@ -5,22 +5,22 @@ android:layout_height="wrap_content" android:orientation="vertical"> - - @@ -43,7 +43,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_weight="0.6" - android:text="@string/rsb_minutes" + android:text="@string/rsf_minutes" android:textAppearance="?android:attr/textAppearanceMedium" /> diff --git a/backbone/src/main/res/layout/rsb_item_edit_text.xml b/foundation/src/main/res/layout/rsf_item_edit_text.xml similarity index 89% rename from backbone/src/main/res/layout/rsb_item_edit_text.xml rename to foundation/src/main/res/layout/rsf_item_edit_text.xml index b4dee8384..cf2777f32 100644 --- a/backbone/src/main/res/layout/rsb_item_edit_text.xml +++ b/foundation/src/main/res/layout/rsf_item_edit_text.xml @@ -6,7 +6,7 @@ android:layout_height="wrap_content" android:imeOptions="actionNext" android:inputType="text" - android:minHeight="@dimen/rsb_item_size_default" + android:minHeight="@dimen/rsf_item_size_default" android:singleLine="true" android:textColor="?android:attr/textColorPrimary" android:textSize="14sp" diff --git a/backbone/src/main/res/layout/rsb_item_edit_text_compact.xml b/foundation/src/main/res/layout/rsf_item_edit_text_compact.xml similarity index 89% rename from backbone/src/main/res/layout/rsb_item_edit_text_compact.xml rename to foundation/src/main/res/layout/rsf_item_edit_text_compact.xml index 557882298..96ac24d81 100644 --- a/backbone/src/main/res/layout/rsb_item_edit_text_compact.xml +++ b/foundation/src/main/res/layout/rsf_item_edit_text_compact.xml @@ -11,7 +11,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" - android:minHeight="@dimen/rsb_item_size_default" + android:minHeight="@dimen/rsf_item_size_default" android:textColor="?attr/colorAccent" android:textSize="16sp" tools:text="title" /> @@ -22,7 +22,7 @@ android:layout_height="wrap_content" android:imeOptions="actionNext" android:inputType="text" - android:minHeight="@dimen/rsb_item_size_default" + android:minHeight="@dimen/rsf_item_size_default" android:singleLine="true" android:textColor="?android:attr/textColorPrimary" android:textSize="14sp" diff --git a/backbone/src/main/res/layout/rsb_item_radio.xml b/foundation/src/main/res/layout/rsf_item_radio.xml similarity index 73% rename from backbone/src/main/res/layout/rsb_item_radio.xml rename to foundation/src/main/res/layout/rsf_item_radio.xml index 6631b9b00..9a44b4d79 100644 --- a/backbone/src/main/res/layout/rsb_item_radio.xml +++ b/foundation/src/main/res/layout/rsf_item_radio.xml @@ -1,9 +1,9 @@ - diff --git a/backbone/src/main/res/layout/rsb_item_text_view_title_compact.xml b/foundation/src/main/res/layout/rsf_item_text_view_title_compact.xml similarity index 100% rename from backbone/src/main/res/layout/rsb_item_text_view_title_compact.xml rename to foundation/src/main/res/layout/rsf_item_text_view_title_compact.xml diff --git a/backbone/src/main/res/layout/rsb_layout_fixed_submit_bar.xml b/foundation/src/main/res/layout/rsf_layout_fixed_submit_bar.xml similarity index 63% rename from backbone/src/main/res/layout/rsb_layout_fixed_submit_bar.xml rename to foundation/src/main/res/layout/rsf_layout_fixed_submit_bar.xml index 22a398722..588c36538 100644 --- a/backbone/src/main/res/layout/rsb_layout_fixed_submit_bar.xml +++ b/foundation/src/main/res/layout/rsf_layout_fixed_submit_bar.xml @@ -1,19 +1,19 @@ - - + - diff --git a/backbone/src/main/res/layout/rsb_layout_toolbar.xml b/foundation/src/main/res/layout/rsf_layout_toolbar.xml similarity index 81% rename from backbone/src/main/res/layout/rsb_layout_toolbar.xml rename to foundation/src/main/res/layout/rsf_layout_toolbar.xml index 3493d8f39..68e769205 100644 --- a/backbone/src/main/res/layout/rsb_layout_toolbar.xml +++ b/foundation/src/main/res/layout/rsf_layout_toolbar.xml @@ -1,5 +1,5 @@ - diff --git a/backbone/src/main/res/layout/rsb_step_layout_form_body.xml b/foundation/src/main/res/layout/rsf_step_layout_form_body.xml similarity index 82% rename from backbone/src/main/res/layout/rsb_step_layout_form_body.xml rename to foundation/src/main/res/layout/rsf_step_layout_form_body.xml index 993d22a51..cb6a1cac0 100644 --- a/backbone/src/main/res/layout/rsb_step_layout_form_body.xml +++ b/foundation/src/main/res/layout/rsf_step_layout_form_body.xml @@ -2,6 +2,6 @@ \ No newline at end of file diff --git a/backbone/src/main/res/layout/rsb_step_layout_instruction.xml b/foundation/src/main/res/layout/rsf_step_layout_instruction.xml similarity index 81% rename from backbone/src/main/res/layout/rsb_step_layout_instruction.xml rename to foundation/src/main/res/layout/rsf_step_layout_instruction.xml index 0bd6e2e90..c49a000bf 100644 --- a/backbone/src/main/res/layout/rsb_step_layout_instruction.xml +++ b/foundation/src/main/res/layout/rsf_step_layout_instruction.xml @@ -6,8 +6,8 @@ android:orientation="vertical"> - - - + android:src="@drawable/rsf_ic_circle_8dp" /> \ No newline at end of file diff --git a/backbone/src/main/res/layout/rsb_view_submitbar.xml b/foundation/src/main/res/layout/rsf_view_submitbar.xml similarity index 90% rename from backbone/src/main/res/layout/rsb_view_submitbar.xml rename to foundation/src/main/res/layout/rsf_view_submitbar.xml index 8e3386312..bba385e8e 100644 --- a/backbone/src/main/res/layout/rsb_view_submitbar.xml +++ b/foundation/src/main/res/layout/rsf_view_submitbar.xml @@ -11,14 +11,14 @@ android:layout_height="wrap_content" android:layout_weight="1" /> - - + + + + + \ No newline at end of file diff --git a/foundation/src/main/res/values/attrs.xml b/foundation/src/main/res/values/attrs.xml new file mode 100644 index 000000000..0597c0016 --- /dev/null +++ b/foundation/src/main/res/values/attrs.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/foundation/src/main/res/values/colors.xml b/foundation/src/main/res/values/colors.xml new file mode 100644 index 000000000..38faea889 --- /dev/null +++ b/foundation/src/main/res/values/colors.xml @@ -0,0 +1,20 @@ + + + #3F51B5 + #303F9F + #FF4081 + #cc3367 + #000 + #33000000 + #66000000 + #CCFFFFFF + #FF757575 + #33757575 + #EEEEEE + #979797 + #e5e5e5 + #ffff5722 + + #2196f3 + #662196f3 + diff --git a/foundation/src/main/res/values/dimens.xml b/foundation/src/main/res/values/dimens.xml new file mode 100644 index 000000000..aba39ca3c --- /dev/null +++ b/foundation/src/main/res/values/dimens.xml @@ -0,0 +1,23 @@ + + + + + 8dp + 12dp + 16dp + 24dp + + + 48dp + 56dp + @dimen/rsf_item_size_small + 1dp + + + 48dp + 16dp + + + 20sp + + \ No newline at end of file diff --git a/foundation/src/main/res/values/ids.xml b/foundation/src/main/res/values/ids.xml new file mode 100644 index 000000000..0d2c4cc40 --- /dev/null +++ b/foundation/src/main/res/values/ids.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/foundation/src/main/res/values/integers.xml b/foundation/src/main/res/values/integers.xml new file mode 100644 index 000000000..865ea8487 --- /dev/null +++ b/foundation/src/main/res/values/integers.xml @@ -0,0 +1,4 @@ + + + 300 + \ No newline at end of file diff --git a/foundation/src/main/res/values/strings.xml b/foundation/src/main/res/values/strings.xml new file mode 100644 index 000000000..77d9ae9a6 --- /dev/null +++ b/foundation/src/main/res/values/strings.xml @@ -0,0 +1,76 @@ + + + Lorem Ipsum + Lorem ipsum dolor sit amet, consectetur + adipiscing elit. + + Lorem ipsum dolor sit amet, consectetur + adipiscing elit sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim. + + Lorem ipsum dolor sit amet, consectetur + adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis + nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute + irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit + anim id est laborum. + + + + Submit + Exit + Get Started + Done + Skip + next + What to Expect + Name + Email + Disagree + Agree + OK + Cancel + Yes + No + Step %1$d of %2$d + Hours + Minutes + + + Failed to load encrypted data, try again! + Signature Invalid + Invalid answer, try again! + Invalid answer, date must be before %1$s + Invalid answer, date must be after %1$s + Invalid answer, your value must be %1$s or lower + Invalid answer, your value must be %1$s or higher + Please select a value! + Please choose a date. + You must be %1$s years or younger + You must be at least %1$s years old + + + Enter a number %1$d-%2$d + Enter a number %1$.2f-%2$.2f + Enter a number + Enter a date + Enter a time + Enter a date and a time + Answer + + + %1$s of %2$s + %1$s% + + + + Video problem + + This video isn\'t valid for streaming to this device. + + Can\'t play this video. + + OK + + diff --git a/foundation/src/main/res/values/styles.xml b/foundation/src/main/res/values/styles.xml new file mode 100644 index 000000000..4b85840c4 --- /dev/null +++ b/foundation/src/main/res/values/styles.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + diff --git a/foundation/src/main/res/values/themes.xml b/foundation/src/main/res/values/themes.xml new file mode 100644 index 000000000..69724d63c --- /dev/null +++ b/foundation/src/main/res/values/themes.xml @@ -0,0 +1,22 @@ + + + + + + + + + \ No newline at end of file diff --git a/foundation/src/test/java/org/researchstack/foundation/ExampleUnitTest.java b/foundation/src/test/java/org/researchstack/foundation/ExampleUnitTest.java new file mode 100644 index 000000000..a4687af1d --- /dev/null +++ b/foundation/src/test/java/org/researchstack/foundation/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package org.researchstack.foundation; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 7791533f8..9d24db0b8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,4 +11,7 @@ # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file +# org.gradle.parallel=true +android.enableJetifier=true +android.useAndroidX=true +systemProp.snapshot=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5653266a8..2be106237 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Aug 30 13:10:33 EDT 2016 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +#Wed Feb 27 13:45:12 PST 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/sample_backbone_app/.gitignore b/sample_backbone_app/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/sample_backbone_app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/sample_backbone_app/build.gradle b/sample_backbone_app/build.gradle new file mode 100644 index 000000000..f87f61fee --- /dev/null +++ b/sample_backbone_app/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 28 + + defaultConfig { + applicationId "org.researchstack.backboneapp" + minSdkVersion 16 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'org.researchstack:backbone:1.1.2' + + testImplementation 'junit:junit:4.12' + + androidTestImplementation "androidx.core:core-ktx:1.0.0" + androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + androidTestImplementation "androidx.test.espresso:espresso-contrib:3.1.1" + + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-beta01' + androidTestImplementation 'androidx.test:rules:1.2.0-beta01' +} +repositories { + mavenCentral() +} diff --git a/sample_backbone_app/proguard-rules.pro b/sample_backbone_app/proguard-rules.pro new file mode 100644 index 000000000..2b8673663 --- /dev/null +++ b/sample_backbone_app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/bradleymcdermott/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/sample_backbone_app/src/androidTest/java/org/researchstack/backboneapp/MainActivityTest.kt b/sample_backbone_app/src/androidTest/java/org/researchstack/backboneapp/MainActivityTest.kt new file mode 100644 index 000000000..b44b910e7 --- /dev/null +++ b/sample_backbone_app/src/androidTest/java/org/researchstack/backboneapp/MainActivityTest.kt @@ -0,0 +1,292 @@ +package org.researchstack.backboneapp + +import android.view.View +import android.view.ViewGroup +import android.widget.DatePicker +import android.widget.LinearLayout +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.closeSoftKeyboard +import androidx.test.espresso.action.ViewActions.replaceText +import androidx.test.espresso.action.ViewActions.scrollTo +import androidx.test.espresso.action.ViewActions.swipeDown +import androidx.test.espresso.action.ViewActions.swipeRight +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.PickerActions.setDate +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withClassName +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withSubstring +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.filters.LargeTest +import androidx.test.rule.ActivityTestRule +import org.hamcrest.* +import org.hamcrest.Matchers.* +import org.hamcrest.core.* +import org.junit.* +import org.researchstack.backboneapp.R.id + +@LargeTest +class MainActivityTest { + + @Rule + @JvmField + var mActivityTestRule = ActivityTestRule(MainActivity::class.java) + + @Test + fun mainActivityTest() { + + // reset state, TODO: better way to setup/cleanup + onView(withId(R.id.menu_clear)).perform(click()) + + // Launch consent task + onView(withId(R.id.consent_button)).perform(click()) + + testConsentTask() + + // Launch survey task + onView(withId(R.id.survey_button)).perform(click()) + + testSurvey() + } + + private fun testSurvey() { + val appCompatTextView5 = onView( + allOf(withId(id.bar_submit_postitive), withText("next"), + childAtPosition( + allOf(withId(id.rsb_submit_bar), + childAtPosition( + withId(id.rsb_current_step), + 1)), + 2), + isDisplayed())) + appCompatTextView5.perform(click()) + + val appCompatEditText2 = onView( + allOf(withId(id.value), + childAtPosition( + allOf(withId(id.rsb_survey_step_body), + childAtPosition( + withId(id.rsb_survey_content_container), + 2)), + 1), + isDisplayed())) + appCompatEditText2.perform(replaceText("test"), closeSoftKeyboard()) + + val appCompatTextView6 = onView( + allOf(withId(id.bar_submit_postitive), withText("next"), + childAtPosition( + allOf(withId(id.rsb_submit_bar), + childAtPosition( + withId(id.rsb_current_step), + 1)), + 2), + isDisplayed())) + appCompatTextView6.perform(click()) + + + onView(withId(id.value)) + .perform(click()) + + onView(isAssignableFrom(DatePicker::class.java)) + .perform(setDate(2017, 6, 30)); + + val appCompatButton4 = onView( + allOf(withId(android.R.id.button1), withText("OK"), + childAtPosition( + childAtPosition( + withClassName(`is`("android.widget.ScrollView")), + 0), + 3))) + appCompatButton4.perform(scrollTo(), click()) + + val appCompatTextView7 = onView( + allOf(withId(id.bar_submit_postitive), withText("next"), + childAtPosition( + allOf(withId(id.rsb_submit_bar), + childAtPosition( + withId(id.rsb_current_step), + 1)), + 2), + isDisplayed())) + appCompatTextView7.perform(click()) + + val appCompatRadioButton = onView( + allOf(withText("Yes"), + childAtPosition( + allOf(withId(id.rsb_survey_step_body), + childAtPosition( + withId(id.rsb_survey_content_container), + 2)), + 0), + isDisplayed())) + appCompatRadioButton.perform(click()) + + val appCompatTextView8 = onView( + allOf(withId(id.bar_submit_postitive), withText("next"), + childAtPosition( + allOf(withId(id.rsb_submit_bar), + childAtPosition( + withId(id.rsb_current_step), + 1)), + 2), + isDisplayed())) + appCompatTextView8.perform(click()) + + val appCompatCheckBox = onView( + allOf(withText("One"), + childAtPosition( + allOf(withId(id.rsb_survey_step_body), + childAtPosition( + withId(id.rsb_survey_content_container), + 2)), + 1), + isDisplayed())) + appCompatCheckBox.perform(click()) + + val appCompatCheckBox2 = onView( + allOf(withText("Two"), + childAtPosition( + allOf(withId(id.rsb_survey_step_body), + childAtPosition( + withId(id.rsb_survey_content_container), + 2)), + 2), + isDisplayed())) + appCompatCheckBox2.perform(click()) + + val appCompatTextView9 = onView( + allOf(withId(id.bar_submit_postitive), withText("next"), + childAtPosition( + allOf(withId(id.rsb_submit_bar), + childAtPosition( + withId(id.rsb_current_step), + 1)), + 2), + isDisplayed())) + appCompatTextView9.perform(click()) + + val textView = onView( + allOf(withId(id.survey_results), + childAtPosition( + childAtPosition( + IsInstanceOf.instanceOf(LinearLayout::class.java), + 3), + 1), + isDisplayed())) + textView.check( + matches(allOf( + withSubstring("multi_step: [1.0, 2.0]"), + withSubstring("nutrition: true"), + withSubstring("date: 1.49"), + withSubstring("name: test"))) + + ) + } + + private fun testConsentTask() { + // ConsentVisualStep + + onView(withId(id.title)) + .check(matches(allOf( + withText("The title of the section goes here ..."), + isDisplayed()))) + + onView(withId(id.summary)) + .check(matches(allOf( + withText("The summary about the section goes here ..."), + isDisplayed()))) + + onView(withId(id.bar_submit_negative)) + .check(matches(not(isDisplayed()))) + + onView(withId(id.bar_submit_postitive)) + .check(matches(allOf(withText("next"), isDisplayed()))) + .perform(click()) + + // ConsentDocumentStep + + onView(withId(id.bar_submit_negative)) + .check(matches(allOf( + isDisplayed(), + withText("DISAGREE") + ))) + + onView(withId(id.bar_submit_postitive)) + .check(matches(allOf( + withText("Agree"), + isDisplayed()))) + .perform(click()) + + + onView(withId(android.R.id.button2)) + .check(matches(allOf( + withText("CANCEL"), + isDisplayed() + ))) + + onView(withId(android.R.id.button1)) + .check(matches(allOf( + withText("Agree"), + isDisplayed()))) + .perform(scrollTo(), click()) + + // FormStep (for signature) + + val appCompatEditText = onView( + allOf(withId(id.value), + childAtPosition( + childAtPosition( + withId(id.rsb_survey_step_body), + 0), + 1), + isDisplayed())) + appCompatEditText.perform(replaceText("test"), closeSoftKeyboard()) + + val appCompatTextView3 = onView( + allOf(withId(id.bar_submit_postitive), withText("next"), + childAtPosition( + allOf(withId(id.rsb_submit_bar), + childAtPosition( + withId(id.rsb_current_step), + 1)), + 2), + isDisplayed())) + appCompatTextView3.perform(click()) + + val appCompatTextView4 = onView( + allOf(withId(id.bar_submit_postitive), withText("next"), + childAtPosition( + allOf(withId(id.submit_bar), + childAtPosition( + withId(id.rsb_current_step), + 3)), + 2), + isDisplayed())) + + // ConsentSignatureStep + onView(withId(id.layout_consent_review_signature)) + .perform(swipeRight()) + .perform(swipeDown()) + + appCompatTextView4.perform(click()) + } + + private fun childAtPosition( + parentMatcher: Matcher, position: Int): Matcher { + + return object : TypeSafeMatcher() { + override fun describeTo(description: Description) { + description.appendText("Child at position $position in parent ") + parentMatcher.describeTo(description) + } + + public override fun matchesSafely(view: View): Boolean { + val parent = view.parent + return parent is ViewGroup && parentMatcher.matches(parent) + && view == parent.getChildAt(position) + } + } + } +} diff --git a/sample_backbone_app/src/main/AndroidManifest.xml b/sample_backbone_app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..0c72435bc --- /dev/null +++ b/sample_backbone_app/src/main/AndroidManifest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/sample_backbone_app/src/main/java/org/researchstack/backboneapp/AppPrefs.java b/sample_backbone_app/src/main/java/org/researchstack/backboneapp/AppPrefs.java new file mode 100644 index 000000000..921009c87 --- /dev/null +++ b/sample_backbone_app/src/main/java/org/researchstack/backboneapp/AppPrefs.java @@ -0,0 +1,58 @@ +package org.researchstack.backboneapp; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + + +public class AppPrefs +{ + public static final String HAS_CONSENTED = "HAS_CONSENTED"; + public static final String CONSENT_NAME = "CONSENT_NAME"; + public static final String CONSENT_SIGNATURE = "CONSENT_SIGNATURE"; + public static final String HAS_SURVEYED = "HAS_SURVEYED"; + public static final String SURVEY_RESULT = "SURVEY_RESULT"; + + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + // Statics + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + private static AppPrefs instance; + + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + // Field Vars + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + private final SharedPreferences prefs; + + AppPrefs(Context context) + { + prefs = PreferenceManager.getDefaultSharedPreferences(context); + } + + public static synchronized AppPrefs getInstance(Context context) + { + if(instance == null) + { + instance = new AppPrefs(context); + } + return instance; + } + + public boolean hasConsented() + { + return prefs.getBoolean(HAS_CONSENTED, false); + } + + public void setHasConsented(boolean consented) + { + prefs.edit().putBoolean(HAS_CONSENTED, consented).apply(); + } + + public boolean hasSurveyed() + { + return prefs.getBoolean(HAS_SURVEYED, false); + } + + public void setHasSurveyed(boolean surveyed) + { + prefs.edit().putBoolean(HAS_SURVEYED, surveyed).apply(); + } +} \ No newline at end of file diff --git a/sample_backbone_app/src/main/java/org/researchstack/backboneapp/BackboneApplication.java b/sample_backbone_app/src/main/java/org/researchstack/backboneapp/BackboneApplication.java new file mode 100644 index 000000000..89803d86e --- /dev/null +++ b/sample_backbone_app/src/main/java/org/researchstack/backboneapp/BackboneApplication.java @@ -0,0 +1,39 @@ +package org.researchstack.backboneapp; + +import android.app.Application; + +import org.researchstack.backbone.StorageAccess; +import org.researchstack.backbone.storage.database.AppDatabase; +import org.researchstack.backbone.storage.database.sqlite.DatabaseHelper; +import org.researchstack.backbone.storage.file.EncryptionProvider; +import org.researchstack.backbone.storage.file.FileAccess; +import org.researchstack.backbone.storage.file.PinCodeConfig; +import org.researchstack.backbone.storage.file.SimpleFileAccess; +import org.researchstack.backbone.storage.file.UnencryptedProvider; + + +public class BackboneApplication extends Application +{ + @Override + public void onCreate() + { + super.onCreate(); + + // Customize your pin code preferences + PinCodeConfig pinCodeConfig = new PinCodeConfig(); // default pin config (4-digit, 1 min lockout) + + // Customize encryption preferences + EncryptionProvider encryptionProvider = new UnencryptedProvider(); // No pin, no encryption + + // If you have special file handling needs, implement FileAccess + FileAccess fileAccess = new SimpleFileAccess(); + + // If you have your own custom database, implement AppDatabase + AppDatabase database = new DatabaseHelper(this, + DatabaseHelper.DEFAULT_NAME, + null, + DatabaseHelper.DEFAULT_VERSION); + + StorageAccess.getInstance().init(pinCodeConfig, encryptionProvider, fileAccess, database); + } +} diff --git a/sample_backbone_app/src/main/java/org/researchstack/backboneapp/MainActivity.java b/sample_backbone_app/src/main/java/org/researchstack/backboneapp/MainActivity.java new file mode 100644 index 000000000..315cf95d1 --- /dev/null +++ b/sample_backbone_app/src/main/java/org/researchstack/backboneapp/MainActivity.java @@ -0,0 +1,432 @@ +package org.researchstack.backboneapp; + +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.AppCompatButton; +import androidx.appcompat.widget.Toolbar; +import android.util.Base64; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import org.researchstack.backbone.StorageAccess; +import org.researchstack.backbone.answerformat.AnswerFormat; +import org.researchstack.backbone.answerformat.BooleanAnswerFormat; +import org.researchstack.backbone.answerformat.ChoiceAnswerFormat; +import org.researchstack.backbone.answerformat.DateAnswerFormat; +import org.researchstack.backbone.answerformat.IntegerAnswerFormat; +import org.researchstack.backbone.answerformat.TextAnswerFormat; +import org.researchstack.backbone.answerformat.UnknownAnswerFormat; +import org.researchstack.backbone.model.Choice; +import org.researchstack.backbone.model.ConsentDocument; +import org.researchstack.backbone.model.ConsentSection; +import org.researchstack.backbone.model.ConsentSignature; +import org.researchstack.backbone.result.StepResult; +import org.researchstack.backbone.result.TaskResult; +import org.researchstack.backbone.step.ConsentDocumentStep; +import org.researchstack.backbone.step.ConsentSignatureStep; +import org.researchstack.backbone.step.ConsentVisualStep; +import org.researchstack.backbone.step.FormStep; +import org.researchstack.backbone.step.InstructionStep; +import org.researchstack.backbone.step.QuestionStep; +import org.researchstack.backbone.task.OrderedTask; +import org.researchstack.backbone.task.Task; +import org.researchstack.backbone.ui.PinCodeActivity; +import org.researchstack.backbone.ui.ViewTaskActivity; +import org.researchstack.backbone.ui.step.layout.ConsentSignatureStepLayout; + +import java.util.ArrayList; +import java.util.Collections; + +public class MainActivity extends PinCodeActivity +{ + // Activity Request Codes + private static final int REQUEST_CONSENT = 0; + private static final int REQUEST_SURVEY = 1; + + // Task/Step Identifiers + public static final String FORM_STEP = "form_step"; + public static final String AGE = "age"; + public static final String INSTRUCTION = "identifier"; + public static final String BASIC_INFO_HEADER = "basic_info_header"; + public static final String FORM_AGE = "form_age"; + public static final String FORM_GENDER = "gender"; + public static final String FORM_MULTI_CHOICE = "multi_choice"; + public static final String FORM_DATE_OF_BIRTH = "date_of_birth"; + public static final String NUTRITION = "nutrition"; + public static final String SIGNATURE = "signature"; + public static final String SIGNATURE_DATE = "signature_date"; + public static final String VISUAL_CONSENT_IDENTIFIER = "visual_consent_identifier"; + public static final String CONSENT_DOC = "consent_doc"; + public static final String SIGNATURE_FORM_STEP = "form_step"; + public static final String NAME = "name"; + public static final String CONSENT = "consent"; + public static final String MULTI_STEP = "multi_step"; + public static final String DATE = "date"; + public static final String DECIMAL = "decimal"; + private static final String FORM_NAME = "form_name"; + public static final String SAMPLE_SURVEY = "sample_survey"; + + // Views + private AppCompatButton consentButton; + private AppCompatButton surveyButton; + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayShowTitleEnabled(true); + + consentButton = (AppCompatButton) findViewById(R.id.consent_button); + consentButton.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + launchConsent(); + } + }); + + surveyButton = (AppCompatButton) findViewById(R.id.survey_button); + surveyButton.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + launchSurvey(); + } + }); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) + { + getMenuInflater().inflate(R.menu.activity_main, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + if (item.getItemId() == R.id.menu_clear) + { + clearData(); + Toast.makeText(this, R.string.menu_data_cleared, Toast.LENGTH_SHORT).show(); + return true; + } + else + { + return super.onOptionsItemSelected(item); + } + } + + void clearData() + { + AppPrefs appPrefs = AppPrefs.getInstance(this); + appPrefs.setHasSurveyed(false); + appPrefs.setHasConsented(false); + + initViews(); + } + + @Override + public void onDataReady() + { + super.onDataReady(); + initViews(); + } + + private void initViews() + { + AppPrefs prefs = AppPrefs.getInstance(this); + + View lblConsentedDate = findViewById(R.id.consented_date_lbl); + TextView consentedDate = (TextView)findViewById(R.id.consented_date); + ImageView consentedSig = (ImageView) findViewById(R.id.consented_signature); + + if(prefs.hasConsented()) + { + consentButton.setVisibility(View.GONE); + surveyButton.setEnabled(true); + + consentedSig.setVisibility(View.VISIBLE); + consentedDate.setVisibility(View.VISIBLE); + lblConsentedDate.setVisibility(View.VISIBLE); + + printConsentInfo(consentedDate, consentedSig); + } + else + { + consentButton.setVisibility(View.VISIBLE); + surveyButton.setEnabled(false); + + consentedSig.setVisibility(View.INVISIBLE); + consentedSig.setImageBitmap(null); + consentedDate.setVisibility(View.INVISIBLE); + lblConsentedDate.setVisibility(View.INVISIBLE); + } + + TextView surveyAnswer = (TextView) findViewById(R.id.survey_results); + + if(prefs.hasSurveyed()) + { + surveyAnswer.setVisibility(View.VISIBLE); + printSurveyInfo(surveyAnswer); + } + else + { + surveyAnswer.setVisibility(View.GONE); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) + { + super.onActivityResult(requestCode, resultCode, data); + + if(requestCode == REQUEST_CONSENT && resultCode == RESULT_OK) + { + processConsentResult((TaskResult) data.getSerializableExtra(ViewTaskActivity.EXTRA_TASK_RESULT)); + } + else if(requestCode == REQUEST_SURVEY && resultCode == RESULT_OK) + { + processSurveyResult((TaskResult) data.getSerializableExtra(ViewTaskActivity.EXTRA_TASK_RESULT)); + } + } + + // Consent stuff + + private void launchConsent() + { + ConsentDocument document = new ConsentDocument(); + document.setTitle("Demo Consent"); + document.setSignaturePageTitle(R.string.rsb_consent); + + // Create consent visual sections + ConsentSection section1 = new ConsentSection(ConsentSection.Type.DataGathering); + section1.setTitle("The title of the section goes here ..."); + section1.setSummary("The summary about the section goes here ..."); + section1.setContent("The content to show in learn more ..."); + + // ...add more sections as needed, then create a visual consent step + ConsentVisualStep visualStep = new ConsentVisualStep(VISUAL_CONSENT_IDENTIFIER); + visualStep.setStepTitle(R.string.rsb_consent); + visualStep.setSection(section1); + visualStep.setNextButtonString(getString(R.string.rsb_next)); + + // Create consent signature object and set what info is required + ConsentSignature signature = new ConsentSignature(); + signature.setRequiresName(true); + signature.setRequiresSignatureImage(true); + + // Create our HTML to show the user and have them accept or decline. + StringBuilder docBuilder = new StringBuilder( + "

"); + String title = getString(R.string.rsb_consent_review_title); + docBuilder.append(String.format( + "

%1$s

", + title)); + String detail = getString(R.string.rsb_consent_review_instruction); + docBuilder.append(String.format("

%1$s

", detail)); + docBuilder.append("

"); + docBuilder.append("

HTML Consent Doc goes here

"); + + // Create the Consent doc step, pass in our HTML doc + ConsentDocumentStep documentStep = new ConsentDocumentStep(CONSENT_DOC); + documentStep.setConsentHTML(docBuilder.toString()); + documentStep.setConfirmMessage(getString(R.string.rsb_consent_review_reason)); + + // Create Consent form step, to get users first & last name + FormStep formStep = new FormStep(SIGNATURE_FORM_STEP, + "Form Title", + "Form step description"); + formStep.setStepTitle(R.string.rsb_consent); + + TextAnswerFormat format = new TextAnswerFormat(); + format.setIsMultipleLines(false); + + QuestionStep fullName = new QuestionStep(NAME, "Full name", format); + formStep.setFormSteps(Collections.singletonList(fullName)); + + // Create Consent signature step, user can sign their name + ConsentSignatureStep signatureStep = new ConsentSignatureStep(SIGNATURE); + signatureStep.setStepTitle(R.string.rsb_consent); + signatureStep.setTitle(getString(R.string.rsb_consent_signature_title)); + signatureStep.setText(getString(R.string.rsb_consent_signature_instruction)); + signatureStep.setSignatureDateFormat(signature.getSignatureDateFormatString()); + signatureStep.setOptional(false); + signatureStep.setStepLayoutClass(ConsentSignatureStepLayout.class); + + // Finally, create and present a task including these steps. + Task consentTask = new OrderedTask(CONSENT, + visualStep, + documentStep, + formStep, + signatureStep); + + // Launch using hte ViewTaskActivity and make sure to listen for the activity result + Intent intent = ViewTaskActivity.newIntent(this, consentTask); + startActivityForResult(intent, REQUEST_CONSENT); + } + + private void processConsentResult(TaskResult result) + { + boolean consented = (boolean) result.getStepResult(CONSENT_DOC).getResult(); + + if(consented) + { + StorageAccess.getInstance().getAppDatabase().saveTaskResult(result); + + AppPrefs prefs = AppPrefs.getInstance(this); + prefs.setHasConsented(true); + + initViews(); + } + } + + private void printConsentInfo(TextView consentedDate, ImageView consentedSig) + { + TaskResult result = StorageAccess.getInstance() + .getAppDatabase() + .loadLatestTaskResult(CONSENT); + + String signatureBase64 = (String) result.getStepResult(SIGNATURE) + .getResultForIdentifier(ConsentSignatureStepLayout.KEY_SIGNATURE); + + String signatureDate = (String) result.getStepResult(SIGNATURE) + .getResultForIdentifier(ConsentSignatureStepLayout.KEY_SIGNATURE_DATE); + + consentedDate.setText(signatureDate); + + byte[] signatureBytes = Base64.decode(signatureBase64, Base64.DEFAULT); + consentedSig.setImageBitmap(BitmapFactory.decodeByteArray( + signatureBytes, + 0, + signatureBytes.length)); + } + + + // Survey Stuff + + private void launchSurvey() + { + InstructionStep instructionStep = new InstructionStep(INSTRUCTION, + "Selection Survey", + "This survey can help us understand your eligibility for the fitness study"); + instructionStep.setStepTitle(R.string.survey); + + TextAnswerFormat format = new TextAnswerFormat(); + QuestionStep ageStep = new QuestionStep(NAME, "What is your name?", format); + ageStep.setStepTitle(R.string.survey); + + DateAnswerFormat dateFormat = new DateAnswerFormat(AnswerFormat.DateAnswerStyle.Date); + QuestionStep dateStep = new QuestionStep(DATE, "Enter a date", dateFormat); + dateStep.setStepTitle(R.string.survey); + + // Create a Boolean step to include in the task. + QuestionStep booleanStep = new QuestionStep(NUTRITION); + booleanStep.setStepTitle(R.string.survey); + booleanStep.setTitle("Do you take nutritional supplements?"); + booleanStep.setAnswerFormat(new BooleanAnswerFormat(getString(R.string.rsb_yes), + getString(R.string.rsb_no))); + booleanStep.setOptional(false); + + QuestionStep multiStep = new QuestionStep(MULTI_STEP); + multiStep.setStepTitle(R.string.survey); + AnswerFormat multiFormat = new ChoiceAnswerFormat(AnswerFormat.ChoiceAnswerStyle.MultipleChoice, + new Choice<>("Zero", 0), + new Choice<>("One", 1), + new Choice<>("Two", 2)); + multiStep.setTitle("Select multiple"); + multiStep.setAnswerFormat(multiFormat); + multiStep.setOptional(false); + + // Create a task wrapping the steps. + OrderedTask task = new OrderedTask(SAMPLE_SURVEY, instructionStep, ageStep, dateStep, + // formStep, + booleanStep, multiStep); + + // Create an activity using the task and set a delegate. + Intent intent = ViewTaskActivity.newIntent(this, task); + startActivityForResult(intent, REQUEST_SURVEY); + } + + @NonNull + private FormStep createFormStep() + { + FormStep formStep = new FormStep(FORM_STEP, "Form", "Form groups multi-entry in one page"); + ArrayList formItems = new ArrayList<>(); + + QuestionStep basicInfoHeader = new QuestionStep(BASIC_INFO_HEADER, + "Basic Information", + new UnknownAnswerFormat()); + formItems.add(basicInfoHeader); + + TextAnswerFormat format = new TextAnswerFormat(); + format.setIsMultipleLines(false); + QuestionStep nameItem = new QuestionStep(FORM_NAME, "Name", format); + formItems.add(nameItem); + + QuestionStep ageItem = new QuestionStep(FORM_AGE, "Age", new IntegerAnswerFormat(18, 90)); + formItems.add(ageItem); + + AnswerFormat genderFormat = new ChoiceAnswerFormat(AnswerFormat.ChoiceAnswerStyle.SingleChoice, + new Choice<>("Male", 0), + new Choice<>("Female", 1)); + QuestionStep genderFormItem = new QuestionStep(FORM_GENDER, "Gender", genderFormat); + formItems.add(genderFormItem); + + AnswerFormat multiFormat = new ChoiceAnswerFormat(AnswerFormat.ChoiceAnswerStyle.MultipleChoice, + new Choice<>("Zero", 0), + new Choice<>("One", 1), + new Choice<>("Two", 2)); + QuestionStep multiFormItem = new QuestionStep(FORM_MULTI_CHOICE, "Test Multi", multiFormat); + formItems.add(multiFormItem); + + AnswerFormat dateOfBirthFormat = new DateAnswerFormat(AnswerFormat.DateAnswerStyle.Date); + QuestionStep dateOfBirthFormItem = new QuestionStep(FORM_DATE_OF_BIRTH, + "Birthdate", + dateOfBirthFormat); + formItems.add(dateOfBirthFormItem); + + // ... And so on, adding additional items + formStep.setFormSteps(formItems); + return formStep; + } + + private void processSurveyResult(TaskResult result) + { + StorageAccess.getInstance().getAppDatabase().saveTaskResult(result); + + AppPrefs prefs = AppPrefs.getInstance(this); + prefs.setHasSurveyed(true); + initViews(); + } + + private void printSurveyInfo(TextView surveyAnswer) + { + TaskResult taskResult = StorageAccess.getInstance() + .getAppDatabase() + .loadLatestTaskResult(SAMPLE_SURVEY); + + String results = ""; + for(String id : taskResult.getResults().keySet()) + { + StepResult stepResult = taskResult.getStepResult(id); + results += id + ": " + stepResult.getResult().toString() + "\n"; + } + + surveyAnswer.setText(results); + } +} diff --git a/sample_backbone_app/src/main/res/layout/activity_main.xml b/sample_backbone_app/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..29bd51f79 --- /dev/null +++ b/sample_backbone_app/src/main/res/layout/activity_main.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample_backbone_app/src/main/res/menu/activity_main.xml b/sample_backbone_app/src/main/res/menu/activity_main.xml new file mode 100644 index 000000000..abc9d8bf9 --- /dev/null +++ b/sample_backbone_app/src/main/res/menu/activity_main.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/sample_backbone_app/src/main/res/mipmap-hdpi/ic_launcher.png b/sample_backbone_app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..aa46eebdc Binary files /dev/null and b/sample_backbone_app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/sample_backbone_app/src/main/res/mipmap-mdpi/ic_launcher.png b/sample_backbone_app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..cbab2b190 Binary files /dev/null and b/sample_backbone_app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/sample_backbone_app/src/main/res/mipmap-xhdpi/ic_launcher.png b/sample_backbone_app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..82a75e801 Binary files /dev/null and b/sample_backbone_app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/sample_backbone_app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/sample_backbone_app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..dded52e65 Binary files /dev/null and b/sample_backbone_app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/sample_backbone_app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/sample_backbone_app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4cf21665a Binary files /dev/null and b/sample_backbone_app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/sample_backbone_app/src/main/res/values-v21/styles.xml b/sample_backbone_app/src/main/res/values-v21/styles.xml new file mode 100644 index 000000000..2c02b673a --- /dev/null +++ b/sample_backbone_app/src/main/res/values-v21/styles.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/sample_backbone_app/src/main/res/values-w820dp/dimens.xml b/sample_backbone_app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 000000000..63fc81644 --- /dev/null +++ b/sample_backbone_app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/sample_backbone_app/src/main/res/values/colors.xml b/sample_backbone_app/src/main/res/values/colors.xml new file mode 100644 index 000000000..975426a94 --- /dev/null +++ b/sample_backbone_app/src/main/res/values/colors.xml @@ -0,0 +1,7 @@ + + + #3F51B5 + #303F9F + #FF4081 + #cccccc + diff --git a/sample_backbone_app/src/main/res/values/dimens.xml b/sample_backbone_app/src/main/res/values/dimens.xml new file mode 100644 index 000000000..47c822467 --- /dev/null +++ b/sample_backbone_app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + diff --git a/sample_backbone_app/src/main/res/values/strings.xml b/sample_backbone_app/src/main/res/values/strings.xml new file mode 100644 index 000000000..b1472a140 --- /dev/null +++ b/sample_backbone_app/src/main/res/values/strings.xml @@ -0,0 +1,11 @@ + + Backbone App + Start Consent + Take Survey + Consented + Clear + Survey + Data has been cleared + User Name: + Date Consented: + diff --git a/sample_backbone_app/src/main/res/values/styles.xml b/sample_backbone_app/src/main/res/values/styles.xml new file mode 100644 index 000000000..c0507cc6b --- /dev/null +++ b/sample_backbone_app/src/main/res/values/styles.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample_backbone_app/src/test/java/org/researchstack/backboneapp/ExampleUnitTest.java b/sample_backbone_app/src/test/java/org/researchstack/backboneapp/ExampleUnitTest.java new file mode 100644 index 000000000..3132a0438 --- /dev/null +++ b/sample_backbone_app/src/test/java/org/researchstack/backboneapp/ExampleUnitTest.java @@ -0,0 +1,18 @@ +package org.researchstack.backboneapp; + +import org.junit.Test; + + +import static org.junit.Assert.assertEquals; + +/** + * To work on unit tests, switch the Test Artifact in the Build Variants view. + */ +public class ExampleUnitTest +{ + @Test + public void addition_isCorrect() throws Exception + { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 408516fa3..46157c442 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,2 @@ -include ':backbone', ':skin' +include ':backbone', ':skin', ':foundation', ':authentication', ':chart', ':consent', ':storage' +include ':sample_backbone_app' \ No newline at end of file diff --git a/skin/build.gradle b/skin/build.gradle index d828485dc..07c2d932b 100644 --- a/skin/build.gradle +++ b/skin/build.gradle @@ -1,25 +1,26 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' apply plugin: 'com.github.dcendents.android-maven' -apply plugin: 'me.tatarka.retrolambda' -apply plugin: 'com.neenbedankt.android-apt' apply plugin: 'com.jfrog.bintray' -version = '1.1.2' +apply plugin: 'kotlin-kapt' + +version = research_stack_version android { - compileSdkVersion 23 - buildToolsVersion "23.0.2" + compileSdkVersion 28 lintOptions { warning "InvalidPackage" } defaultConfig { - minSdkVersion 16 - targetSdkVersion 23 - versionCode 6 + minSdkVersion 19 + targetSdkVersion 28 + versionCode 7 versionName version } + buildTypes { release { minifyEnabled false @@ -69,16 +70,38 @@ ext { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar', '*.so']) - compile 'com.cronutils:cron-utils:3.1.2' - compile project(':backbone') - testCompile 'junit:junit:4.12' - testCompile 'org.robolectric:robolectric:3.0' - testCompile 'org.mockito:mockito-core:1.10.19' - compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3' - compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3' - compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta3' - compile 'com.squareup.okhttp3:logging-interceptor:3.0.0-RC1' + implementation fileTree(dir: 'libs', include: ['*.jar', '*.so']) + implementation 'com.cronutils:cron-utils:3.1.2' + implementation project(':foundation') + implementation project(':authentication') + implementation project(':storage') + implementation project(':consent') + + implementation project(':backbone') + + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.legacy:legacy-preference-v14:1.0.0' + implementation 'com.google.android.material:material:1.0.0' + + implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation 'com.jakewharton.rxbinding:rxbinding:0.4.0' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation 'com.jakewharton.rxbinding:rxbinding-support-v4:0.4.0' + implementation 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.4.0' + implementation 'com.jakewharton.rxbinding:rxbinding-design:0.4.0' + + implementation 'co.touchlab.squeaky:squeaky-query:0.4.0.0' + kapt 'co.touchlab.squeaky:squeaky-processor:0.4.0.0' + + testImplementation 'junit:junit:4.12' + testImplementation 'org.robolectric:robolectric:3.0' + testImplementation 'org.mockito:mockito-core:1.10.19' + implementation 'com.squareup.retrofit2:retrofit:2.0.0-beta3' + implementation 'com.squareup.retrofit2:converter-gson:2.0.0-beta3' + implementation 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta3' + implementation 'com.squareup.okhttp3:logging-interceptor:3.0.0-RC1' } diff --git a/skin/src/main/java/org/researchstack/skin/DataProvider.java b/skin/src/main/java/org/researchstack/skin/DataProvider.java index 3cbfd5a58..f3e32b8b8 100644 --- a/skin/src/main/java/org/researchstack/skin/DataProvider.java +++ b/skin/src/main/java/org/researchstack/skin/DataProvider.java @@ -3,9 +3,8 @@ import android.app.Application; import android.content.Context; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.storage.file.FileAccess; -import org.researchstack.backbone.task.Task; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.task.Task; import org.researchstack.skin.model.SchedulesAndTasksModel; import org.researchstack.skin.model.User; import org.researchstack.skin.ui.EmailVerificationActivity; diff --git a/skin/src/main/java/org/researchstack/skin/PermissionRequestManager.java b/skin/src/main/java/org/researchstack/skin/PermissionRequestManager.java index 23c748e4e..175de0a30 100644 --- a/skin/src/main/java/org/researchstack/skin/PermissionRequestManager.java +++ b/skin/src/main/java/org/researchstack/skin/PermissionRequestManager.java @@ -5,9 +5,9 @@ import android.app.Application; import android.content.Context; import android.content.Intent; -import android.support.annotation.DrawableRes; -import android.support.annotation.StringRes; -import android.support.v4.content.ContextCompat; +import androidx.annotation.DrawableRes; +import androidx.annotation.StringRes; +import androidx.core.content.ContextCompat; import org.researchstack.skin.ui.layout.PermissionStepLayout; diff --git a/skin/src/main/java/org/researchstack/skin/ResearchStack.java b/skin/src/main/java/org/researchstack/skin/ResearchStack.java index 84b3500ea..584580452 100644 --- a/skin/src/main/java/org/researchstack/skin/ResearchStack.java +++ b/skin/src/main/java/org/researchstack/skin/ResearchStack.java @@ -3,11 +3,12 @@ import android.app.Application; import android.content.Context; -import org.researchstack.backbone.StorageAccess; -import org.researchstack.backbone.storage.database.AppDatabase; -import org.researchstack.backbone.storage.file.EncryptionProvider; -import org.researchstack.backbone.storage.file.FileAccess; -import org.researchstack.backbone.storage.file.PinCodeConfig; +import org.researchstack.feature.authentication.pincode.PinCodeConfig; +import org.researchstack.feature.authentication.pincode.PinCodeConfigProvider; +import org.researchstack.feature.storage.StorageAccess; +import org.researchstack.feature.storage.database.AppDatabase; +import org.researchstack.feature.storage.file.EncryptionProvider; +import org.researchstack.feature.storage.file.FileAccess; import org.researchstack.skin.notification.NotificationConfig; /** @@ -53,8 +54,10 @@ public static void init(Context context, ResearchStack concreteResearchStack) { DataProvider.init(concreteResearchStack.createDataProviderImplementation(context)); + PinCodeConfig pinCodeConfig = concreteResearchStack.getPinCodeConfig(context); + PinCodeConfigProvider.Companion.config(pinCodeConfig); StorageAccess.getInstance() - .init(concreteResearchStack.getPinCodeConfig(context), + .init(pinCodeConfig, concreteResearchStack.getEncryptionProvider(context), concreteResearchStack.createFileAccessImplementation(context), concreteResearchStack.createAppDatabaseImplementation(context)); diff --git a/skin/src/main/java/org/researchstack/skin/ResourceManager.java b/skin/src/main/java/org/researchstack/skin/ResourceManager.java index e3ded729e..e9cec4e66 100644 --- a/skin/src/main/java/org/researchstack/skin/ResourceManager.java +++ b/skin/src/main/java/org/researchstack/skin/ResourceManager.java @@ -1,6 +1,6 @@ package org.researchstack.skin; -import org.researchstack.backbone.ResourcePathManager; +import org.researchstack.foundation.components.singletons.ResourcePathManager; /** * This class is responsible for returning paths of resources defined in the assets folder. This diff --git a/skin/src/main/java/org/researchstack/skin/TaskProvider.java b/skin/src/main/java/org/researchstack/skin/TaskProvider.java index b3b9658ff..a3b6b3d2e 100644 --- a/skin/src/main/java/org/researchstack/skin/TaskProvider.java +++ b/skin/src/main/java/org/researchstack/skin/TaskProvider.java @@ -2,13 +2,17 @@ import android.app.Application; -import org.researchstack.backbone.task.Task; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.researchstack.foundation.components.presentation.ITaskProvider; +import org.researchstack.foundation.core.interfaces.ITask; +import org.researchstack.foundation.core.models.task.Task; /** * TaskProvider is used as a way for the Framework to get Tasks needed throughout the onboarding * process. This allows you to implement your own Tasks if needed. */ -public abstract class TaskProvider { +public abstract class TaskProvider implements ITaskProvider { /** * Task ID used by the framework for looking up the "initial" task */ @@ -64,6 +68,12 @@ public static TaskProvider getInstance() { */ public abstract Task get(String taskId); + @Nullable + @Override + public ITask task(@NotNull String identifier) { + return this.get(identifier); + } + /** * Used to store a task object for reuse * diff --git a/skin/src/main/java/org/researchstack/skin/UiManager.java b/skin/src/main/java/org/researchstack/skin/UiManager.java index c3849d8ff..7f14c8ce4 100644 --- a/skin/src/main/java/org/researchstack/skin/UiManager.java +++ b/skin/src/main/java/org/researchstack/skin/UiManager.java @@ -3,8 +3,10 @@ import android.app.Application; import android.content.Context; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; +import androidx.fragment.app.Fragment; + +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.notification.TaskNotificationReceiver; import java.util.List; @@ -53,7 +55,7 @@ public static UiManager getInstance() { * All ActionItems returned by this method should define a title, icon, and class. These items * are used to fill a pager in the MainActivity. The framework uses the class objects from this * list to create a Fragments for tha pager. It is imperative that the defined classes be of - * instance {@link android.support.v4.app.Fragment}. + * instance {@link Fragment}. * * @return a list of ActionItems for display in the MainActivity ActionBar */ diff --git a/skin/src/main/java/org/researchstack/skin/model/ConsentQuizModel.java b/skin/src/main/java/org/researchstack/skin/model/ConsentQuizModel.java index 50b7c107c..6c66d500a 100644 --- a/skin/src/main/java/org/researchstack/skin/model/ConsentQuizModel.java +++ b/skin/src/main/java/org/researchstack/skin/model/ConsentQuizModel.java @@ -12,7 +12,7 @@ public class ConsentQuizModel implements Serializable { private List questions; // fields with defaults - private String incorrectIcon = "rsb_quiz_retry"; + private String incorrectIcon = "rsf_quiz_retry"; private String correctIcon = "rss_ic_quiz_valid"; public String getFailureTitle() { diff --git a/skin/src/main/java/org/researchstack/skin/model/ConsentSectionModel.java b/skin/src/main/java/org/researchstack/skin/model/ConsentSectionModel.java index 092a091b7..a933272d1 100644 --- a/skin/src/main/java/org/researchstack/skin/model/ConsentSectionModel.java +++ b/skin/src/main/java/org/researchstack/skin/model/ConsentSectionModel.java @@ -2,8 +2,8 @@ import com.google.gson.annotations.SerializedName; -import org.researchstack.backbone.model.ConsentSection; import org.researchstack.backbone.model.DocumentProperties; +import org.researchstack.feature.consent.model.ConsentSection; import java.util.List; diff --git a/skin/src/main/java/org/researchstack/skin/notification/NotificationConfig.java b/skin/src/main/java/org/researchstack/skin/notification/NotificationConfig.java index 0190423eb..59b2b632a 100644 --- a/skin/src/main/java/org/researchstack/skin/notification/NotificationConfig.java +++ b/skin/src/main/java/org/researchstack/skin/notification/NotificationConfig.java @@ -2,8 +2,8 @@ import android.app.Application; import android.content.Context; -import android.support.annotation.ColorInt; -import android.support.annotation.DrawableRes; +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; /** * Configuration class for framework notifciations diff --git a/skin/src/main/java/org/researchstack/skin/notification/SimpleNotificationConfig.java b/skin/src/main/java/org/researchstack/skin/notification/SimpleNotificationConfig.java index 9886e8de2..66204538f 100644 --- a/skin/src/main/java/org/researchstack/skin/notification/SimpleNotificationConfig.java +++ b/skin/src/main/java/org/researchstack/skin/notification/SimpleNotificationConfig.java @@ -12,7 +12,7 @@ public int getSmallIcon() { @Override public int getLargeIconBackgroundColor(Context context) { - return context.getResources().getColor(R.color.rsb_error); + return context.getResources().getColor(R.color.rsf_error); } @Override diff --git a/skin/src/main/java/org/researchstack/skin/notification/TaskAlertReceiver.java b/skin/src/main/java/org/researchstack/skin/notification/TaskAlertReceiver.java index 425ea40a6..c82c8acc3 100644 --- a/skin/src/main/java/org/researchstack/skin/notification/TaskAlertReceiver.java +++ b/skin/src/main/java/org/researchstack/skin/notification/TaskAlertReceiver.java @@ -7,11 +7,11 @@ import android.content.Intent; import android.util.Log; -import org.researchstack.backbone.storage.NotificationHelper; -import org.researchstack.backbone.storage.database.TaskNotification; -import org.researchstack.backbone.utils.FormatHelper; -import org.researchstack.backbone.utils.LogExt; import org.researchstack.backbone.utils.ObservableUtils; +import org.researchstack.feature.storage.NotificationHelper; +import org.researchstack.feature.storage.database.TaskNotification; +import org.researchstack.foundation.components.utils.FormatHelper; +import org.researchstack.foundation.components.utils.LogExt; import org.researchstack.skin.UiManager; import org.researchstack.skin.schedule.ScheduleHelper; diff --git a/skin/src/main/java/org/researchstack/skin/notification/TaskNotificationReceiver.java b/skin/src/main/java/org/researchstack/skin/notification/TaskNotificationReceiver.java index 6ae54463c..f07a4528e 100644 --- a/skin/src/main/java/org/researchstack/skin/notification/TaskNotificationReceiver.java +++ b/skin/src/main/java/org/researchstack/skin/notification/TaskNotificationReceiver.java @@ -6,7 +6,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.support.v7.app.NotificationCompat; +//import android.support.v7.app.NotificationCompat; +import androidx.core.app.NotificationCompat; import android.util.Log; import org.researchstack.skin.ui.MainActivity; diff --git a/skin/src/main/java/org/researchstack/skin/step/ConsentQuizEvaluationStep.java b/skin/src/main/java/org/researchstack/skin/step/ConsentQuizEvaluationStep.java index 778bd071c..5d658f588 100644 --- a/skin/src/main/java/org/researchstack/skin/step/ConsentQuizEvaluationStep.java +++ b/skin/src/main/java/org/researchstack/skin/step/ConsentQuizEvaluationStep.java @@ -1,6 +1,6 @@ package org.researchstack.skin.step; -import org.researchstack.backbone.step.Step; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.R; import org.researchstack.skin.model.ConsentQuizModel; import org.researchstack.skin.ui.layout.ConsentQuizEvaluationStepLayout; @@ -18,7 +18,7 @@ public ConsentQuizEvaluationStep(String identifier, ConsentQuizModel quizModel) @Override public int getStepTitle() { - return R.string.rsb_quiz_evaluation; + return R.string.rsfc_quiz_evaluation; } @Override diff --git a/skin/src/main/java/org/researchstack/skin/step/ConsentQuizQuestionStep.java b/skin/src/main/java/org/researchstack/skin/step/ConsentQuizQuestionStep.java index fb844a464..84992f7a6 100644 --- a/skin/src/main/java/org/researchstack/skin/step/ConsentQuizQuestionStep.java +++ b/skin/src/main/java/org/researchstack/skin/step/ConsentQuizQuestionStep.java @@ -1,6 +1,6 @@ package org.researchstack.skin.step; -import org.researchstack.backbone.step.Step; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.R; import org.researchstack.skin.model.ConsentQuizModel; import org.researchstack.skin.ui.layout.ConsentQuizQuestionStepLayout; @@ -20,7 +20,7 @@ public Class getStepLayoutClass() { @Override public int getStepTitle() { - return R.string.rsb_quiz; + return R.string.rsfc_quiz; } @Override diff --git a/skin/src/main/java/org/researchstack/skin/task/ConsentTask.java b/skin/src/main/java/org/researchstack/skin/task/ConsentTask.java index 34ecb7fbc..8ca9bc340 100644 --- a/skin/src/main/java/org/researchstack/skin/task/ConsentTask.java +++ b/skin/src/main/java/org/researchstack/skin/task/ConsentTask.java @@ -3,29 +3,29 @@ import android.content.Context; import android.content.res.Resources; -import org.researchstack.backbone.answerformat.AnswerFormat; -import org.researchstack.backbone.answerformat.BirthDateAnswerFormat; -import org.researchstack.backbone.answerformat.ChoiceAnswerFormat; -import org.researchstack.backbone.answerformat.DateAnswerFormat; -import org.researchstack.backbone.answerformat.TextAnswerFormat; -import org.researchstack.backbone.model.Choice; -import org.researchstack.backbone.model.ConsentDocument; -import org.researchstack.backbone.model.ConsentSection; -import org.researchstack.backbone.model.ConsentSignature; import org.researchstack.backbone.model.DocumentProperties; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.ConsentDocumentStep; -import org.researchstack.backbone.step.ConsentSharingStep; -import org.researchstack.backbone.step.ConsentSignatureStep; -import org.researchstack.backbone.step.ConsentVisualStep; -import org.researchstack.backbone.step.FormStep; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.task.OrderedTask; -import org.researchstack.backbone.ui.step.layout.ConsentSignatureStepLayout; -import org.researchstack.backbone.utils.LogExt; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.feature.consent.model.ConsentDocument; +import org.researchstack.feature.consent.model.ConsentSection; +import org.researchstack.feature.consent.model.ConsentSignature; +import org.researchstack.feature.consent.step.ConsentDocumentStep; +import org.researchstack.feature.consent.step.ConsentSharingStep; +import org.researchstack.feature.consent.step.ConsentSignatureStep; +import org.researchstack.feature.consent.step.ConsentVisualStep; +import org.researchstack.feature.consent.ui.layout.ConsentSignatureStepLayout; +import org.researchstack.foundation.components.common.task.OrderedTask; +import org.researchstack.foundation.components.survey.answerformat.AnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.BirthDateAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.ChoiceAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.DateAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.TextAnswerFormat; +import org.researchstack.foundation.components.survey.model.Choice; +import org.researchstack.foundation.components.survey.step.FormStep; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.R; import org.researchstack.skin.ResourceManager; import org.researchstack.skin.model.ConsentQuizModel; @@ -75,9 +75,9 @@ public static ConsentTask create(Context context, String taskId) { signature.setRequiresBirthDate(properties.requiresBirthdate()); ConsentDocument doc = new ConsentDocument(); - doc.setTitle(r.getString(R.string.rsb_consent_form_title)); - doc.setSignaturePageTitle(R.string.rsb_consent_form_title); - doc.setSignaturePageContent(r.getString(R.string.rsb_consent_signature_content)); + doc.setTitle(r.getString(R.string.rsfc_consent_form_title)); + doc.setSignaturePageTitle(R.string.rsfc_consent_form_title); + doc.setSignaturePageContent(r.getString(R.string.rsfc_consent_signature_content)); doc.setSections(sections); doc.addSignature(signature); @@ -116,13 +116,13 @@ private static void initConsentSharingStep(Resources r, ConsentSectionModel data ConsentSharingStep sharingStep = new ConsentSharingStep(ID_SHARING); sharingStep.setOptional(false); - sharingStep.setStepTitle(R.string.rsb_consent); + sharingStep.setStepTitle(R.string.rsfc_consent); // sharingStep.setLocalizedLearnMoreHTMLContent(localizedLearnMoreHTMLContent); - String shareWidely = r.getString(R.string.rsb_consent_share_widely, investigatorLongDesc); + String shareWidely = r.getString(R.string.rsfc_consent_share_widely, investigatorLongDesc); Choice shareWidelyChoice = new Choice<>(shareWidely, "sponsors_and_partners", null); - String shareRestricted = r.getString(R.string.rsb_consent_share_only, + String shareRestricted = r.getString(R.string.rsfc_consent_share_only, investigatorShortDesc); Choice shareRestrictedChoice = new Choice<>(shareRestricted, "all_qualified_researchers", @@ -132,8 +132,8 @@ private static void initConsentSharingStep(Resources r, ConsentSectionModel data shareWidelyChoice, shareRestrictedChoice)); - sharingStep.setTitle(r.getString(R.string.rsb_consent_share_title)); - sharingStep.setText(r.getString(R.string.rsb_consent_share_description, + sharingStep.setTitle(r.getString(R.string.rsfc_consent_share_title)); + sharingStep.setText(r.getString(R.string.rsfc_consent_share_description, investigatorLongDesc, localizedLearnMoreHTMLContent)); @@ -153,11 +153,11 @@ private static void initVisualSteps(Context ctx, ConsentDocument doc, List ConsentVisualStep step = new ConsentVisualStep("consent_" + i); step.setSection(section); - String nextString = ctx.getString(R.string.rsb_next); + String nextString = ctx.getString(R.string.rsf_next); if (section.getType() == ConsentSection.Type.Overview) { - nextString = ctx.getString(R.string.rsb_get_started); + nextString = ctx.getString(R.string.rsf_get_started); } else if (i == size - 1) { - nextString = ctx.getString(R.string.rsb_done); + nextString = ctx.getString(R.string.rsf_done); } step.setNextButtonString(nextString); @@ -193,18 +193,18 @@ private static void initConsentReviewSteps(Context ctx, ConsentDocument doc, Lis // Add ConsentReviewDocumentStep (view html version of the PDF doc) StringBuilder docBuilder = new StringBuilder( "
"); - String title = ctx.getString(R.string.rsb_consent_review_title); + String title = ctx.getString(R.string.rsfc_consent_review_title); docBuilder.append(String.format( "

%1$s

", title)); - String detail = ctx.getString(R.string.rsb_consent_review_instruction); + String detail = ctx.getString(R.string.rsfc_consent_review_instruction); docBuilder.append(String.format("

%1$s

", detail)); docBuilder.append("

"); docBuilder.append(doc.getHtmlReviewContent()); ConsentDocumentStep step = new ConsentDocumentStep(ID_CONSENT_DOC); step.setConsentHTML(docBuilder.toString()); - step.setConfirmMessage(ctx.getString(R.string.rsb_consent_review_reason)); + step.setConfirmMessage(ctx.getString(R.string.rsfc_consent_review_reason)); steps.add(step); // Add full-name input @@ -217,8 +217,8 @@ private static void initConsentReviewSteps(Context ctx, ConsentDocument doc, Lis format.setIsMultipleLines(false); String placeholder = ctx.getResources() - .getString(R.string.rsb_consent_name_placeholder); - String nameText = ctx.getResources().getString(R.string.rsb_consent_name_full); + .getString(R.string.rsfc_consent_name_placeholder); + String nameText = ctx.getResources().getString(R.string.rsfc_consent_name_full); formSteps.add(new QuestionStep(ID_FORM_NAME, nameText, format)); } @@ -226,13 +226,13 @@ private static void initConsentReviewSteps(Context ctx, ConsentDocument doc, Lis Calendar maxDate = Calendar.getInstance(); maxDate.add(Calendar.YEAR, -18); DateAnswerFormat dobFormat = new BirthDateAnswerFormat(null, 18, 0); - String dobText = ctx.getResources().getString(R.string.rsb_consent_dob_full); + String dobText = ctx.getResources().getString(R.string.rsfc_consent_dob_full); formSteps.add(new QuestionStep(ID_FORM_DOB, dobText, dobFormat)); } - String formTitle = ctx.getString(R.string.rsb_consent_form_title); + String formTitle = ctx.getString(R.string.rsfc_consent_form_title); FormStep formStep = new FormStep(ID_FORM, formTitle, step.getText()); - formStep.setStepTitle(R.string.rsb_consent); + formStep.setStepTitle(R.string.rsfc_consent); formStep.setOptional(false); formStep.setFormSteps(formSteps); steps.add(formStep); @@ -241,9 +241,9 @@ private static void initConsentReviewSteps(Context ctx, ConsentDocument doc, Lis // Add signature input if (doc.getSignature(0).requiresSignatureImage()) { ConsentSignatureStep signatureStep = new ConsentSignatureStep(ID_SIGNATURE); - signatureStep.setStepTitle(R.string.rsb_consent); - signatureStep.setTitle(ctx.getString(R.string.rsb_consent_signature_title)); - signatureStep.setText(ctx.getString(R.string.rsb_consent_signature_instruction)); + signatureStep.setStepTitle(R.string.rsfc_consent); + signatureStep.setTitle(ctx.getString(R.string.rsfc_consent_signature_title)); + signatureStep.setText(ctx.getString(R.string.rsfc_consent_signature_instruction)); signatureStep.setOptional(false); signatureStep.setSignatureDateFormat(doc.getSignature(0) .getSignatureDateFormatString()); diff --git a/skin/src/main/java/org/researchstack/skin/task/OnboardingTask.java b/skin/src/main/java/org/researchstack/skin/task/OnboardingTask.java index 921f67aaf..49a3c092d 100644 --- a/skin/src/main/java/org/researchstack/skin/task/OnboardingTask.java +++ b/skin/src/main/java/org/researchstack/skin/task/OnboardingTask.java @@ -1,12 +1,12 @@ package org.researchstack.skin.task; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.task.Task; -import org.researchstack.backbone.ui.step.body.NotImplementedStepBody; +import org.researchstack.feature.authentication.pincode.step.PassCodeCreationStep; +import org.researchstack.foundation.components.survey.ui.body.NotImplementedStepBody; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.step.Step; +import org.researchstack.foundation.core.models.task.Task; import org.researchstack.skin.R; -import org.researchstack.skin.step.PassCodeCreationStep; import org.researchstack.skin.ui.layout.PermissionStepLayout; import org.researchstack.skin.ui.layout.SignInStepLayout; import org.researchstack.skin.ui.layout.SignUpEligibleStepLayout; diff --git a/skin/src/main/java/org/researchstack/skin/task/SignInTask.java b/skin/src/main/java/org/researchstack/skin/task/SignInTask.java index 20d1812f5..e238b5929 100644 --- a/skin/src/main/java/org/researchstack/skin/task/SignInTask.java +++ b/skin/src/main/java/org/researchstack/skin/task/SignInTask.java @@ -2,8 +2,8 @@ import android.content.Context; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.Step; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.PermissionRequestManager; import org.researchstack.skin.TaskProvider; diff --git a/skin/src/main/java/org/researchstack/skin/task/SignUpTask.java b/skin/src/main/java/org/researchstack/skin/task/SignUpTask.java index 8a34ea529..bc787e4f1 100644 --- a/skin/src/main/java/org/researchstack/skin/task/SignUpTask.java +++ b/skin/src/main/java/org/researchstack/skin/task/SignUpTask.java @@ -2,8 +2,8 @@ import android.content.Context; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.Step; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.PermissionRequestManager; import org.researchstack.skin.TaskProvider; import org.researchstack.skin.UiManager; diff --git a/skin/src/main/java/org/researchstack/skin/task/SmartSurveyTask.java b/skin/src/main/java/org/researchstack/skin/task/SmartSurveyTask.java index 88896590f..7d8323a0c 100644 --- a/skin/src/main/java/org/researchstack/skin/task/SmartSurveyTask.java +++ b/skin/src/main/java/org/researchstack/skin/task/SmartSurveyTask.java @@ -2,22 +2,22 @@ import android.content.Context; -import org.researchstack.backbone.answerformat.AnswerFormat; -import org.researchstack.backbone.answerformat.BooleanAnswerFormat; -import org.researchstack.backbone.answerformat.ChoiceAnswerFormat; -import org.researchstack.backbone.answerformat.DateAnswerFormat; -import org.researchstack.backbone.answerformat.DecimalAnswerFormat; -import org.researchstack.backbone.answerformat.DurationAnswerFormat; -import org.researchstack.backbone.answerformat.IntegerAnswerFormat; -import org.researchstack.backbone.answerformat.TextAnswerFormat; -import org.researchstack.backbone.answerformat.UnknownAnswerFormat; -import org.researchstack.backbone.model.Choice; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.InstructionStep; -import org.researchstack.backbone.step.QuestionStep; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.task.Task; -import org.researchstack.backbone.utils.LogExt; +import org.researchstack.foundation.components.survey.answerformat.AnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.BooleanAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.ChoiceAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.DateAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.DecimalAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.DurationAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.IntegerAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.TextAnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.UnknownAnswerFormat; +import org.researchstack.foundation.components.survey.model.Choice; +import org.researchstack.foundation.components.survey.step.InstructionStep; +import org.researchstack.foundation.components.survey.step.QuestionStep; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.step.Step; +import org.researchstack.foundation.core.models.task.Task; import org.researchstack.skin.R; import org.researchstack.skin.model.TaskModel; @@ -95,8 +95,8 @@ private AnswerFormat from(Context context, TaskModel.ConstraintsModel constraint AnswerFormat answerFormat; String type = constraints.type; if (type.equals("BooleanConstraints")) { - answerFormat = new BooleanAnswerFormat(context.getString(R.string.rsb_yes), - context.getString(R.string.rsb_no)); + answerFormat = new BooleanAnswerFormat(context.getString(R.string.rsf_yes), + context.getString(R.string.rsf_no)); } else if (type.equals("MultiValueConstraints")) { AnswerFormat.ChoiceAnswerStyle answerStyle = constraints.allowMultiple ? AnswerFormat.ChoiceAnswerStyle.MultipleChoice @@ -215,7 +215,7 @@ public Step getStepWithIdentifier(String identifier) { @Override public String getTitleForStep(Context context, Step step) { int currentIndex = staticStepIdentifiers.indexOf(step.getIdentifier()) + 1; - return context.getString(R.string.rsb_format_step_title, + return context.getString(R.string.rsf_format_step_title, currentIndex, staticStepIdentifiers.size()); } diff --git a/skin/src/main/java/org/researchstack/skin/ui/BaseActivity.java b/skin/src/main/java/org/researchstack/skin/ui/BaseActivity.java index 95b662c3a..23eebeb57 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/BaseActivity.java +++ b/skin/src/main/java/org/researchstack/skin/ui/BaseActivity.java @@ -5,20 +5,20 @@ import android.content.Intent; import android.content.IntentFilter; import android.graphics.Color; -import android.support.design.widget.Snackbar; -import android.support.v4.content.ContextCompat; -import android.support.v4.content.LocalBroadcastManager; +import com.google.android.material.snackbar.Snackbar; +import androidx.core.content.ContextCompat; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import org.researchstack.backbone.StorageAccess; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.task.Task; import org.researchstack.backbone.ui.PinCodeActivity; import org.researchstack.backbone.ui.ViewTaskActivity; -import org.researchstack.backbone.utils.LogExt; import org.researchstack.backbone.utils.ObservableUtils; +import org.researchstack.feature.storage.StorageAccess; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.task.Task; import org.researchstack.skin.AppPrefs; import org.researchstack.skin.DataProvider; import org.researchstack.skin.R; @@ -124,7 +124,7 @@ private TextView getSnackBarMessageView(Snackbar snackbar) { } // Try id for lib level snackbar id - id = android.support.design.R.id.snackbar_text; + id = com.google.android.material.R.id.snackbar_text; tv = (TextView) snackbar.getView().findViewById(id); if (tv != null) { return tv; diff --git a/skin/src/main/java/org/researchstack/skin/ui/ConsentTaskActivity.java b/skin/src/main/java/org/researchstack/skin/ui/ConsentTaskActivity.java index 5d7b5970d..180e1fe39 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/ConsentTaskActivity.java +++ b/skin/src/main/java/org/researchstack/skin/ui/ConsentTaskActivity.java @@ -3,9 +3,9 @@ import android.content.Context; import android.content.Intent; -import org.researchstack.backbone.StorageAccess; -import org.researchstack.backbone.task.Task; import org.researchstack.backbone.ui.ViewTaskActivity; +import org.researchstack.feature.storage.StorageAccess; +import org.researchstack.foundation.core.models.task.Task; public class ConsentTaskActivity extends ViewTaskActivity { public static Intent newIntent(Context context, Task task) { diff --git a/skin/src/main/java/org/researchstack/skin/ui/EmailVerificationActivity.java b/skin/src/main/java/org/researchstack/skin/ui/EmailVerificationActivity.java index de49c50a7..18ce888a2 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/EmailVerificationActivity.java +++ b/skin/src/main/java/org/researchstack/skin/ui/EmailVerificationActivity.java @@ -3,8 +3,8 @@ import android.content.Intent; import android.graphics.Color; import android.os.Bundle; -import android.support.v7.widget.AppCompatTextView; -import android.support.v7.widget.Toolbar; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.appcompat.widget.Toolbar; import android.text.Html; import android.view.MenuItem; import android.view.View; @@ -12,15 +12,15 @@ import com.jakewharton.rxbinding.view.RxView; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.task.OrderedTask; import org.researchstack.backbone.ui.PinCodeActivity; import org.researchstack.backbone.ui.ViewTaskActivity; -import org.researchstack.backbone.ui.views.SubmitBar; import org.researchstack.backbone.utils.ObservableUtils; -import org.researchstack.backbone.utils.ThemeUtils; +import org.researchstack.foundation.components.common.task.OrderedTask; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.foundation.components.utils.ThemeUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.DataProvider; import org.researchstack.skin.R; import org.researchstack.skin.task.OnboardingTask; diff --git a/skin/src/main/java/org/researchstack/skin/ui/LearnActivity.java b/skin/src/main/java/org/researchstack/skin/ui/LearnActivity.java index 47e186804..e32a19e63 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/LearnActivity.java +++ b/skin/src/main/java/org/researchstack/skin/ui/LearnActivity.java @@ -1,7 +1,7 @@ package org.researchstack.skin.ui; import android.os.Bundle; -import android.support.v7.widget.Toolbar; +import androidx.appcompat.widget.Toolbar; import android.view.MenuItem; import org.researchstack.backbone.ui.PinCodeActivity; diff --git a/skin/src/main/java/org/researchstack/skin/ui/MainActivity.java b/skin/src/main/java/org/researchstack/skin/ui/MainActivity.java index 057894633..bcf803202 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/MainActivity.java +++ b/skin/src/main/java/org/researchstack/skin/ui/MainActivity.java @@ -4,20 +4,20 @@ import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; -import android.support.design.widget.TabLayout; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.Toolbar; +import com.google.android.material.tabs.TabLayout; +import androidx.viewpager.widget.ViewPager; +import androidx.appcompat.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; -import org.researchstack.backbone.StorageAccess; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.task.Task; import org.researchstack.backbone.ui.ViewTaskActivity; -import org.researchstack.backbone.ui.views.IconTabLayout; -import org.researchstack.backbone.utils.LogExt; import org.researchstack.backbone.utils.ObservableUtils; -import org.researchstack.backbone.utils.UiThreadContext; +import org.researchstack.feature.storage.StorageAccess; +import org.researchstack.foundation.components.common.ui.views.IconTabLayout; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.components.utils.UiThreadContext; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.task.Task; import org.researchstack.skin.ActionItem; import org.researchstack.skin.DataProvider; import org.researchstack.skin.R; diff --git a/skin/src/main/java/org/researchstack/skin/ui/OnboardingActivity.java b/skin/src/main/java/org/researchstack/skin/ui/OnboardingActivity.java index 9a3a1cda1..62e406c6b 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/OnboardingActivity.java +++ b/skin/src/main/java/org/researchstack/skin/ui/OnboardingActivity.java @@ -4,10 +4,10 @@ import android.animation.ValueAnimator; import android.content.Intent; import android.os.Bundle; -import android.support.design.widget.TabLayout; -import android.support.v4.content.ContextCompat; -import android.support.v4.view.ViewPager; -import android.support.v7.widget.AppCompatButton; +import com.google.android.material.tabs.TabLayout; +import androidx.core.content.ContextCompat; +import androidx.viewpager.widget.ViewPager; +import androidx.appcompat.widget.AppCompatButton; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; @@ -15,20 +15,20 @@ import android.widget.LinearLayout; import android.widget.TextView; -import org.researchstack.backbone.StorageAccess; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.task.OrderedTask; import org.researchstack.backbone.ui.PinCodeActivity; import org.researchstack.backbone.ui.ViewTaskActivity; -import org.researchstack.backbone.utils.ResUtils; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.feature.authentication.pincode.step.PassCodeCreationStep; +import org.researchstack.feature.storage.StorageAccess; +import org.researchstack.foundation.components.common.task.OrderedTask; +import org.researchstack.foundation.components.utils.ResUtils; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.core.models.result.TaskResult; import org.researchstack.skin.AppPrefs; import org.researchstack.skin.R; import org.researchstack.skin.ResourceManager; import org.researchstack.skin.TaskProvider; import org.researchstack.skin.UiManager; import org.researchstack.skin.model.StudyOverviewModel; -import org.researchstack.skin.step.PassCodeCreationStep; import org.researchstack.skin.task.OnboardingTask; import org.researchstack.skin.task.SignInTask; import org.researchstack.skin.task.SignUpTask; diff --git a/skin/src/main/java/org/researchstack/skin/ui/SettingsActivity.java b/skin/src/main/java/org/researchstack/skin/ui/SettingsActivity.java index 5615f0d10..15a34a964 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/SettingsActivity.java +++ b/skin/src/main/java/org/researchstack/skin/ui/SettingsActivity.java @@ -1,7 +1,7 @@ package org.researchstack.skin.ui; import android.os.Bundle; -import android.support.v7.widget.Toolbar; +import androidx.appcompat.widget.Toolbar; import android.view.MenuItem; import org.researchstack.skin.R; diff --git a/skin/src/main/java/org/researchstack/skin/ui/SignUpTaskActivity.java b/skin/src/main/java/org/researchstack/skin/ui/SignUpTaskActivity.java index 65e21d03c..584ca4084 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/SignUpTaskActivity.java +++ b/skin/src/main/java/org/researchstack/skin/ui/SignUpTaskActivity.java @@ -6,16 +6,19 @@ import android.content.Intent; import android.os.Build; -import org.researchstack.backbone.StorageAccess; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.task.Task; +import org.jetbrains.annotations.Nullable; import org.researchstack.backbone.ui.ViewTaskActivity; import org.researchstack.backbone.ui.callbacks.ActivityCallback; -import org.researchstack.backbone.ui.step.layout.StepLayout; import org.researchstack.backbone.ui.step.layout.StepPermissionRequest; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.feature.storage.StorageAccess; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.core.interfaces.IResult; +import org.researchstack.foundation.core.interfaces.IStep; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.step.Step; +import org.researchstack.foundation.core.models.task.Task; import org.researchstack.skin.DataProvider; import org.researchstack.skin.PermissionRequestManager; import org.researchstack.skin.R; @@ -44,20 +47,24 @@ public void onDataAuth() { } @Override - public void onSaveStep(int action, Step step, StepResult result) { - // Save result to task - onSaveStepResult(step.getIdentifier(), result); - - // Save Pin to disk, then save our consent info - if (action == ACTION_NEXT && - step.getIdentifier().equals(OnboardingTask.SignUpPassCodeCreationStepIdentifier)) { - String pin = (String) result.getResult(); - if (!TextUtils.isEmpty(pin)) { - StorageAccess.getInstance().createPinCode(this, pin); - } + public void onSaveStep(int action, IStep step, @Nullable IResult result) { + + if (result instanceof StepResult) { + StepResult stepResult = (StepResult) result; + // Save result to task + onSaveStepResult(step.getIdentifier(), stepResult); + + // Save Pin to disk, then save our consent info + if (action == ACTION_NEXT && + step.getIdentifier().equals(OnboardingTask.SignUpPassCodeCreationStepIdentifier)) { + String pin = (String) stepResult.getResult(); + if (!TextUtils.isEmpty(pin)) { + StorageAccess.getInstance().createPinCode(this, pin); + } - if (consentResult != null) { - saveConsentResultInfo(); + if (consentResult != null) { + saveConsentResultInfo(); + } } } diff --git a/skin/src/main/java/org/researchstack/skin/ui/SplashActivity.java b/skin/src/main/java/org/researchstack/skin/ui/SplashActivity.java index 9098f1bbe..94cdc8b6e 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/SplashActivity.java +++ b/skin/src/main/java/org/researchstack/skin/ui/SplashActivity.java @@ -3,9 +3,9 @@ import android.content.Intent; import android.os.Bundle; -import org.researchstack.backbone.StorageAccess; import org.researchstack.backbone.ui.PinCodeActivity; import org.researchstack.backbone.utils.ObservableUtils; +import org.researchstack.feature.storage.StorageAccess; import org.researchstack.skin.AppPrefs; import org.researchstack.skin.DataProvider; import org.researchstack.skin.notification.TaskAlertReceiver; diff --git a/skin/src/main/java/org/researchstack/skin/ui/adapter/MainPagerAdapter.java b/skin/src/main/java/org/researchstack/skin/ui/adapter/MainPagerAdapter.java index 852cfc026..11e1e5481 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/adapter/MainPagerAdapter.java +++ b/skin/src/main/java/org/researchstack/skin/ui/adapter/MainPagerAdapter.java @@ -1,10 +1,10 @@ package org.researchstack.skin.ui.adapter; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentPagerAdapter; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; -import org.researchstack.backbone.utils.ViewUtils; +import org.researchstack.foundation.components.utils.ViewUtils; import org.researchstack.skin.ActionItem; import java.util.List; diff --git a/skin/src/main/java/org/researchstack/skin/ui/adapter/OnboardingPagerAdapter.java b/skin/src/main/java/org/researchstack/skin/ui/adapter/OnboardingPagerAdapter.java index e877604d0..7ea337053 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/adapter/OnboardingPagerAdapter.java +++ b/skin/src/main/java/org/researchstack/skin/ui/adapter/OnboardingPagerAdapter.java @@ -2,16 +2,16 @@ import android.content.Context; import android.content.Intent; -import android.support.v4.view.PagerAdapter; +import androidx.viewpager.widget.PagerAdapter; import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import org.researchstack.backbone.ui.ViewVideoActivity; -import org.researchstack.backbone.ui.views.LocalWebView; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.components.web.ui.activities.ViewVideoActivity; +import org.researchstack.foundation.components.web.ui.views.LocalWebView; import org.researchstack.skin.R; import org.researchstack.skin.ResourceManager; import org.researchstack.skin.model.StudyOverviewModel; diff --git a/skin/src/main/java/org/researchstack/skin/ui/fragment/ActivitiesFragment.java b/skin/src/main/java/org/researchstack/skin/ui/fragment/ActivitiesFragment.java index 1732c9ad1..cd36cc1d6 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/fragment/ActivitiesFragment.java +++ b/skin/src/main/java/org/researchstack/skin/ui/fragment/ActivitiesFragment.java @@ -5,12 +5,12 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v4.graphics.drawable.DrawableCompat; -import android.support.v7.widget.AppCompatTextView; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.core.graphics.drawable.DrawableCompat; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import android.text.Html; import android.view.LayoutInflater; import android.view.View; @@ -18,13 +18,13 @@ import android.widget.ImageView; import android.widget.Toast; -import org.researchstack.backbone.StorageAccess; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.storage.file.StorageAccessListener; -import org.researchstack.backbone.task.Task; import org.researchstack.backbone.ui.ViewTaskActivity; -import org.researchstack.backbone.utils.LogExt; import org.researchstack.backbone.utils.ObservableUtils; +import org.researchstack.feature.storage.StorageAccess; +import org.researchstack.feature.storage.file.StorageAccessListener; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.task.Task; import org.researchstack.skin.DataProvider; import org.researchstack.skin.R; import org.researchstack.skin.model.SchedulesAndTasksModel; diff --git a/skin/src/main/java/org/researchstack/skin/ui/fragment/LearnFragment.java b/skin/src/main/java/org/researchstack/skin/ui/fragment/LearnFragment.java index 0e78c7d5b..e12bc3f5c 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/fragment/LearnFragment.java +++ b/skin/src/main/java/org/researchstack/skin/ui/fragment/LearnFragment.java @@ -3,17 +3,17 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v7.widget.AppCompatTextView; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import org.researchstack.backbone.ui.ViewWebDocumentActivity; +import org.researchstack.foundation.components.web.ui.activities.ViewWebDocumentActivity; import org.researchstack.skin.R; import org.researchstack.skin.ResourceManager; import org.researchstack.skin.model.SectionModel; @@ -63,7 +63,7 @@ public LearnAdapter(Context context, SectionModel sections) { @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_HEADER) { - View view = inflater.inflate(R.layout.preference_category_material, parent, false); + View view = inflater.inflate(R.layout.rss_item_section_learn, parent, false); return new HeaderViewHolder(view); } else { View view = inflater.inflate(R.layout.rss_item_row_learn, parent, false); @@ -114,7 +114,7 @@ public static class HeaderViewHolder extends RecyclerView.ViewHolder { public HeaderViewHolder(View itemView) { super(itemView); - title = (TextView) itemView; + title = (AppCompatTextView) itemView.findViewById(R.id.learn_item_title); } } diff --git a/skin/src/main/java/org/researchstack/skin/ui/fragment/SettingsFragment.java b/skin/src/main/java/org/researchstack/skin/ui/fragment/SettingsFragment.java index 2ee0e0482..4cbddce0c 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/fragment/SettingsFragment.java +++ b/skin/src/main/java/org/researchstack/skin/ui/fragment/SettingsFragment.java @@ -6,41 +6,41 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Bundle; -import android.support.v7.app.AlertDialog; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceCategory; -import android.support.v7.preference.PreferenceFragmentCompat; -import android.support.v7.preference.PreferenceScreen; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.Toast; -import org.researchstack.backbone.StorageAccess; -import org.researchstack.backbone.answerformat.AnswerFormat; -import org.researchstack.backbone.answerformat.ChoiceAnswerFormat; -import org.researchstack.backbone.model.Choice; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.step.ConsentSharingStep; -import org.researchstack.backbone.storage.file.StorageAccessListener; -import org.researchstack.backbone.task.OrderedTask; -import org.researchstack.backbone.task.Task; import org.researchstack.backbone.ui.ViewTaskActivity; -import org.researchstack.backbone.ui.ViewWebDocumentActivity; -import org.researchstack.backbone.utils.FormatHelper; -import org.researchstack.backbone.utils.LogExt; import org.researchstack.backbone.utils.ObservableUtils; +import org.researchstack.feature.authentication.pincode.step.PassCodeCreationStep; +import org.researchstack.feature.authentication.pincode.ui.SignUpPinCodeCreationStepLayout; +import org.researchstack.feature.consent.step.ConsentSharingStep; +import org.researchstack.feature.storage.StorageAccess; +import org.researchstack.feature.storage.file.StorageAccessListener; +import org.researchstack.foundation.components.common.task.OrderedTask; +import org.researchstack.foundation.components.survey.answerformat.AnswerFormat; +import org.researchstack.foundation.components.survey.answerformat.ChoiceAnswerFormat; +import org.researchstack.foundation.components.survey.model.Choice; +import org.researchstack.foundation.components.utils.FormatHelper; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.components.web.ui.activities.ViewWebDocumentActivity; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.foundation.core.models.task.Task; import org.researchstack.skin.AppPrefs; import org.researchstack.skin.DataProvider; import org.researchstack.skin.R; import org.researchstack.skin.ResourceManager; import org.researchstack.skin.model.ConsentSectionModel; import org.researchstack.skin.notification.TaskAlertReceiver; -import org.researchstack.skin.step.PassCodeCreationStep; import org.researchstack.skin.task.ConsentTask; import org.researchstack.skin.ui.OnboardingActivity; -import org.researchstack.skin.ui.layout.SignUpPinCodeCreationStepLayout; import org.researchstack.skin.utils.ConsentFormUtils; import java.text.DateFormat; @@ -203,7 +203,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa ViewGroup v = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState); settingsRoot.addView(v); - progress = inflater.inflate(R.layout.rsb_progress, container, false); + progress = inflater.inflate(R.layout.rsf_progress, container, false); progress.setVisibility(View.GONE); settingsRoot.addView(progress); @@ -251,13 +251,13 @@ public boolean onPreferenceTreeClick(Preference preference) { sharingStep.setOptional(false); sharingStep.setStepTitle(R.string.rss_settings_privacy_sharing_options); - String shareWidely = getString(R.string.rsb_consent_share_widely, + String shareWidely = getString(R.string.rsfc_consent_share_widely, investigatorLongDesc); Choice shareWidelyChoice = new Choice<>(shareWidely, "sponsors_and_partners", null); - String shareRestricted = getString(R.string.rsb_consent_share_only, + String shareRestricted = getString(R.string.rsfc_consent_share_only, investigatorShortDesc); Choice shareRestrictedChoice = new Choice<>(shareRestricted, "all_qualified_researchers", @@ -267,8 +267,8 @@ public boolean onPreferenceTreeClick(Preference preference) { shareWidelyChoice, shareRestrictedChoice)); - sharingStep.setTitle(getString(R.string.rsb_consent_share_title)); - sharingStep.setText(getString(R.string.rsb_consent_share_description, + sharingStep.setTitle(getString(R.string.rsfc_consent_share_title)); + sharingStep.setText(getString(R.string.rsfc_consent_share_description, investigatorLongDesc, localizedLearnMoreHTMLContent)); @@ -308,7 +308,7 @@ public boolean onPreferenceTreeClick(Preference preference) { progress.setVisibility(View.GONE); }); }) - .setNegativeButton(R.string.rsb_cancel, null) + .setNegativeButton(R.string.rsf_cancel, null) .show(); return true; @@ -387,14 +387,14 @@ public String formatSharingOption(String option) { String investigatorLongDesc = data.getDocumentProperties() .getInvestigatorLongDescription(); - return getString(R.string.rsb_consent_share_widely, investigatorLongDesc); + return getString(R.string.rsfc_consent_share_widely, investigatorLongDesc); } else if (option.equals("all_qualified_researchers")) { String investigatorShortDesc = data.getDocumentProperties() .getInvestigatorShortDescription(); - return getString(R.string.rsb_consent_share_only, investigatorShortDesc); + return getString(R.string.rsfc_consent_share_only, investigatorShortDesc); } else if (option.equals("no_sharing")) { - return getString(R.string.rsb_consent_share_no); + return getString(R.string.rsfc_consent_share_no); } else { // If you want to add another sharing option, feel free, you just need to override this // method in your SettingsFragment diff --git a/skin/src/main/java/org/researchstack/skin/ui/layout/ConsentQuizEvaluationStepLayout.java b/skin/src/main/java/org/researchstack/skin/ui/layout/ConsentQuizEvaluationStepLayout.java index f101095b4..b3348dee9 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/layout/ConsentQuizEvaluationStepLayout.java +++ b/skin/src/main/java/org/researchstack/skin/ui/layout/ConsentQuizEvaluationStepLayout.java @@ -6,13 +6,13 @@ import android.widget.ImageView; import android.widget.TextView; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.step.layout.StepLayout; -import org.researchstack.backbone.ui.views.FixedSubmitBarLayout; -import org.researchstack.backbone.ui.views.SubmitBar; -import org.researchstack.backbone.utils.ResUtils; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.FixedSubmitBarLayout; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.foundation.components.utils.ResUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.R; import org.researchstack.skin.step.ConsentQuizEvaluationStep; @@ -52,7 +52,7 @@ private void initializeStep() { TextView title = (TextView) findViewById(R.id.rss_quiz_eval_title); TextView summary = (TextView) findViewById(R.id.rss_quiz_eval_summary); - SubmitBar submitBar = (SubmitBar) findViewById(R.id.rsb_submit_bar); + SubmitBar submitBar = (SubmitBar) findViewById(R.id.rsf_submit_bar); submitBar.getNegativeActionView().setVisibility(View.GONE); submitBar.setPositiveAction(v -> callbacks.onSaveStep(StepCallbacks.ACTION_NEXT, step, @@ -64,14 +64,14 @@ private void initializeStep() { step.getQuizModel().getIncorrectIcon()); image.setImageResource(iconResId); - title.setText(R.string.rsb_quiz_evaluation_try_again); + title.setText(R.string.rsfc_quiz_evaluation_try_again); if (!step.isOverMaxAttempts()) { summary.setText(step.getQuizModel().getFailureMessage()); - submitBar.setPositiveTitle(R.string.rsb_quiz_evaluation_retake); + submitBar.setPositiveTitle(R.string.rsfc_quiz_evaluation_retake); } else { summary.setText(step.getQuizModel().getFailureMessage()); - submitBar.setPositiveTitle(R.string.rsb_quiz_evaluation_review_consent); + submitBar.setPositiveTitle(R.string.rsfc_quiz_evaluation_review_consent); } } @@ -81,7 +81,7 @@ private void initializeStep() { step.getQuizModel().getCorrectIcon()); image.setImageResource(iconResId); - title.setText(R.string.rsb_quiz_evaluation_great_job); + title.setText(R.string.rsfc_quiz_evaluation_great_job); if (step.getIncorrect() == 0) { summary.setText(step.getQuizModel().getSuccessMessage()); @@ -89,7 +89,7 @@ private void initializeStep() { summary.setText(step.getQuizModel().getSuccessMessage()); } - submitBar.setPositiveTitle(R.string.rsb_next); + submitBar.setPositiveTitle(R.string.rsf_next); } } diff --git a/skin/src/main/java/org/researchstack/skin/ui/layout/ConsentQuizQuestionStepLayout.java b/skin/src/main/java/org/researchstack/skin/ui/layout/ConsentQuizQuestionStepLayout.java index 48d3831b0..7e9fa0bd0 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/layout/ConsentQuizQuestionStepLayout.java +++ b/skin/src/main/java/org/researchstack/skin/ui/layout/ConsentQuizQuestionStepLayout.java @@ -3,10 +3,10 @@ import android.content.Context; import android.graphics.Color; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; -import android.support.v4.graphics.drawable.DrawableCompat; -import android.support.v7.widget.AppCompatRadioButton; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; +import androidx.appcompat.widget.AppCompatRadioButton; import android.text.Html; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -18,12 +18,12 @@ import android.widget.TextView; import android.widget.Toast; -import org.researchstack.backbone.model.Choice; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.step.layout.StepLayout; -import org.researchstack.backbone.ui.views.SubmitBar; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.foundation.components.survey.model.Choice; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.R; import org.researchstack.skin.model.ConsentQuizModel; import org.researchstack.skin.step.ConsentQuizQuestionStep; @@ -88,10 +88,10 @@ public void initializeStep() { instructionText.setVisibility(VISIBLE); // instruction steps don't need submit, also always count as correct answer - submitBar.setPositiveTitle(R.string.rsb_next); + submitBar.setPositiveTitle(R.string.rsf_next); submitBar.setPositiveAction(v -> onNext(true)); } else { - submitBar.setPositiveTitle(R.string.rsb_submit); + submitBar.setPositiveTitle(R.string.rsf_submit); submitBar.setPositiveAction(v -> onSubmit()); for (Choice choice : getChoices(question)) { @@ -148,7 +148,7 @@ public void onSubmit() { } // Set the drawable of the current checked button, with correct color tint - int resId = answerCorrect ? R.drawable.rsb_ic_check : R.drawable.rsb_ic_x; + int resId = answerCorrect ? R.drawable.rsf_ic_check : R.drawable.rsf_ic_x; Drawable drawable = ContextCompat.getDrawable(getContext(), resId); drawable = DrawableCompat.wrap(drawable); DrawableCompat.setTint(drawable, resultTextColor); @@ -211,7 +211,7 @@ private void onNext(boolean answerCorrect) { private void setSubmitBarNext() { // Change the submit bar positive-title to "next" - submitBar.setPositiveTitle(R.string.rsb_next); + submitBar.setPositiveTitle(R.string.rsf_next); } public boolean isAnswerValid() { diff --git a/skin/src/main/java/org/researchstack/skin/ui/layout/PermissionStepLayout.java b/skin/src/main/java/org/researchstack/skin/ui/layout/PermissionStepLayout.java index 5a50e09ab..673f9cc8c 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/layout/PermissionStepLayout.java +++ b/skin/src/main/java/org/researchstack/skin/ui/layout/PermissionStepLayout.java @@ -2,8 +2,8 @@ import android.content.Context; import android.graphics.drawable.Drawable; -import android.support.v4.content.ContextCompat; -import android.support.v4.graphics.drawable.DrawableCompat; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -14,14 +14,14 @@ import com.jakewharton.rxbinding.view.RxView; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; import org.researchstack.backbone.ui.callbacks.ActivityCallback; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.step.layout.StepLayout; import org.researchstack.backbone.ui.step.layout.StepPermissionRequest; -import org.researchstack.backbone.ui.views.SubmitBar; -import org.researchstack.backbone.utils.ThemeUtils; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.foundation.components.utils.ThemeUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.PermissionRequestManager; import org.researchstack.skin.R; @@ -122,7 +122,7 @@ public void initializeStep() { // Set submit bar behavior submitBar = (SubmitBar) findViewById(R.id.submit_bar); - submitBar.setPositiveTitle(R.string.rsb_next); + submitBar.setPositiveTitle(R.string.rsf_next); submitBar.setPositiveAction(v -> { if (isAnswerValid()) { onNext(true); diff --git a/skin/src/main/java/org/researchstack/skin/ui/layout/SignInStepLayout.java b/skin/src/main/java/org/researchstack/skin/ui/layout/SignInStepLayout.java index d76dcae2d..21565c86d 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/layout/SignInStepLayout.java +++ b/skin/src/main/java/org/researchstack/skin/ui/layout/SignInStepLayout.java @@ -1,7 +1,7 @@ package org.researchstack.skin.ui.layout; import android.content.Context; -import android.support.v7.widget.AppCompatEditText; +import androidx.appcompat.widget.AppCompatEditText; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -13,13 +13,13 @@ import com.jakewharton.rxbinding.view.RxView; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.step.layout.StepLayout; -import org.researchstack.backbone.ui.views.SubmitBar; import org.researchstack.backbone.utils.ObservableUtils; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.DataProvider; import org.researchstack.skin.R; import org.researchstack.skin.task.SignInTask; diff --git a/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpEligibleStepLayout.java b/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpEligibleStepLayout.java index 80dd361df..1a5bd70c6 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpEligibleStepLayout.java +++ b/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpEligibleStepLayout.java @@ -6,12 +6,12 @@ import android.view.View; import android.widget.RelativeLayout; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; import org.researchstack.backbone.ui.callbacks.ActivityCallback; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.step.layout.StepLayout; -import org.researchstack.backbone.ui.views.SubmitBar; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.R; public class SignUpEligibleStepLayout extends RelativeLayout implements StepLayout { diff --git a/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpIneligibleStepLayout.java b/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpIneligibleStepLayout.java index 0abb6bc18..0de3a462d 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpIneligibleStepLayout.java +++ b/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpIneligibleStepLayout.java @@ -6,10 +6,10 @@ import android.view.View; import android.widget.LinearLayout; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.step.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.R; public class SignUpIneligibleStepLayout extends LinearLayout implements StepLayout { diff --git a/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpStepLayout.java b/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpStepLayout.java index b2e23c00a..cc217bc71 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpStepLayout.java +++ b/skin/src/main/java/org/researchstack/skin/ui/layout/SignUpStepLayout.java @@ -1,7 +1,7 @@ package org.researchstack.skin.ui.layout; import android.content.Context; -import android.support.v7.widget.AppCompatEditText; +import androidx.appcompat.widget.AppCompatEditText; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -10,13 +10,13 @@ import android.widget.RelativeLayout; import android.widget.Toast; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.ui.callbacks.StepCallbacks; -import org.researchstack.backbone.ui.step.layout.StepLayout; -import org.researchstack.backbone.ui.views.SubmitBar; import org.researchstack.backbone.utils.ObservableUtils; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.foundation.components.common.ui.callbacks.StepCallbacks; +import org.researchstack.foundation.components.common.ui.layout.StepLayout; +import org.researchstack.foundation.components.common.ui.views.SubmitBar; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import org.researchstack.skin.DataProvider; import org.researchstack.skin.R; import org.researchstack.skin.task.SignUpTask; diff --git a/skin/src/main/java/org/researchstack/skin/ui/preference/TextColorPreference.java b/skin/src/main/java/org/researchstack/skin/ui/preference/TextColorPreference.java index 8f92609f1..d4be03ab6 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/preference/TextColorPreference.java +++ b/skin/src/main/java/org/researchstack/skin/ui/preference/TextColorPreference.java @@ -3,8 +3,8 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceViewHolder; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; import android.util.AttributeSet; import android.widget.TextView; diff --git a/skin/src/main/java/org/researchstack/skin/ui/views/DividerItemDecoration.java b/skin/src/main/java/org/researchstack/skin/ui/views/DividerItemDecoration.java index 63afc476f..3b88bd93b 100644 --- a/skin/src/main/java/org/researchstack/skin/ui/views/DividerItemDecoration.java +++ b/skin/src/main/java/org/researchstack/skin/ui/views/DividerItemDecoration.java @@ -21,9 +21,9 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.support.v4.view.ViewCompat; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; +import androidx.core.view.ViewCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import android.view.View; public class DividerItemDecoration extends RecyclerView.ItemDecoration { diff --git a/skin/src/main/java/org/researchstack/skin/utils/ConsentFormUtils.java b/skin/src/main/java/org/researchstack/skin/utils/ConsentFormUtils.java index b35056223..c5b6d6a71 100644 --- a/skin/src/main/java/org/researchstack/skin/utils/ConsentFormUtils.java +++ b/skin/src/main/java/org/researchstack/skin/utils/ConsentFormUtils.java @@ -4,12 +4,12 @@ import android.content.Intent; import android.net.Uri; import android.os.Environment; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; -import org.researchstack.backbone.ui.ViewWebDocumentActivity; -import org.researchstack.backbone.utils.LogExt; import org.researchstack.backbone.utils.ObservableUtils; -import org.researchstack.backbone.utils.ResUtils; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.components.utils.ResUtils; +import org.researchstack.foundation.components.web.ui.activities.ViewWebDocumentActivity; import org.researchstack.skin.R; import org.researchstack.skin.ResourceManager; @@ -27,7 +27,7 @@ private ConsentFormUtils() { public static void viewConsentForm(Context context) { String path = ResourceManager.getInstance().getConsentHtml().getAbsolutePath(); - String title = context.getString(R.string.rsb_consent); + String title = context.getString(R.string.rsfc_consent); Intent intent = ViewWebDocumentActivity.newIntentForPath(context, title, path); context.startActivity(intent); } diff --git a/skin/src/main/res/drawable/rss_ic_circle_16dp.xml b/skin/src/main/res/drawable/rss_ic_circle_16dp.xml index 5120fea77..c160d9398 100644 --- a/skin/src/main/res/drawable/rss_ic_circle_16dp.xml +++ b/skin/src/main/res/drawable/rss_ic_circle_16dp.xml @@ -6,6 +6,6 @@ android:width="16dp" android:height="16dp" /> - + \ No newline at end of file diff --git a/skin/src/main/res/drawable/rss_text_color_accent.xml b/skin/src/main/res/drawable/rss_text_color_accent.xml index b9647e761..ffb387b7c 100644 --- a/skin/src/main/res/drawable/rss_text_color_accent.xml +++ b/skin/src/main/res/drawable/rss_text_color_accent.xml @@ -1,6 +1,6 @@ - - + + \ No newline at end of file diff --git a/skin/src/main/res/layout-v16/rss_item_row_learn.xml b/skin/src/main/res/layout-v16/rss_item_row_learn.xml index cceb649f1..05d674717 100644 --- a/skin/src/main/res/layout-v16/rss_item_row_learn.xml +++ b/skin/src/main/res/layout-v16/rss_item_row_learn.xml @@ -1,5 +1,5 @@ - - - diff --git a/skin/src/main/res/layout/rss_activity_email_verification.xml b/skin/src/main/res/layout/rss_activity_email_verification.xml index 7df7401e5..32def5430 100644 --- a/skin/src/main/res/layout/rss_activity_email_verification.xml +++ b/skin/src/main/res/layout/rss_activity_email_verification.xml @@ -5,40 +5,40 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + - - - @@ -114,7 +114,7 @@ android:layout_height="1dp" android:layout_marginBottom="12dp" android:layout_marginTop="12dp" - android:background="@color/rsb_black" + android:background="@color/rsf_black" /> @@ -136,10 +136,10 @@ --> \ No newline at end of file diff --git a/skin/src/main/res/layout/rss_activity_fragment.xml b/skin/src/main/res/layout/rss_activity_fragment.xml index 6e2f6f6d4..892998af6 100644 --- a/skin/src/main/res/layout/rss_activity_fragment.xml +++ b/skin/src/main/res/layout/rss_activity_fragment.xml @@ -4,7 +4,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - + - + android:background="@color/rsf_submit_bar_gray" /> - - - - + - - - - diff --git a/skin/src/main/res/layout/rss_fragment_activities.xml b/skin/src/main/res/layout/rss_fragment_activities.xml index c9609588b..31e00c4db 100644 --- a/skin/src/main/res/layout/rss_fragment_activities.xml +++ b/skin/src/main/res/layout/rss_fragment_activities.xml @@ -1,5 +1,5 @@ - - - - - - @@ -48,7 +48,7 @@ - - \ No newline at end of file diff --git a/skin/src/main/res/layout/rss_item_permission_card.xml b/skin/src/main/res/layout/rss_item_permission_card.xml index 6b3a111c0..cc578ae9a 100644 --- a/skin/src/main/res/layout/rss_item_permission_card.xml +++ b/skin/src/main/res/layout/rss_item_permission_card.xml @@ -1,9 +1,9 @@ - - + diff --git a/skin/src/main/res/layout/rss_item_permission_content.xml b/skin/src/main/res/layout/rss_item_permission_content.xml index eed09e395..236b06bf4 100644 --- a/skin/src/main/res/layout/rss_item_permission_content.xml +++ b/skin/src/main/res/layout/rss_item_permission_content.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - - - - - diff --git a/skin/src/main/res/layout/rss_item_row_learn.xml b/skin/src/main/res/layout/rss_item_row_learn.xml index 37e6bb521..cb5ca1ed2 100644 --- a/skin/src/main/res/layout/rss_item_row_learn.xml +++ b/skin/src/main/res/layout/rss_item_row_learn.xml @@ -1,5 +1,5 @@ - - - \ No newline at end of file diff --git a/skin/src/main/res/layout/rss_item_section_learn.xml b/skin/src/main/res/layout/rss_item_section_learn.xml new file mode 100644 index 000000000..c3dd63eed --- /dev/null +++ b/skin/src/main/res/layout/rss_item_section_learn.xml @@ -0,0 +1,16 @@ + + \ No newline at end of file diff --git a/skin/src/main/res/layout/rss_layout_consent_evaluation.xml b/skin/src/main/res/layout/rss_layout_consent_evaluation.xml index f37baf4ba..32cc6b59a 100644 --- a/skin/src/main/res/layout/rss_layout_consent_evaluation.xml +++ b/skin/src/main/res/layout/rss_layout_consent_evaluation.xml @@ -10,15 +10,15 @@ android:layout_height="180dp" android:layout_centerHorizontal="true" android:scaleType="center" - tools:src="@drawable/rsb_debug_gray" /> + tools:src="@drawable/rsf_debug_gray" /> diff --git a/skin/src/main/res/layout/rss_layout_eligible.xml b/skin/src/main/res/layout/rss_layout_eligible.xml index 0e85ebbaf..5914f2424 100644 --- a/skin/src/main/res/layout/rss_layout_eligible.xml +++ b/skin/src/main/res/layout/rss_layout_eligible.xml @@ -26,7 +26,7 @@ android:layout_marginTop="24dp" android:text="@string/rss_eligibility_tap_below" /> - @@ -34,11 +34,11 @@ - + app:negativeActionTitle="@string/rsf_exit" + app:positiveActionTitle="@string/rsf_submit" /> \ No newline at end of file diff --git a/skin/src/main/res/layout/rss_layout_quiz_question.xml b/skin/src/main/res/layout/rss_layout_quiz_question.xml index 777e6649f..cdb8648b3 100644 --- a/skin/src/main/res/layout/rss_layout_quiz_question.xml +++ b/skin/src/main/res/layout/rss_layout_quiz_question.xml @@ -12,7 +12,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="0dp" - android:paddingBottom="@dimen/rsb_padding_wedge" + android:paddingBottom="@dimen/rsf_padding_wedge" android:text="@string/rss_quiz_question_disclamer" android:visibility="visible" /> @@ -38,8 +38,8 @@ style="@style/Backbone.Survey.Title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingBottom="@dimen/rsb_padding_wedge" - android:paddingTop="@dimen/rsb_padding_wedge" + android:paddingBottom="@dimen/rsf_padding_wedge" + android:paddingTop="@dimen/rsf_padding_wedge" tools:text="@string/lorem_short" /> @@ -59,7 +59,7 @@ android:layout_height="wrap_content" android:layout_alignTop="@+id/radio_group" android:background="@android:color/holo_red_light" - android:minHeight="@dimen/rsb_item_size_default" + android:minHeight="@dimen/rsf_item_size_default" android:visibility="gone" /> @@ -88,8 +88,8 @@ android:layout_height="wrap_content" android:layout_below="@+id/quiz_result_title" android:layout_marginTop="0dp" - android:paddingBottom="@dimen/rsb_padding_medium" - android:paddingTop="@dimen/rsb_padding_small" + android:paddingBottom="@dimen/rsf_padding_medium" + android:paddingTop="@dimen/rsf_padding_small" android:text="@string/lorem_long" android:visibility="gone" tools:visibility="visible" /> @@ -98,12 +98,12 @@ - diff --git a/skin/src/main/res/layout/rss_layout_sign_in.xml b/skin/src/main/res/layout/rss_layout_sign_in.xml index 411a18c50..cdcb48499 100644 --- a/skin/src/main/res/layout/rss_layout_sign_in.xml +++ b/skin/src/main/res/layout/rss_layout_sign_in.xml @@ -19,24 +19,24 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/title" - android:layout_marginLeft="@dimen/rsb_margin_left" - android:layout_marginRight="@dimen/rsb_margin_right" - android:layout_marginTop="@dimen/rsb_padding_wedge" + android:layout_marginLeft="@dimen/rsf_margin_left" + android:layout_marginRight="@dimen/rsf_margin_right" + android:layout_marginTop="@dimen/rsf_padding_wedge" android:stretchColumns="1"> + android:minHeight="@dimen/rsf_item_size_default"> - - + android:minHeight="@dimen/rsf_item_size_default"> - - - + app:negativeActionTitle="@string/rsf_exit" + app:positiveActionTitle="@string/rsf_submit" /> - + android:textColor="@color/rsf_submit_bar_negative" /> diff --git a/skin/src/main/res/layout/rss_layout_sign_up.xml b/skin/src/main/res/layout/rss_layout_sign_up.xml index 99dfdc745..0d8bcb033 100644 --- a/skin/src/main/res/layout/rss_layout_sign_up.xml +++ b/skin/src/main/res/layout/rss_layout_sign_up.xml @@ -30,23 +30,23 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/text" - android:layout_marginLeft="@dimen/rsb_margin_left" - android:layout_marginRight="@dimen/rsb_margin_right" + android:layout_marginLeft="@dimen/rsf_margin_left" + android:layout_marginRight="@dimen/rsf_margin_right" android:stretchColumns="1"> + android:minHeight="@dimen/rsf_item_size_default"> - + android:text="@string/rsf_email" /> - + android:minHeight="@dimen/rsf_item_size_default"> - - - + app:negativeActionTitle="@string/rsf_exit" + app:positiveActionTitle="@string/rsf_submit" /> diff --git a/skin/src/main/res/layout/rss_layout_toolbar_tabs.xml b/skin/src/main/res/layout/rss_layout_toolbar_tabs.xml index c8a83b5dc..9c05019b8 100644 --- a/skin/src/main/res/layout/rss_layout_toolbar_tabs.xml +++ b/skin/src/main/res/layout/rss_layout_toolbar_tabs.xml @@ -6,13 +6,13 @@ android:foreground="?android:attr/windowContentOverlay" android:orientation="vertical"> - - diff --git a/skin/src/main/res/values/strings.xml b/skin/src/main/res/values/strings.xml index d413d21b5..b1a1b6465 100644 --- a/skin/src/main/res/values/strings.xml +++ b/skin/src/main/res/values/strings.xml @@ -113,7 +113,7 @@ Software Notices Leave Study Join Study - Build number %1$s (%2$s) + Build number %1$s (%2$d) Unknown version Are you sure you want to leave the study? This action cannot be undone and you will need to provide consent in order to re-enroll. diff --git a/skin/src/main/res/xml/rss_settings.xml b/skin/src/main/res/xml/rss_settings.xml index 6f4dc5fce..e679e6700 100644 --- a/skin/src/main/res/xml/rss_settings.xml +++ b/skin/src/main/res/xml/rss_settings.xml @@ -88,7 +88,7 @@ android:key="rss_settings_general_leave_study" android:order="2" android:title="@string/rss_settings_general_leave_study" - app:preferenceTextColor="@color/rsb_error" /> + app:preferenceTextColor="@color/rsf_error" /> diff --git a/storage/.gitignore b/storage/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/storage/.gitignore @@ -0,0 +1 @@ +/build diff --git a/storage/build.gradle b/storage/build.gradle new file mode 100644 index 000000000..5d5702de5 --- /dev/null +++ b/storage/build.gradle @@ -0,0 +1,172 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +apply plugin: 'com.github.dcendents.android-maven' +apply plugin: 'com.jfrog.bintray' + +apply plugin: 'kotlin-kapt' + +version = research_stack_version + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 19 + targetSdkVersion 28 + versionCode 1 + versionName version + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + resourcePrefix 'rsfs_' + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +Properties properties = new Properties() +properties.load(project.rootProject.file('local.properties').newDataInputStream()) + +ext { + bintrayRepo = 'ResearchStack' + bintrayName = 'Storage' + + publishedGroupId = 'org.researchstack' + libraryName = 'Storage' + artifact = 'storage' + + libraryDescription = 'Storage' + + siteUrl = 'https://researchstack.org' + gitUrl = 'https://github.com/ResearchStack/ResearchStack.git' + + libraryVersion = version + + userOrgName = 'researchstack' + developerId = properties.getProperty("bintray.user") + developerName = properties.getProperty("bintray.developerName") + developerEmail = properties.getProperty("bintray.developerEmail") + + licenseName = 'The Apache Software License, Version 2.0' + licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + allLicenses = ["Apache-2.0"] +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.legacy:legacy-preference-v14:1.0.0' + implementation 'com.google.android.material:material:1.0.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation project(':foundation') + implementation project(':authentication') + implementation "com.google.code.gson:gson:$gson_version" + implementation 'com.scottyab:aes-crypto:0.0.3' + implementation 'co.touchlab.squeaky:squeaky-query:0.4.0.0' + kapt 'co.touchlab.squeaky:squeaky-processor:0.4.0.0' + implementation 'net.zetetic:android-database-sqlcipher:3.5.4@aar' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} + +group = publishedGroupId // Maven Group ID for the artifact + +install { + repositories.mavenInstaller { + // This generates POM.xml with proper parameters + pom { + project { + packaging 'aar' + groupId publishedGroupId + artifactId artifact + + // Add your description here + name libraryName + description libraryDescription + url siteUrl + + // Set your license + licenses { + license { + name licenseName + url licenseUrl + } + } + developers { + developer { + id developerId + name developerName + email developerEmail + } + } + scm { + connection gitUrl + developerConnection gitUrl + url siteUrl + } + } + } + } +} + +if (project.hasProperty("android")) { // Android libraries + task sourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs + } + + task javadoc(type: Javadoc) { + failOnError false + source = android.sourceSets.main.java.srcDirs + } + + afterEvaluate { + javadoc.classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + javadoc.classpath += files(android.libraryVariants.collect { variant -> + variant.javaCompile.classpath.files + }) + } +} else { // Java libraries + task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from sourceSets.main.allSource + } +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives javadocJar + archives sourcesJar +} + +bintray { + user = properties.getProperty("bintray.user") + key = properties.getProperty("bintray.apikey") + + configurations = ['archives'] + pkg { + repo = bintrayRepo + name = bintrayName + userOrg = userOrgName + desc = libraryDescription + websiteUrl = siteUrl + vcsUrl = gitUrl + licenses = allLicenses + publish = true + } +} \ No newline at end of file diff --git a/storage/proguard-rules.pro b/storage/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/storage/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/storage/src/androidTest/java/org/researchstack/feature/storage/ExampleInstrumentedTest.java b/storage/src/androidTest/java/org/researchstack/feature/storage/ExampleInstrumentedTest.java new file mode 100644 index 000000000..c87c689af --- /dev/null +++ b/storage/src/androidTest/java/org/researchstack/feature/storage/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package org.researchstack.feature.storage; + +import android.content.Context; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("org.researchstack.feature.storage.test", appContext.getPackageName()); + } +} diff --git a/storage/src/main/AndroidManifest.xml b/storage/src/main/AndroidManifest.xml new file mode 100644 index 000000000..b86a31c3e --- /dev/null +++ b/storage/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/NotificationHelper.java b/storage/src/main/java/org/researchstack/feature/storage/NotificationHelper.java similarity index 93% rename from backbone/src/main/java/org/researchstack/backbone/storage/NotificationHelper.java rename to storage/src/main/java/org/researchstack/feature/storage/NotificationHelper.java index f327ffa14..98b1af1f1 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/NotificationHelper.java +++ b/storage/src/main/java/org/researchstack/feature/storage/NotificationHelper.java @@ -1,9 +1,9 @@ -package org.researchstack.backbone.storage; +package org.researchstack.feature.storage; import android.content.Context; -import org.researchstack.backbone.storage.database.TaskNotification; -import org.researchstack.backbone.utils.LogExt; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.feature.storage.database.TaskNotification; import java.sql.SQLException; import java.util.List; diff --git a/backbone/src/main/java/org/researchstack/backbone/StorageAccess.java b/storage/src/main/java/org/researchstack/feature/storage/StorageAccess.java similarity index 94% rename from backbone/src/main/java/org/researchstack/backbone/StorageAccess.java rename to storage/src/main/java/org/researchstack/feature/storage/StorageAccess.java index a810e15c0..ec7e6e795 100644 --- a/backbone/src/main/java/org/researchstack/backbone/StorageAccess.java +++ b/storage/src/main/java/org/researchstack/feature/storage/StorageAccess.java @@ -1,19 +1,18 @@ -package org.researchstack.backbone; +package org.researchstack.feature.storage; import android.app.Application; import android.content.Context; import android.os.Handler; import android.os.Looper; -import android.support.annotation.MainThread; +import androidx.annotation.MainThread; -import org.researchstack.backbone.storage.database.AppDatabase; -import org.researchstack.backbone.storage.file.EncryptionProvider; -import org.researchstack.backbone.storage.file.FileAccess; -import org.researchstack.backbone.storage.file.PinCodeConfig; -import org.researchstack.backbone.storage.file.StorageAccessException; -import org.researchstack.backbone.storage.file.StorageAccessListener; -import org.researchstack.backbone.ui.PinCodeActivity; -import org.researchstack.backbone.utils.UiThreadContext; +import org.researchstack.foundation.components.utils.UiThreadContext; +import org.researchstack.feature.storage.database.AppDatabase; +import org.researchstack.feature.storage.file.EncryptionProvider; +import org.researchstack.feature.storage.file.FileAccess; +import org.researchstack.feature.authentication.pincode.PinCodeConfig; +import org.researchstack.feature.storage.file.StorageAccessException; +import org.researchstack.feature.storage.file.StorageAccessListener; import java.util.ArrayList; import java.util.Collections; @@ -28,7 +27,7 @@ * If {@link StorageAccessListener#onDataAuth()} is called, then you must prompt the user for their * pin and authenticate using {@link #authenticate}. *

- * {@link org.researchstack.backbone.ui.PinCodeActivity} handles almost all of this for you, + * {@link org.researchstack.foundation.ui.PinCodeActivity} handles almost all of this for you, * including presenting the pin code screen to the user. PinCodeActivity should be used, extended, * or it's fuctionality copied to your application's own base Activity. Make sure to delay any data * access until {@link PinCodeActivity#onDataReady()} has been called. diff --git a/storage/src/main/java/org/researchstack/feature/storage/StorageAccessPasscodeStore.kt b/storage/src/main/java/org/researchstack/feature/storage/StorageAccessPasscodeStore.kt new file mode 100644 index 000000000..fafb20e8c --- /dev/null +++ b/storage/src/main/java/org/researchstack/feature/storage/StorageAccessPasscodeStore.kt @@ -0,0 +1,28 @@ +package org.researchstack.feature.storage + +import android.content.Context +import org.researchstack.feature.authentication.pincode.PasscodeAuthenticator + +class StorageAccessPasscodeStore(val context: Context): PasscodeAuthenticator.PasscodeStore { + + override fun hasPasscode(): Boolean { + return StorageAccess.getInstance().hasPinCode(context) + } + + override fun registerPasscode(passcode: String) { + StorageAccess.getInstance().createPinCode(context, passcode) + } + + override fun checkPasscode(passcode: String) { + StorageAccess.getInstance().authenticate(context, passcode) + } + + override fun removePasscode() { + StorageAccess.getInstance().removePinCode(context) + } + + override fun changePasscode(oldPasscode: String, newPasscode: String) { + StorageAccess.getInstance().changePinCode(context, oldPasscode, newPasscode) + } + +} \ No newline at end of file diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/database/AppDatabase.java b/storage/src/main/java/org/researchstack/feature/storage/database/AppDatabase.java similarity index 90% rename from backbone/src/main/java/org/researchstack/backbone/storage/database/AppDatabase.java rename to storage/src/main/java/org/researchstack/feature/storage/database/AppDatabase.java index 7e1a529a5..46d25e9a1 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/database/AppDatabase.java +++ b/storage/src/main/java/org/researchstack/feature/storage/database/AppDatabase.java @@ -1,7 +1,7 @@ -package org.researchstack.backbone.storage.database; +package org.researchstack.feature.storage.database; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.result.TaskResult; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.result.TaskResult; import java.util.List; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/database/StepRecord.java b/storage/src/main/java/org/researchstack/feature/storage/database/StepRecord.java similarity index 81% rename from backbone/src/main/java/org/researchstack/backbone/storage/database/StepRecord.java rename to storage/src/main/java/org/researchstack/feature/storage/database/StepRecord.java index 196743cd7..45a103124 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/database/StepRecord.java +++ b/storage/src/main/java/org/researchstack/feature/storage/database/StepRecord.java @@ -1,12 +1,12 @@ -package org.researchstack.backbone.storage.database; +package org.researchstack.feature.storage.database; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.step.Step; -import org.researchstack.backbone.utils.FormatHelper; -import org.researchstack.backbone.utils.TextUtils; +import org.researchstack.foundation.components.utils.FormatHelper; +import org.researchstack.foundation.components.utils.TextUtils; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.step.Step; import java.util.Date; import java.util.Map; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/database/TaskNotification.java b/storage/src/main/java/org/researchstack/feature/storage/database/TaskNotification.java similarity index 87% rename from backbone/src/main/java/org/researchstack/backbone/storage/database/TaskNotification.java rename to storage/src/main/java/org/researchstack/feature/storage/database/TaskNotification.java index 7ba21945e..8d798d68d 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/database/TaskNotification.java +++ b/storage/src/main/java/org/researchstack/feature/storage/database/TaskNotification.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.storage.database; +package org.researchstack.feature.storage.database; import java.io.Serializable; import java.util.Date; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/database/TaskRecord.java b/storage/src/main/java/org/researchstack/feature/storage/database/TaskRecord.java similarity index 85% rename from backbone/src/main/java/org/researchstack/backbone/storage/database/TaskRecord.java rename to storage/src/main/java/org/researchstack/feature/storage/database/TaskRecord.java index 2c8600a42..3992adf5e 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/database/TaskRecord.java +++ b/storage/src/main/java/org/researchstack/feature/storage/database/TaskRecord.java @@ -1,7 +1,7 @@ -package org.researchstack.backbone.storage.database; +package org.researchstack.feature.storage.database; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.result.TaskResult; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.result.TaskResult; import java.util.Date; import java.util.List; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/database/sqlite/DatabaseHelper.java b/storage/src/main/java/org/researchstack/feature/storage/database/sqlite/DatabaseHelper.java similarity index 92% rename from backbone/src/main/java/org/researchstack/backbone/storage/database/sqlite/DatabaseHelper.java rename to storage/src/main/java/org/researchstack/feature/storage/database/sqlite/DatabaseHelper.java index 9dae5cead..8063956fa 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/database/sqlite/DatabaseHelper.java +++ b/storage/src/main/java/org/researchstack/feature/storage/database/sqlite/DatabaseHelper.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.storage.database.sqlite; +package org.researchstack.feature.storage.database.sqlite; import android.content.Context; import android.database.sqlite.SQLiteDatabase; @@ -6,13 +6,13 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.storage.database.AppDatabase; -import org.researchstack.backbone.storage.database.StepRecord; -import org.researchstack.backbone.storage.database.TaskRecord; -import org.researchstack.backbone.utils.FormatHelper; -import org.researchstack.backbone.utils.LogExt; +import org.researchstack.foundation.components.utils.FormatHelper; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.feature.storage.database.AppDatabase; +import org.researchstack.feature.storage.database.StepRecord; +import org.researchstack.feature.storage.database.TaskRecord; import java.sql.SQLException; import java.util.ArrayList; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/database/sqlite/SqlCipherDatabaseHelper.java b/storage/src/main/java/org/researchstack/feature/storage/database/sqlite/SqlCipherDatabaseHelper.java similarity index 92% rename from backbone/src/main/java/org/researchstack/backbone/storage/database/sqlite/SqlCipherDatabaseHelper.java rename to storage/src/main/java/org/researchstack/feature/storage/database/sqlite/SqlCipherDatabaseHelper.java index fea741c9d..b36fa44f2 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/database/sqlite/SqlCipherDatabaseHelper.java +++ b/storage/src/main/java/org/researchstack/feature/storage/database/sqlite/SqlCipherDatabaseHelper.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.storage.database.sqlite; +package org.researchstack.feature.storage.database.sqlite; import android.content.Context; @@ -7,13 +7,13 @@ import net.sqlcipher.database.SQLiteDatabase; -import org.researchstack.backbone.result.StepResult; -import org.researchstack.backbone.result.TaskResult; -import org.researchstack.backbone.storage.database.AppDatabase; -import org.researchstack.backbone.storage.database.StepRecord; -import org.researchstack.backbone.storage.database.TaskRecord; -import org.researchstack.backbone.utils.FormatHelper; -import org.researchstack.backbone.utils.LogExt; +import org.researchstack.foundation.components.utils.FormatHelper; +import org.researchstack.foundation.components.utils.LogExt; +import org.researchstack.foundation.core.models.result.StepResult; +import org.researchstack.foundation.core.models.result.TaskResult; +import org.researchstack.feature.storage.database.AppDatabase; +import org.researchstack.feature.storage.database.StepRecord; +import org.researchstack.feature.storage.database.TaskRecord; import java.sql.SQLException; import java.util.ArrayList; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/database/sqlite/UpdatablePassphraseProvider.java b/storage/src/main/java/org/researchstack/feature/storage/database/sqlite/UpdatablePassphraseProvider.java similarity index 85% rename from backbone/src/main/java/org/researchstack/backbone/storage/database/sqlite/UpdatablePassphraseProvider.java rename to storage/src/main/java/org/researchstack/feature/storage/database/sqlite/UpdatablePassphraseProvider.java index 11b713b10..32de2db5f 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/database/sqlite/UpdatablePassphraseProvider.java +++ b/storage/src/main/java/org/researchstack/feature/storage/database/sqlite/UpdatablePassphraseProvider.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.storage.database.sqlite; +package org.researchstack.feature.storage.database.sqlite; import co.touchlab.squeaky.db.sqlcipher.PassphraseProvider; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/EncryptionProvider.java b/storage/src/main/java/org/researchstack/feature/storage/file/EncryptionProvider.java similarity index 92% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/EncryptionProvider.java rename to storage/src/main/java/org/researchstack/feature/storage/file/EncryptionProvider.java index 5852f6aae..3399ef985 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/EncryptionProvider.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/EncryptionProvider.java @@ -1,8 +1,9 @@ -package org.researchstack.backbone.storage.file; +package org.researchstack.feature.storage.file; import android.content.Context; -import org.researchstack.backbone.storage.file.aes.Encrypter; +import org.researchstack.feature.storage.file.aes.Encrypter; +import org.researchstack.feature.authentication.pincode.PinCodeConfig; /** * This interface is used to create, change, and authenticate pin codes provided by the user. diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/FileAccess.java b/storage/src/main/java/org/researchstack/feature/storage/file/FileAccess.java similarity index 96% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/FileAccess.java rename to storage/src/main/java/org/researchstack/feature/storage/file/FileAccess.java index 41945cf75..0ed084fb0 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/FileAccess.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/FileAccess.java @@ -1,8 +1,8 @@ -package org.researchstack.backbone.storage.file; +package org.researchstack.feature.storage.file; import android.content.Context; -import org.researchstack.backbone.storage.file.aes.Encrypter; +import org.researchstack.feature.storage.file.aes.Encrypter; /** * Generic file access contract for the app. Depending on the type, there may need to be auth diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/SimpleFileAccess.java b/storage/src/main/java/org/researchstack/feature/storage/file/SimpleFileAccess.java similarity index 90% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/SimpleFileAccess.java rename to storage/src/main/java/org/researchstack/feature/storage/file/SimpleFileAccess.java index 550da5e85..f6f1bc3d3 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/SimpleFileAccess.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/SimpleFileAccess.java @@ -1,11 +1,11 @@ -package org.researchstack.backbone.storage.file; +package org.researchstack.feature.storage.file; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.WorkerThread; +import androidx.annotation.NonNull; +import androidx.annotation.WorkerThread; -import org.researchstack.backbone.storage.file.aes.Encrypter; -import org.researchstack.backbone.utils.FileUtils; +import org.researchstack.feature.storage.utils.FileUtils; +import org.researchstack.feature.storage.file.aes.Encrypter; import java.io.File; import java.io.FileInputStream; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/StorageAccessException.java b/storage/src/main/java/org/researchstack/feature/storage/file/StorageAccessException.java similarity index 89% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/StorageAccessException.java rename to storage/src/main/java/org/researchstack/feature/storage/file/StorageAccessException.java index 1d73f846b..5f5424f42 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/StorageAccessException.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/StorageAccessException.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.storage.file; +package org.researchstack.feature.storage.file; public class StorageAccessException extends RuntimeException { public StorageAccessException() { diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/StorageAccessListener.java b/storage/src/main/java/org/researchstack/feature/storage/file/StorageAccessListener.java similarity index 93% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/StorageAccessListener.java rename to storage/src/main/java/org/researchstack/feature/storage/file/StorageAccessListener.java index afac8f42e..6d90903ea 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/StorageAccessListener.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/StorageAccessListener.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.storage.file; +package org.researchstack.feature.storage.file; /** * Callback for data access. This will change a lot soon. diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/UnencryptedProvider.java b/storage/src/main/java/org/researchstack/feature/storage/file/UnencryptedProvider.java similarity index 85% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/UnencryptedProvider.java rename to storage/src/main/java/org/researchstack/feature/storage/file/UnencryptedProvider.java index 95f041358..a9e639043 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/UnencryptedProvider.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/UnencryptedProvider.java @@ -1,9 +1,10 @@ -package org.researchstack.backbone.storage.file; +package org.researchstack.feature.storage.file; import android.content.Context; -import org.researchstack.backbone.storage.file.aes.ClearEncrypter; -import org.researchstack.backbone.storage.file.aes.Encrypter; +import org.researchstack.feature.storage.file.aes.ClearEncrypter; +import org.researchstack.feature.storage.file.aes.Encrypter; +import org.researchstack.feature.authentication.pincode.PinCodeConfig; /** * Use this class as the EncryptionProvider when you want to store all data without encryption. Pin diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/AesEncrypter.java b/storage/src/main/java/org/researchstack/feature/storage/file/aes/AesEncrypter.java similarity index 95% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/aes/AesEncrypter.java rename to storage/src/main/java/org/researchstack/feature/storage/file/aes/AesEncrypter.java index 21712f9ae..280ba275a 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/AesEncrypter.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/aes/AesEncrypter.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.storage.file.aes; +package org.researchstack.feature.storage.file.aes; import com.tozny.crypto.android.AesCbcWithIntegrity; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/AesProvider.java b/storage/src/main/java/org/researchstack/feature/storage/file/aes/AesProvider.java similarity index 91% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/aes/AesProvider.java rename to storage/src/main/java/org/researchstack/feature/storage/file/aes/AesProvider.java index e901df21b..95ec7e45a 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/AesProvider.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/aes/AesProvider.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.storage.file.aes; +package org.researchstack.feature.storage.file.aes; import com.tozny.crypto.android.AesCbcWithIntegrity; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/ClearEncrypter.java b/storage/src/main/java/org/researchstack/feature/storage/file/aes/ClearEncrypter.java similarity index 89% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/aes/ClearEncrypter.java rename to storage/src/main/java/org/researchstack/feature/storage/file/aes/ClearEncrypter.java index ca8a3eee3..30eb0ad46 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/ClearEncrypter.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/aes/ClearEncrypter.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.storage.file.aes; +package org.researchstack.feature.storage.file.aes; /** * This encrypter doesn't actually encrypt or decrypt anything that passes through it. Allows for diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/Encrypter.java b/storage/src/main/java/org/researchstack/feature/storage/file/aes/Encrypter.java similarity index 87% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/aes/Encrypter.java rename to storage/src/main/java/org/researchstack/feature/storage/file/aes/Encrypter.java index f62d147ce..18d8a0ebf 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/Encrypter.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/aes/Encrypter.java @@ -1,10 +1,10 @@ -package org.researchstack.backbone.storage.file.aes; +package org.researchstack.feature.storage.file.aes; import java.security.GeneralSecurityException; /** - * Implement this class and use in your {@link org.researchstack.backbone.storage.file.EncryptionProvider} - * to encrypt/decrypt all date before it is written using {@link org.researchstack.backbone.storage.file.FileAccess}. + * Implement this class and use in your {@link org.researchstack.foundation.storage.file.EncryptionProvider} + * to encrypt/decrypt all date before it is written using {@link org.researchstack.foundation.storage.file.FileAccess}. */ public interface Encrypter { /** diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/PinProtectedProvider.java b/storage/src/main/java/org/researchstack/feature/storage/file/aes/PinProtectedProvider.java similarity index 94% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/aes/PinProtectedProvider.java rename to storage/src/main/java/org/researchstack/feature/storage/file/aes/PinProtectedProvider.java index ed94960af..3c8905174 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/PinProtectedProvider.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/aes/PinProtectedProvider.java @@ -1,14 +1,14 @@ -package org.researchstack.backbone.storage.file.aes; +package org.researchstack.feature.storage.file.aes; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import com.tozny.crypto.android.AesCbcWithIntegrity; -import org.researchstack.backbone.storage.file.EncryptionProvider; -import org.researchstack.backbone.storage.file.PinCodeConfig; -import org.researchstack.backbone.storage.file.StorageAccessException; -import org.researchstack.backbone.utils.FileUtils; +import org.researchstack.feature.storage.utils.FileUtils; +import org.researchstack.feature.storage.file.EncryptionProvider; +import org.researchstack.feature.authentication.pincode.PinCodeConfig; +import org.researchstack.feature.storage.file.StorageAccessException; import java.io.File; import java.io.IOException; diff --git a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/UnencryptedPinProvider.java b/storage/src/main/java/org/researchstack/feature/storage/file/aes/UnencryptedPinProvider.java similarity index 93% rename from backbone/src/main/java/org/researchstack/backbone/storage/file/aes/UnencryptedPinProvider.java rename to storage/src/main/java/org/researchstack/feature/storage/file/aes/UnencryptedPinProvider.java index 56a4301f8..c7e33ea1b 100644 --- a/backbone/src/main/java/org/researchstack/backbone/storage/file/aes/UnencryptedPinProvider.java +++ b/storage/src/main/java/org/researchstack/feature/storage/file/aes/UnencryptedPinProvider.java @@ -1,4 +1,4 @@ -package org.researchstack.backbone.storage.file.aes; +package org.researchstack.feature.storage.file.aes; import com.tozny.crypto.android.AesCbcWithIntegrity; diff --git a/backbone/src/main/java/org/researchstack/backbone/utils/FileUtils.java b/storage/src/main/java/org/researchstack/feature/storage/utils/FileUtils.java similarity index 92% rename from backbone/src/main/java/org/researchstack/backbone/utils/FileUtils.java rename to storage/src/main/java/org/researchstack/feature/storage/utils/FileUtils.java index e3d9954b3..4351465b4 100644 --- a/backbone/src/main/java/org/researchstack/backbone/utils/FileUtils.java +++ b/storage/src/main/java/org/researchstack/feature/storage/utils/FileUtils.java @@ -1,8 +1,10 @@ -package org.researchstack.backbone.utils; +package org.researchstack.feature.storage.utils; -import android.support.annotation.NonNull; +//TODO: MOVE TO STORAGE MODULE -import org.researchstack.backbone.storage.file.StorageAccessException; +import androidx.annotation.NonNull; + +import org.researchstack.feature.storage.file.StorageAccessException; import java.io.ByteArrayOutputStream; import java.io.File; diff --git a/storage/src/main/res/values/strings.xml b/storage/src/main/res/values/strings.xml new file mode 100644 index 000000000..f11f7450a --- /dev/null +++ b/storage/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + + diff --git a/storage/src/test/java/org/researchstack/feature/storage/ExampleUnitTest.java b/storage/src/test/java/org/researchstack/feature/storage/ExampleUnitTest.java new file mode 100644 index 000000000..f3083ac17 --- /dev/null +++ b/storage/src/test/java/org/researchstack/feature/storage/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package org.researchstack.feature.storage; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file