resolved conflicts before merge
This commit is contained in:
commit
edbf3aafa7
@ -4,9 +4,10 @@ apply plugin: 'kotlin-android-extensions'
|
|||||||
apply plugin: 'jacoco'
|
apply plugin: 'jacoco'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
|
||||||
compileSdkVersion 29
|
compileSdkVersion 29
|
||||||
buildToolsVersion "29.0.3"
|
buildToolsVersion "29.0.3"
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
@ -18,6 +19,12 @@ compileOptions {
|
|||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||||
|
}
|
||||||
|
sourceSets {
|
||||||
|
main.java.srcDirs += 'src/main/java'
|
||||||
|
test.java.srcDirs += 'src/test/java'
|
||||||
|
androidTest.java.srcDirs += 'src/androidTest/java'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@ -29,6 +36,10 @@ compileOptions {
|
|||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
testOptions {
|
||||||
|
animationsDisabled true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
@ -54,13 +65,24 @@ dependencies {
|
|||||||
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.1'
|
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.1'
|
||||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.16'
|
implementation 'io.reactivex.rxjava2:rxjava:2.2.16'
|
||||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||||
testImplementation "com.github.tomakehurst:wiremock-jre8:2.26.2"
|
implementation "androidx.browser:browser:1.2.0"
|
||||||
|
implementation 'com.google.android.material:material:1.1.0'
|
||||||
|
|
||||||
|
|
||||||
|
implementation ("com.github.bumptech.glide:glide:4.11.0") {
|
||||||
|
exclude group: "com.android.support"
|
||||||
|
}
|
||||||
|
implementation "com.github.bumptech.glide:okhttp-integration:4.11.0"
|
||||||
|
|
||||||
|
testImplementation "com.github.tomakehurst:wiremock-jre8:2.26.3"
|
||||||
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
|
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
|
||||||
testImplementation 'junit:junit:4.13'
|
testImplementation 'junit:junit:4.13'
|
||||||
|
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
}
|
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.2.0'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
tasks.withType(Test) {
|
tasks.withType(Test) {
|
||||||
jacoco.includeNoLocationClasses = true
|
jacoco.includeNoLocationClasses = true
|
||||||
@ -77,9 +99,13 @@ task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'crea
|
|||||||
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
|
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
|
||||||
def kotlinDebugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter)
|
def kotlinDebugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter)
|
||||||
def mainSrc = "$project.projectDir/src/main/java"
|
def mainSrc = "$project.projectDir/src/main/java"
|
||||||
sourceDirectories = files([mainSrc])
|
getSourceDirectories().from(files([mainSrc]))
|
||||||
classDirectories = files([kotlinDebugTree])
|
getClassDirectories().from(files([kotlinDebugTree]))
|
||||||
executionData = fileTree(dir: project.buildDir, includes: [
|
getExecutionData().from(fileTree(dir: project.buildDir, includes: [
|
||||||
'jacoco/testDebugUnitTest.exec', 'outputs/code-coverage/debugAndroidTest/connected/*coverage.ec'
|
|
||||||
])
|
'outputs/code_coverage/debugAndroidTest/connected/*coverage.ec',
|
||||||
|
|
||||||
|
'jacoco/testDebugUnitTest.exec'
|
||||||
|
|
||||||
|
]))
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
package com.h.pixeldroid
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.Intent.ACTION_VIEW
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.action.ViewActions
|
||||||
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
|
import androidx.test.espresso.intent.Intents.intended
|
||||||
|
import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
|
||||||
|
import androidx.test.espresso.intent.matcher.IntentMatchers.hasDataString
|
||||||
|
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||||
|
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.rule.ActivityTestRule
|
||||||
|
import org.hamcrest.CoreMatchers.*
|
||||||
|
import org.hamcrest.Matcher
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class LoginInstrumentedTest {
|
||||||
|
@get:Rule
|
||||||
|
var activityRule: ActivityScenarioRule<LoginActivity>
|
||||||
|
= ActivityScenarioRule(LoginActivity::class.java)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun clickConnect() {
|
||||||
|
onView(withId(R.id.connect_instance_button)).check(matches(withText("Connect")))
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun invalidURL() {
|
||||||
|
onView(withId(R.id.editText)).perform(ViewActions.replaceText("/jdi"), ViewActions.closeSoftKeyboard())
|
||||||
|
onView(withId(R.id.connect_instance_button)).perform(click())
|
||||||
|
onView(withId(R.id.editText)).check(matches(hasErrorText("Invalid domain")))
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun notPixelfedInstance() {
|
||||||
|
onView(withId(R.id.editText)).perform(ViewActions.replaceText("localhost"), ViewActions.closeSoftKeyboard())
|
||||||
|
onView(withId(R.id.connect_instance_button)).perform(click())
|
||||||
|
onView(withId(R.id.editText)).check(matches(hasErrorText("Could not register the application with this server")))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class LoginCheckIntent {
|
||||||
|
@get:Rule
|
||||||
|
val intentsTestRule = IntentsTestRule(LoginActivity::class.java)
|
||||||
|
@Test
|
||||||
|
fun launchesIntent() {
|
||||||
|
val expectedIntent: Matcher<Intent> = allOf(
|
||||||
|
hasAction(ACTION_VIEW),
|
||||||
|
hasDataString(containsString("pixelfed.social"))
|
||||||
|
)
|
||||||
|
|
||||||
|
onView(withId(R.id.editText)).perform(ViewActions.replaceText("pixelfed.social"), ViewActions.closeSoftKeyboard())
|
||||||
|
onView(withId(R.id.connect_instance_button)).perform(click())
|
||||||
|
|
||||||
|
Thread.sleep(5000)
|
||||||
|
|
||||||
|
intended(expectedIntent)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class AfterIntent {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val rule = ActivityTestRule(LoginActivity::class.java)
|
||||||
|
private var launchedActivity: Activity? = null
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
val intent = Intent(ACTION_VIEW, Uri.parse("oauth2redirect://com.h.pixeldroid?code=sdfdqsf"))
|
||||||
|
launchedActivity = rule.launchActivity(intent)
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun usesIntent() {
|
||||||
|
|
||||||
|
Thread.sleep(5000)
|
||||||
|
|
||||||
|
onView(withId(R.id.editText)).check(matches(
|
||||||
|
anyOf(hasErrorText("Error getting token"),
|
||||||
|
hasErrorText("Could not authenticate"))))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
28
app/src/androidTest/java/com/h/pixeldroid/ProfileTest.kt
Normal file
28
app/src/androidTest/java/com/h/pixeldroid/ProfileTest.kt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package com.h.pixeldroid
|
||||||
|
|
||||||
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||||
|
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import org.hamcrest.Matchers.not
|
||||||
|
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import java.lang.Thread.sleep
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ProfileTest {
|
||||||
|
@get:Rule
|
||||||
|
var activityRule: ActivityScenarioRule<MainActivity>
|
||||||
|
= ActivityScenarioRule(MainActivity::class.java)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testFollowersTextView() {
|
||||||
|
onView(withId(R.id.button)).perform(click())
|
||||||
|
onView(withId(R.id.followers)).check(matches(withText("Followers")))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,9 +9,23 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
|
<activity
|
||||||
|
android:name=".LoginActivity"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data
|
||||||
|
android:host="${applicationId}"
|
||||||
|
android:scheme="@string/auth_scheme" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity android:name=".ProfileActivity"></activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:theme="@style/AppTheme.NoActionBar" >
|
android:theme="@style/AppTheme.NoActionBar">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
174
app/src/main/java/com/h/pixeldroid/LoginActivity.kt
Normal file
174
app/src/main/java/com/h/pixeldroid/LoginActivity.kt
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
package com.h.pixeldroid
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.browser.customtabs.CustomTabsIntent
|
||||||
|
import com.h.pixeldroid.api.PixelfedAPI
|
||||||
|
import com.h.pixeldroid.objects.Application
|
||||||
|
import com.h.pixeldroid.objects.Token
|
||||||
|
import kotlinx.android.synthetic.main.activity_login.*
|
||||||
|
import okhttp3.HttpUrl
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Callback
|
||||||
|
import retrofit2.Response
|
||||||
|
|
||||||
|
class LoginActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
private lateinit var OAUTH_SCHEME: String
|
||||||
|
private val PACKAGE_ID = BuildConfig.APPLICATION_ID
|
||||||
|
private val SCOPE = "read write follow"
|
||||||
|
private lateinit var APP_NAME: String
|
||||||
|
private lateinit var preferences: SharedPreferences
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_login)
|
||||||
|
|
||||||
|
connect_instance_button.setOnClickListener { onClickConnect() }
|
||||||
|
APP_NAME = getString(R.string.app_name)
|
||||||
|
OAUTH_SCHEME = getString(R.string.auth_scheme)
|
||||||
|
preferences = getSharedPreferences(
|
||||||
|
"$PACKAGE_ID.pref", Context.MODE_PRIVATE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart(){
|
||||||
|
super.onStart()
|
||||||
|
|
||||||
|
val url = intent.data
|
||||||
|
|
||||||
|
if (url == null || !url.toString().startsWith("$OAUTH_SCHEME://$PACKAGE_ID")) return
|
||||||
|
|
||||||
|
val code = url.getQueryParameter("code")
|
||||||
|
authenticate(code)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onClickConnect() {
|
||||||
|
|
||||||
|
connect_instance_button.isEnabled = false
|
||||||
|
|
||||||
|
val normalizedDomain = normalizeDomain(editText.text.toString())
|
||||||
|
|
||||||
|
try{
|
||||||
|
HttpUrl.Builder().host(normalizedDomain).scheme("https").build()
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
return failedRegistration(getString(R.string.invalid_domain))
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences.edit()
|
||||||
|
.putString("domain", normalizedDomain)
|
||||||
|
.apply()
|
||||||
|
registerAppToServer(normalizedDomain)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun normalizeDomain(domain: String): String {
|
||||||
|
var d = domain.replace("http://", "")
|
||||||
|
d = d.replace("https://", "")
|
||||||
|
return d.trim(Char::isWhitespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerAppToServer(normalizedDomain: String) {
|
||||||
|
val callback = object : Callback<Application> {
|
||||||
|
override fun onResponse(call: Call<Application>, response: Response<Application>) {
|
||||||
|
if (!response.isSuccessful) {
|
||||||
|
return failedRegistration()
|
||||||
|
}
|
||||||
|
|
||||||
|
val credentials = response.body()
|
||||||
|
val clientId = credentials?.client_id ?: return failedRegistration()
|
||||||
|
val clientSecret = credentials.client_secret
|
||||||
|
|
||||||
|
preferences.edit()
|
||||||
|
.putString("clientID", clientId)
|
||||||
|
.putString("clientSecret", clientSecret)
|
||||||
|
.apply()
|
||||||
|
|
||||||
|
promptOAuth(normalizedDomain, clientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<Application>, t: Throwable) {
|
||||||
|
return failedRegistration()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PixelfedAPI.create("https://$normalizedDomain").registerApplication(
|
||||||
|
APP_NAME,"$OAUTH_SCHEME://$PACKAGE_ID", SCOPE
|
||||||
|
).enqueue(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun promptOAuth(normalizedDomain: String, client_id: String) {
|
||||||
|
|
||||||
|
val url = "https://$normalizedDomain/oauth/authorize?" +
|
||||||
|
"client_id" + "=" + client_id + "&" +
|
||||||
|
"redirect_uri" + "=" + "$OAUTH_SCHEME://$PACKAGE_ID" + "&" +
|
||||||
|
"response_type=code" + "&" +
|
||||||
|
"scope=$SCOPE"
|
||||||
|
|
||||||
|
val intent = CustomTabsIntent.Builder().build()
|
||||||
|
|
||||||
|
try {
|
||||||
|
intent.launchUrl(this, Uri.parse(url))
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||||
|
if (browserIntent.resolveActivity(packageManager) != null) {
|
||||||
|
startActivity(browserIntent)
|
||||||
|
} else {
|
||||||
|
return failedRegistration(getString(R.string.browser_launch_failed))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connect_instance_button.isEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun authenticate(code: String?) {
|
||||||
|
|
||||||
|
// Get previous values from preferences
|
||||||
|
val domain = preferences.getString("domain", "")
|
||||||
|
val clientId = preferences.getString("clientID", "")
|
||||||
|
val clientSecret = preferences.getString("clientSecret", "")
|
||||||
|
|
||||||
|
if (code == null || domain.isNullOrEmpty() || clientId.isNullOrEmpty() || clientSecret.isNullOrEmpty()) {
|
||||||
|
return failedRegistration(getString(R.string.auth_failed))
|
||||||
|
}
|
||||||
|
|
||||||
|
//Successful authorization
|
||||||
|
val callback = object : Callback<Token> {
|
||||||
|
override fun onResponse(call: Call<Token>, response: Response<Token>) {
|
||||||
|
if (!response.isSuccessful || response.body() == null) {
|
||||||
|
return failedRegistration(getString(R.string.token_error))
|
||||||
|
}
|
||||||
|
authenticationSuccessful(domain, response.body()!!.access_token)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<Token>, t: Throwable) {
|
||||||
|
return failedRegistration(getString(R.string.token_error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelfedAPI.create("https://$domain")
|
||||||
|
.obtainToken(
|
||||||
|
clientId, clientSecret, "$OAUTH_SCHEME://$PACKAGE_ID", SCOPE, code,
|
||||||
|
"authorization_code"
|
||||||
|
).enqueue(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun authenticationSuccessful(domain: String, accessToken: String) {
|
||||||
|
preferences.edit().putString("accessToken", accessToken).apply()
|
||||||
|
val intent = Intent(this, MainActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun failedRegistration(message: String =
|
||||||
|
getString(R.string.registration_failed)){
|
||||||
|
connect_instance_button.isEnabled = true
|
||||||
|
editText.error = message
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package com.h.pixeldroid
|
package com.h.pixeldroid
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.annotation.NonNull
|
import androidx.annotation.NonNull
|
||||||
@ -20,6 +20,9 @@ import retrofit2.Response
|
|||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
|
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Button
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
|
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
|
||||||
|
|
||||||
@ -48,6 +51,16 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||||||
launchFragment(AccountFragment())
|
launchFragment(AccountFragment())
|
||||||
navigationView.setCheckedItem(R.id.nav_account)
|
navigationView.setCheckedItem(R.id.nav_account)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val button_login = findViewById<Button>(R.id.button_start_login)
|
||||||
|
button_login.setOnClickListener((View.OnClickListener {
|
||||||
|
val intent = Intent(this, LoginActivity::class.java)
|
||||||
|
startActivity(intent) }))
|
||||||
|
|
||||||
|
val button = findViewById<Button>(R.id.button)
|
||||||
|
button.setOnClickListener((View.OnClickListener {
|
||||||
|
val intent = Intent(this, ProfileActivity::class.java)
|
||||||
|
startActivity(intent) }))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
80
app/src/main/java/com/h/pixeldroid/ProfileActivity.kt
Normal file
80
app/src/main/java/com/h/pixeldroid/ProfileActivity.kt
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package com.h.pixeldroid
|
||||||
|
|
||||||
|
import android.graphics.Typeface
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.h.pixeldroid.api.PixelfedAPI
|
||||||
|
import com.h.pixeldroid.objects.Account
|
||||||
|
import com.h.pixeldroid.objects.Status
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Callback
|
||||||
|
import retrofit2.Response
|
||||||
|
|
||||||
|
class ProfileActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_profile)
|
||||||
|
|
||||||
|
var statuses: ArrayList<Status>? = null
|
||||||
|
val BASE_URL = "https://pixelfed.de/"
|
||||||
|
|
||||||
|
val pixelfedAPI = PixelfedAPI.create(BASE_URL)
|
||||||
|
|
||||||
|
|
||||||
|
pixelfedAPI.timelinePublic(null, null, null, null, null)
|
||||||
|
.enqueue(object : Callback<List<Status>> {
|
||||||
|
override fun onResponse(call: Call<List<Status>>, response: Response<List<Status>>) {
|
||||||
|
if (response.code() == 200) {
|
||||||
|
statuses = response.body() as ArrayList<Status>?
|
||||||
|
|
||||||
|
if(!statuses.isNullOrEmpty()) {
|
||||||
|
|
||||||
|
val account = statuses!![0].account
|
||||||
|
|
||||||
|
setContent(account)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<List<Status>>, t: Throwable) {
|
||||||
|
Log.e("Ouch, not OK", t.toString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setContent(account: Account) {
|
||||||
|
// ImageView : profile picture
|
||||||
|
val profilePicture = findViewById<ImageView>(R.id.profilePicture)
|
||||||
|
Glide.with(applicationContext).load(account.avatar).into(profilePicture)
|
||||||
|
|
||||||
|
// TextView : description / bio
|
||||||
|
val description = findViewById<TextView>(R.id.description)
|
||||||
|
description.text = account.note
|
||||||
|
|
||||||
|
// TextView : account name
|
||||||
|
val accountName = findViewById<TextView>(R.id.accountName)
|
||||||
|
accountName.text = account.username
|
||||||
|
|
||||||
|
// TextView : number of posts
|
||||||
|
val nbPosts = findViewById<TextView>(R.id.nbPosts)
|
||||||
|
nbPosts.text = account.statuses_count.toString()
|
||||||
|
nbPosts.setTypeface(null, Typeface.BOLD)
|
||||||
|
|
||||||
|
// TextView : number of followers
|
||||||
|
val nbFollowers = findViewById<TextView>(R.id.nbFollowers)
|
||||||
|
nbFollowers.text = account.followers_count.toString()
|
||||||
|
nbFollowers.setTypeface(null, Typeface.BOLD)
|
||||||
|
|
||||||
|
// TextView : number of following
|
||||||
|
val nbFollowing = findViewById<TextView>(R.id.nbFollowing)
|
||||||
|
nbFollowing.text = account.following_count.toString()
|
||||||
|
nbFollowing.setTypeface(null, Typeface.BOLD)
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,18 @@
|
|||||||
package com.h.pixeldroid.api
|
package com.h.pixeldroid.api
|
||||||
|
|
||||||
import android.util.Log
|
import com.h.pixeldroid.objects.Application
|
||||||
import com.h.pixeldroid.objects.*
|
import com.h.pixeldroid.objects.Status
|
||||||
|
import com.h.pixeldroid.objects.Token
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
|
||||||
import retrofit2.Response
|
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
|
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import retrofit2.http.FormUrlEncoded
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.POST
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
import retrofit2.http.Field
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Implements the Pixelfed API
|
Implements the Pixelfed API
|
||||||
@ -20,15 +23,36 @@ import retrofit2.http.Query
|
|||||||
|
|
||||||
interface PixelfedAPI {
|
interface PixelfedAPI {
|
||||||
|
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("/api/v1/apps")
|
||||||
|
fun registerApplication(
|
||||||
|
@Field("client_name") client_name: String,
|
||||||
|
@Field("redirect_uris") redirect_uris: String,
|
||||||
|
@Field("scopes") scopes: String? = null,
|
||||||
|
@Field("website") website: String? = null
|
||||||
|
): Call<Application>
|
||||||
|
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("/oauth/token")
|
||||||
|
fun obtainToken(
|
||||||
|
@Field("client_id") client_id: String,
|
||||||
|
@Field("client_secret") client_secret: String,
|
||||||
|
@Field("redirect_uri") redirect_uri: String,
|
||||||
|
@Field("scope") scope: String? = "read",
|
||||||
|
@Field("code") code: String? = null,
|
||||||
|
@Field("grant_type") grant_type: String? = null
|
||||||
|
): Call<Token>
|
||||||
|
|
||||||
@GET("/api/v1/timelines/public")
|
@GET("/api/v1/timelines/public")
|
||||||
fun timelinePublic(
|
fun timelinePublic(
|
||||||
@Query("local") local: Boolean?,
|
@Query("local") local: Boolean? = null,
|
||||||
@Query("max_id") max_id: String?,
|
@Query("max_id") max_id: String? = null,
|
||||||
@Query("since_id") since_id: String?,
|
@Query("since_id") since_id: String? = null,
|
||||||
@Query("min_id") min_id: String?,
|
@Query("min_id") min_id: String? = null,
|
||||||
@Query("limit") limit: Int?
|
@Query("limit") limit: Int? = null
|
||||||
): Call<List<Status>>
|
): Call<List<Status>>
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun create(baseUrl: String): PixelfedAPI {
|
fun create(baseUrl: String): PixelfedAPI {
|
||||||
return Retrofit.Builder()
|
return Retrofit.Builder()
|
||||||
|
@ -5,5 +5,8 @@ data class Application (
|
|||||||
val name: String,
|
val name: String,
|
||||||
//Optional attributes
|
//Optional attributes
|
||||||
val website: String? = null,
|
val website: String? = null,
|
||||||
val vapid_key: String? = null
|
val vapid_key: String? = null,
|
||||||
|
//Client Attributes
|
||||||
|
val client_id: String? = null,
|
||||||
|
val client_secret: String? = null
|
||||||
)
|
)
|
8
app/src/main/java/com/h/pixeldroid/objects/Token.kt
Normal file
8
app/src/main/java/com/h/pixeldroid/objects/Token.kt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package com.h.pixeldroid.objects
|
||||||
|
|
||||||
|
data class Token(
|
||||||
|
val access_token: String,
|
||||||
|
val token_type: String,
|
||||||
|
val scope: String,
|
||||||
|
val created_at: Int
|
||||||
|
)
|
39
app/src/main/res/layout/activity_login.xml
Normal file
39
app/src/main/res/layout/activity_login.xml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".LoginActivity">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/connect_instance_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="36dp"
|
||||||
|
android:text="Connect"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.498"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/domainTextInputLayout" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/domainTextInputLayout"
|
||||||
|
android:layout_width="250dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Domain of your instance"
|
||||||
|
app:errorEnabled="true"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.40">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/editText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ems="10"
|
||||||
|
android:inputType="textUri" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -38,4 +38,26 @@
|
|||||||
app:headerLayout="@layout/nav_header"
|
app:headerLayout="@layout/nav_header"
|
||||||
app:menu="@menu/activity_main_drawer" />
|
app:menu="@menu/activity_main_drawer" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:layout_editor_absoluteX="67dp"
|
||||||
|
tools:layout_editor_absoluteY="299dp">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button_start_login"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="80dp"
|
||||||
|
android:text="start login" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Show a profile" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.drawerlayout.widget.DrawerLayout>
|
</androidx.drawerlayout.widget.DrawerLayout>
|
128
app/src/main/res/layout/activity_profile.xml
Normal file
128
app/src/main/res/layout/activity_profile.xml
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".ProfileActivity">
|
||||||
|
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/profilePicture"
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="120dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:srcCompat="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/nbFollowing"
|
||||||
|
android:layout_width="38dp"
|
||||||
|
android:layout_height="26dp"
|
||||||
|
android:layout_marginTop="52dp"
|
||||||
|
android:layout_marginEnd="36dp"
|
||||||
|
android:text="N/A"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/posts"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="Posts"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/nbPosts"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/nbPosts"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/nbPosts" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/nbPosts"
|
||||||
|
android:layout_width="39dp"
|
||||||
|
android:layout_height="27dp"
|
||||||
|
android:layout_marginStart="152dp"
|
||||||
|
android:layout_marginTop="52dp"
|
||||||
|
android:text="N/A"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/followers"
|
||||||
|
android:layout_width="65dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="Followers"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/nbFollowers"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/nbFollowers"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/nbFollowers" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/following"
|
||||||
|
android:layout_width="65dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="Following"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/nbFollowing"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/nbFollowing"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/nbFollowing" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/nbFollowers"
|
||||||
|
android:layout_width="39dp"
|
||||||
|
android:layout_height="27dp"
|
||||||
|
android:layout_marginTop="52dp"
|
||||||
|
android:text="N/A"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.669"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/accountName"
|
||||||
|
android:layout_width="156dp"
|
||||||
|
android:layout_height="22dp"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:text="No Username"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/profilePicture"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/profilePicture" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="348dp"
|
||||||
|
android:layout_height="85dp"
|
||||||
|
android:layout_marginTop="14dp"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/accountName"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/accountName" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/followButton"
|
||||||
|
android:layout_width="150dp"
|
||||||
|
android:layout_height="38dp"
|
||||||
|
android:layout_marginTop="14dp"
|
||||||
|
android:text="Follow"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/description"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/description" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/postsButton"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_marginStart="152dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/followButton"
|
||||||
|
app:srcCompat="@android:drawable/ic_dialog_dialer" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/collectionButton"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/postsButton"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/postsButton"
|
||||||
|
app:srcCompat="@android:drawable/ic_menu_gallery" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -15,12 +15,26 @@
|
|||||||
<item>English</item>
|
<item>English</item>
|
||||||
<item>Français</item>
|
<item>Français</item>
|
||||||
<item>日本人</item>
|
<item>日本人</item>
|
||||||
|
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="list_font_size">
|
<string-array name="list_font_size">
|
||||||
<item>Small</item>
|
<item>Small</item>
|
||||||
<item>Medium</item>
|
<item>Medium</item>
|
||||||
<item>Big</item>
|
<item>Big</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string name="title_activity_login">Sign in</string>
|
||||||
|
<string name="prompt_email">Email</string>
|
||||||
|
<string name="prompt_password">Password</string>
|
||||||
|
<string name="action_sign_in">Sign in or register</string>
|
||||||
|
<string name="action_sign_in_short">Sign in</string>
|
||||||
|
<string name="welcome">"Welcome !"</string>
|
||||||
|
<string name="invalid_username">Not a valid username</string>
|
||||||
|
<string name="invalid_password">Password must be >5 characters</string>
|
||||||
|
<string name="login_failed">"Login failed"</string>
|
||||||
|
<string name="invalid_domain">"Invalid domain"</string>
|
||||||
|
<string name="registration_failed">"Could not register the application with this server"</string>
|
||||||
|
<string name="browser_launch_failed">"Could not launch a browser, do you have one?"</string>
|
||||||
|
<string name="auth_failed">"Could not authenticate"</string>
|
||||||
|
<string name="token_error">"Error getting token"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
4
app/src/main/res/values/values.xml
Normal file
4
app/src/main/res/values/values.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="auth_scheme" translatable="false">oauth2redirect</string>
|
||||||
|
</resources>
|
@ -5,7 +5,6 @@ import com.github.tomakehurst.wiremock.junit.WireMockRule
|
|||||||
import com.h.pixeldroid.api.PixelfedAPI
|
import com.h.pixeldroid.api.PixelfedAPI
|
||||||
import com.h.pixeldroid.objects.*
|
import com.h.pixeldroid.objects.*
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertNotNull
|
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
@ -132,4 +131,54 @@ class APIUnitTest {
|
|||||||
f.emojis== emptyList<Emoji>() && f.reblogs_count==0 && f.favourites_count==0&& f.replies_count==0 && f.url=="https://pixelfed.de/p/Miike/140364967936397312")
|
f.emojis== emptyList<Emoji>() && f.reblogs_count==0 && f.favourites_count==0&& f.replies_count==0 && f.url=="https://pixelfed.de/p/Miike/140364967936397312")
|
||||||
assert(f.in_reply_to_id==null && f.in_reply_to_account==null && f.reblog==null && f.poll==null && f.card==null && f.language==null && f.text==null && !f.favourited && !f.reblogged && !f.muted && !f.bookmarked && !f.pinned)
|
assert(f.in_reply_to_id==null && f.in_reply_to_account==null && f.reblog==null && f.poll==null && f.card==null && f.language==null && f.text==null && !f.favourited && !f.reblogged && !f.muted && !f.bookmarked && !f.pinned)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun register_application(){
|
||||||
|
stubFor(
|
||||||
|
post(urlEqualTo("/api/v1/apps"))
|
||||||
|
.willReturn(
|
||||||
|
aResponse()
|
||||||
|
.withStatus(200)
|
||||||
|
.withHeader("Content-Type", "application/json")
|
||||||
|
.withBody(""" {"id":3197,"name":"Pixeldroid","website":null,"redirect_uri":"urn:ietf:wg:oauth:2.0:oob","client_id":3197,"client_secret":"hhRwLupqUJPghKsZzpZtxNV67g5DBdPYCqW6XE3m","vapid_key":null}"""
|
||||||
|
)))
|
||||||
|
val call: Call<Application> = PixelfedAPI.create("http://localhost:8089")
|
||||||
|
.registerApplication("Pixeldroid", "urn:ietf:wg:oauth:2.0:oob", "read write follow")
|
||||||
|
val application: Application = call.execute().body()!!
|
||||||
|
assertEquals("3197", application.client_id)
|
||||||
|
assertEquals("hhRwLupqUJPghKsZzpZtxNV67g5DBdPYCqW6XE3m", application.client_secret)
|
||||||
|
assertEquals("Pixeldroid", application.name)
|
||||||
|
assertEquals(null, application.website)
|
||||||
|
assertEquals(null, application.vapid_key)
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun obtainToken(){
|
||||||
|
stubFor(
|
||||||
|
post(urlEqualTo("/oauth/token"))
|
||||||
|
.willReturn(
|
||||||
|
aResponse()
|
||||||
|
.withStatus(200)
|
||||||
|
.withHeader("Content-Type", "application/json")
|
||||||
|
.withBody("""{
|
||||||
|
"access_token": "ZA-Yj3aBD8U8Cm7lKUp-lm9O9BmDgdhHzDeqsY8tlL0",
|
||||||
|
"token_type": "Bearer",
|
||||||
|
"scope": "read write follow push",
|
||||||
|
"created_at": 1573979017
|
||||||
|
}"""
|
||||||
|
)))
|
||||||
|
val OAUTH_SCHEME = "oauth2redirect"
|
||||||
|
val SCOPE = "read write follow"
|
||||||
|
val PACKAGE_ID = "com.h.pixeldroid"
|
||||||
|
val call: Call<Token> = PixelfedAPI.create("http://localhost:8089")
|
||||||
|
.obtainToken("123", "ssqdfqsdfqds", "$OAUTH_SCHEME://$PACKAGE_ID", SCOPE, "abc",
|
||||||
|
"authorization_code")
|
||||||
|
val token: Token = call.execute().body()!!
|
||||||
|
assertEquals("ZA-Yj3aBD8U8Cm7lKUp-lm9O9BmDgdhHzDeqsY8tlL0", token.access_token)
|
||||||
|
assertEquals("Bearer", token.token_type)
|
||||||
|
assertEquals("read write follow push", token.scope)
|
||||||
|
assertEquals(1573979017, token.created_at)
|
||||||
|
assertEquals(Token("ZA-Yj3aBD8U8Cm7lKUp-lm9O9BmDgdhHzDeqsY8tlL0", "Bearer", "read write follow push",1573979017), token)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,17 +0,0 @@
|
|||||||
package com.h.pixeldroid
|
|
||||||
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
|
||||||
*
|
|
||||||
* See [testing documentation](http://d.android.com/tools/testing).
|
|
||||||
*/
|
|
||||||
class ExampleUnitTest {
|
|
||||||
@Test
|
|
||||||
fun addition_isCorrect() {
|
|
||||||
assertEquals(4, 2 + 2)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user