Implements swipe motion & fragmentalize (#41)
* implements swipe motion add a new class to implement swipe motion add the swipe right from home page to display settings passed the homepage in a fragment * transform profile activity into fragment transformed profile activity and layout into fragment linked it with a swipe motion * refactor settings drawer tests * added more tests and refactored some files * added animations to the sliding of the swipe motion
This commit is contained in:
parent
f124af3800
commit
de314dc9de
@ -71,6 +71,7 @@ dependencies {
|
||||
}
|
||||
implementation "com.github.bumptech.glide:okhttp-integration:4.11.0"
|
||||
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
testImplementation "com.github.tomakehurst:wiremock-jre8:2.26.3"
|
||||
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
|
||||
testImplementation 'junit:junit:4.13'
|
||||
|
25
app/src/androidTest/java/com/h/pixeldroid/BottomMenuTest.kt
Normal file
25
app/src/androidTest/java/com/h/pixeldroid/BottomMenuTest.kt
Normal file
@ -0,0 +1,25 @@
|
||||
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.isDisplayed
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class BottomMenuTest {
|
||||
@get:Rule
|
||||
var activityRule: ActivityScenarioRule<MainActivity>
|
||||
= ActivityScenarioRule(MainActivity::class.java)
|
||||
|
||||
@Test
|
||||
fun testFollowersTextView() {
|
||||
onView(withId(R.id.activity_main_account_btn)).perform(click())
|
||||
onView(withId(R.id.profile_main_container)).check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
@ -2,12 +2,10 @@ package com.h.pixeldroid
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
|
@ -12,11 +12,15 @@ 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.espresso.matcher.ViewMatchers.hasErrorText
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||
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.CoreMatchers.allOf
|
||||
import org.hamcrest.CoreMatchers.anyOf
|
||||
import org.hamcrest.CoreMatchers.containsString
|
||||
import org.hamcrest.Matcher
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
@ -39,26 +43,27 @@ class LoginInstrumentedTest {
|
||||
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(
|
||||
@ -75,6 +80,7 @@ class LoginCheckIntent {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AfterIntent {
|
||||
|
||||
@ -87,6 +93,7 @@ class AfterIntent {
|
||||
val intent = Intent(ACTION_VIEW, Uri.parse("oauth2redirect://com.h.pixeldroid?code=sdfdqsf"))
|
||||
launchedActivity = rule.launchActivity(intent)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun usesIntent() {
|
||||
|
||||
|
@ -3,15 +3,16 @@ 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.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.hamcrest.Matchers.not
|
||||
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.lang.Thread.sleep
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ProfileTest {
|
||||
@ -19,10 +20,14 @@ class ProfileTest {
|
||||
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")))
|
||||
@Before
|
||||
fun openProfileFragment() {
|
||||
onView(withId(R.id.activity_main_account_btn)).perform(click())
|
||||
}
|
||||
|
||||
}
|
||||
@Test
|
||||
fun randomUsernameCorrectlyLoadedTest() {
|
||||
Thread.sleep(5000) // wait for the username to load (to modify once we know how)
|
||||
onView(withId(R.id.accountName)).check(matches(not(withText(R.string.no_username))))
|
||||
}
|
||||
}
|
@ -1,16 +1,14 @@
|
||||
package com.h.pixeldroid
|
||||
|
||||
import android.view.Gravity
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.Espresso.pressBack
|
||||
import androidx.test.espresso.action.ViewActions
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.contrib.DrawerActions
|
||||
import androidx.test.espresso.contrib.DrawerMatchers.isClosed
|
||||
import androidx.test.espresso.contrib.NavigationViewActions
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@ -22,47 +20,25 @@ class SettingsTest {
|
||||
var activityRule: ActivityScenarioRule<MainActivity>
|
||||
= ActivityScenarioRule(MainActivity::class.java)
|
||||
|
||||
@Test
|
||||
fun testDrawerSettingsButton() {
|
||||
// Open Drawer to click on navigation.
|
||||
onView(withId(R.id.drawer_layout))
|
||||
.check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed.
|
||||
.perform(DrawerActions.open()); // Open Drawer
|
||||
|
||||
// Start the screen of the activity.
|
||||
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_settings))
|
||||
|
||||
// Check that settings activity was opened.
|
||||
onView(withText(R.string.signature_title)).check(matches(isDisplayed()))
|
||||
@Before
|
||||
fun openDrawer() {
|
||||
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDrawerProfileButton() {
|
||||
// Open Drawer to click on navigation.
|
||||
onView(withId(R.id.drawer_layout))
|
||||
.check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed.
|
||||
.perform(DrawerActions.open()); // Open Drawer
|
||||
|
||||
// Start the screen of the activity.
|
||||
fun myProfileButtonTest() {
|
||||
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_account))
|
||||
|
||||
// Check that profile activity was opened.
|
||||
onView(withId(R.id.posts)).check(matches(withText("Posts")))
|
||||
onView(withId(R.id.profile_main_container)).check(matches(isDisplayed()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnBackPressed() {
|
||||
// Open Drawer to click on navigation.
|
||||
onView(withId(R.id.drawer_layout))
|
||||
.check(matches(isClosed(Gravity.LEFT))) // Left Drawer should be closed.
|
||||
.perform(DrawerActions.open()); // Open Drawer
|
||||
|
||||
// Start the screen of your activity.
|
||||
fun settingsButtonTest() {
|
||||
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_settings))
|
||||
onView(withId(R.id.settings)).check(matches(isDisplayed()))
|
||||
}
|
||||
|
||||
onView(withId(R.id.settings)).perform(ViewActions.pressBack())
|
||||
|
||||
// Check that profile activity was opened.
|
||||
onView(withId(R.id.button_start_login)).check(matches(withText("start login")))
|
||||
@Test
|
||||
fun accessibilityButtonTest() {
|
||||
// TODO if some accessibility view is added
|
||||
}
|
||||
}
|
33
app/src/androidTest/java/com/h/pixeldroid/SwipeTest.kt
Normal file
33
app/src/androidTest/java/com/h/pixeldroid/SwipeTest.kt
Normal file
@ -0,0 +1,33 @@
|
||||
package com.h.pixeldroid
|
||||
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.swipeLeft
|
||||
import androidx.test.espresso.action.ViewActions.swipeRight
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SwipeTest {
|
||||
@get:Rule
|
||||
var activityRule: ActivityScenarioRule<MainActivity>
|
||||
= ActivityScenarioRule(MainActivity::class.java)
|
||||
|
||||
@Test
|
||||
fun swipingRightOnHomepageShowsSettings() {
|
||||
onView(withId(R.id.main_linear_layout)).perform(swipeRight())
|
||||
onView(withId(R.id.nav_view)).check(matches(isDisplayed()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun swipeLeftOnHomePageShowsProfile() {
|
||||
// to modify when we add more tabs
|
||||
onView(withId(R.id.main_linear_layout)).perform(swipeLeft())
|
||||
onView(withId(R.id.profile_main_container)).check(matches(isDisplayed()))
|
||||
}
|
||||
}
|
@ -41,11 +41,6 @@
|
||||
android:scheme="@string/auth_scheme" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ProfileActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".MainActivity"/>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
|
||||
|
@ -6,7 +6,6 @@ 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
|
||||
|
@ -3,13 +3,18 @@ package com.h.pixeldroid
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.h.pixeldroid.fragments.HomeFragment
|
||||
import com.h.pixeldroid.fragments.ProfileFragment
|
||||
import com.h.pixeldroid.motions.OnSwipeListener
|
||||
|
||||
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
|
||||
|
||||
@ -19,20 +24,49 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
val mainLinearLayout : LinearLayout = findViewById(R.id.main_linear_layout)
|
||||
val homepageButton : ImageButton = findViewById(R.id.activity_main_home_btn)
|
||||
val accountButton : ImageButton = findViewById(R.id.activity_main_account_btn)
|
||||
|
||||
homepageButton.setOnClickListener {
|
||||
launchFragment(HomeFragment())
|
||||
}
|
||||
accountButton.setOnClickListener {
|
||||
launchFragment(ProfileFragment())
|
||||
}
|
||||
|
||||
// Setup the drawer
|
||||
drawerLayout = findViewById(R.id.drawer_layout)
|
||||
val navigationView: NavigationView = findViewById(R.id.nav_view)
|
||||
navigationView.setNavigationItemSelectedListener(this)
|
||||
|
||||
val buttonLogin = findViewById<Button>(R.id.button_start_login)
|
||||
buttonLogin.setOnClickListener((View.OnClickListener {
|
||||
val intent = Intent(this, LoginActivity::class.java)
|
||||
startActivity(intent) }))
|
||||
val onSwipeListener = object: OnSwipeListener(this) {
|
||||
override fun onSwipeRight() = swipeRight()
|
||||
override fun onSwipeLeft() = swipeLeft()
|
||||
}
|
||||
mainLinearLayout.setOnTouchListener(onSwipeListener)
|
||||
|
||||
val button = findViewById<Button>(R.id.button)
|
||||
button.setOnClickListener((View.OnClickListener {
|
||||
val intent = Intent(this, ProfileActivity::class.java)
|
||||
startActivity(intent) }))
|
||||
// default fragment that displays when we open the app
|
||||
launchFragment(HomeFragment())
|
||||
}
|
||||
|
||||
private fun swipeRight() {
|
||||
// TODO: correctly switch between tabs
|
||||
drawerLayout.openDrawer(GravityCompat.START)
|
||||
}
|
||||
|
||||
private fun swipeLeft() {
|
||||
// TODO: correctly switch between tabs
|
||||
supportFragmentManager.beginTransaction()
|
||||
.setCustomAnimations(R.anim.slide_from_right, R.anim.slide_to_left)
|
||||
.replace(R.id.fragment_container, ProfileFragment()).commit()
|
||||
}
|
||||
|
||||
/*
|
||||
Launches the given fragment and put it as the current "activity"
|
||||
*/
|
||||
private fun launchFragment(fragment: Fragment) {
|
||||
supportFragmentManager.beginTransaction().replace(R.id.fragment_container, fragment).commit()
|
||||
}
|
||||
|
||||
/*
|
||||
@ -41,7 +75,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||
override fun onNavigationItemSelected(@NonNull item: MenuItem): Boolean {
|
||||
when (item.itemId){
|
||||
R.id.nav_settings -> launchActivity(SettingsActivity())
|
||||
R.id.nav_account -> launchActivity(ProfileActivity())
|
||||
R.id.nav_account -> launchFragment(ProfileFragment())
|
||||
}
|
||||
|
||||
drawerLayout.closeDrawer(GravityCompat.START)
|
||||
|
29
app/src/main/java/com/h/pixeldroid/fragments/HomeFragment.kt
Normal file
29
app/src/main/java/com/h/pixeldroid/fragments/HomeFragment.kt
Normal file
@ -0,0 +1,29 @@
|
||||
package com.h.pixeldroid.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import com.h.pixeldroid.LoginActivity
|
||||
|
||||
import com.h.pixeldroid.R
|
||||
|
||||
|
||||
class HomeFragment : Fragment() {
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val view: View = inflater.inflate(R.layout.fragment_home, container, false)
|
||||
|
||||
val loginButton: Button = view.findViewById(R.id.button_start_login)
|
||||
loginButton.setOnClickListener {
|
||||
startActivity(Intent(view.context, LoginActivity::class.java))
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
}
|
@ -1,12 +1,20 @@
|
||||
package com.h.pixeldroid
|
||||
package com.h.pixeldroid.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.Typeface
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.h.pixeldroid.LoginActivity
|
||||
|
||||
import com.h.pixeldroid.R
|
||||
import com.h.pixeldroid.api.PixelfedAPI
|
||||
import com.h.pixeldroid.objects.Account
|
||||
import com.h.pixeldroid.objects.Status
|
||||
@ -14,18 +22,19 @@ import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
|
||||
class ProfileActivity : AppCompatActivity() {
|
||||
const val BASE_URL = "https://pixelfed.de/"
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_profile)
|
||||
class ProfileFragment : Fragment() {
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val view: View = inflater.inflate(R.layout.fragment_profile, container, false)
|
||||
|
||||
var statuses: ArrayList<Status>? = null
|
||||
val BASE_URL = "https://pixelfed.de/"
|
||||
var statuses: ArrayList<Status>?
|
||||
|
||||
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>>) {
|
||||
@ -36,7 +45,7 @@ class ProfileActivity : AppCompatActivity() {
|
||||
|
||||
val account = statuses!![0].account
|
||||
|
||||
setContent(account)
|
||||
setContent(view, account)
|
||||
|
||||
}
|
||||
}
|
||||
@ -47,33 +56,34 @@ class ProfileActivity : AppCompatActivity() {
|
||||
}
|
||||
})
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
private fun setContent(account: Account) {
|
||||
private fun setContent(view: View, account: Account) {
|
||||
// ImageView : profile picture
|
||||
val profilePicture = findViewById<ImageView>(R.id.profilePicture)
|
||||
Glide.with(applicationContext).load(account.avatar).into(profilePicture)
|
||||
val profilePicture = view.findViewById<ImageView>(R.id.profilePicture)
|
||||
Glide.with(view.context.applicationContext).load(account.avatar).into(profilePicture)
|
||||
|
||||
// TextView : description / bio
|
||||
val description = findViewById<TextView>(R.id.description)
|
||||
val description = view.findViewById<TextView>(R.id.description)
|
||||
description.text = account.note
|
||||
|
||||
// TextView : account name
|
||||
val accountName = findViewById<TextView>(R.id.accountName)
|
||||
val accountName = view.findViewById<TextView>(R.id.accountName)
|
||||
accountName.text = account.username
|
||||
|
||||
// TextView : number of posts
|
||||
val nbPosts = findViewById<TextView>(R.id.nbPosts)
|
||||
val nbPosts = view.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)
|
||||
val nbFollowers = view.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)
|
||||
val nbFollowing = view.findViewById<TextView>(R.id.nbFollowing)
|
||||
nbFollowing.text = account.following_count.toString()
|
||||
nbFollowing.setTypeface(null, Typeface.BOLD)
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.h.pixeldroid.motions
|
||||
|
||||
import android.content.Context
|
||||
import android.view.GestureDetector
|
||||
import android.view.GestureDetector.SimpleOnGestureListener
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.View.OnTouchListener
|
||||
import kotlin.math.abs
|
||||
|
||||
const val SWIPE_DISTANCE_THRESHOLD: Int = 100
|
||||
const val SWIPE_VELOCITY_THRESHOLD: Int = 100
|
||||
|
||||
/**
|
||||
* Detects left and right swipes across a view.
|
||||
*
|
||||
* inspired from https://stackoverflow.com/questions/4139288/android-how-to-handle-right-to-left-swipe-gestures
|
||||
*/
|
||||
open class OnSwipeListener(context: Context?) : OnTouchListener {
|
||||
|
||||
private val gestureDetector: GestureDetector = GestureDetector(context, GestureListener())
|
||||
|
||||
override fun onTouch(v: View?, event: MotionEvent?): Boolean =
|
||||
gestureDetector.onTouchEvent(event)
|
||||
|
||||
// redefining gesture listener to call our custom functions
|
||||
private inner class GestureListener : SimpleOnGestureListener() {
|
||||
|
||||
override fun onDown(e: MotionEvent): Boolean = true
|
||||
|
||||
override fun onFling(
|
||||
e1: MotionEvent,
|
||||
e2: MotionEvent,
|
||||
velocityX: Float,
|
||||
velocityY: Float
|
||||
): Boolean {
|
||||
val distanceX = e2.x - e1.x
|
||||
val distanceY = e2.y - e1.y
|
||||
if (abs(distanceX) > abs(distanceY) // swipe on the side and not up or down
|
||||
&& abs(distanceX) > SWIPE_DISTANCE_THRESHOLD
|
||||
&& abs(velocityX) > SWIPE_VELOCITY_THRESHOLD
|
||||
) {
|
||||
if (distanceX > 0) onSwipeRight() else onSwipeLeft()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open fun onSwipeLeft() {}
|
||||
|
||||
open fun onSwipeRight() {}
|
||||
}
|
8
app/src/main/res/anim/slide_from_left.xml
Normal file
8
app/src/main/res/anim/slide_from_left.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromXDelta="-100%p"
|
||||
android:toXDelta="0"
|
||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
|
||||
android:duration="@integer/swipe_animation_duration"/>
|
||||
</set>
|
8
app/src/main/res/anim/slide_from_right.xml
Normal file
8
app/src/main/res/anim/slide_from_right.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromXDelta="100%p"
|
||||
android:toXDelta="0"
|
||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
|
||||
android:duration="@integer/swipe_animation_duration"/>
|
||||
</set>
|
8
app/src/main/res/anim/slide_to_left.xml
Normal file
8
app/src/main/res/anim/slide_to_left.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromXDelta="0"
|
||||
android:toXDelta="-100%p"
|
||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
|
||||
android:duration="@integer/swipe_animation_duration"/>
|
||||
</set>
|
8
app/src/main/res/anim/slide_to_right.xml
Normal file
8
app/src/main/res/anim/slide_to_right.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromXDelta="0"
|
||||
android:toXDelta="100%p"
|
||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
|
||||
android:duration="@integer/swipe_animation_duration"/>
|
||||
</set>
|
5
app/src/main/res/drawable/ic_home_white_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_home_white_24dp.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_person_white_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_person_white_24dp.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||
</vector>
|
6
app/src/main/res/drawable/ic_photo_camera_white_24dp.xml
Normal file
6
app/src/main/res/drawable/ic_photo_camera_white_24dp.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
|
||||
<path android:fillColor="#FF000000" android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_search_white_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_search_white_24dp.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_star_white_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_star_white_24dp.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
|
||||
</vector>
|
@ -7,28 +7,72 @@
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:openDrawer="start"
|
||||
tools:context=".MainActivity">
|
||||
tools:context="com.h.pixeldroid.MainActivity">
|
||||
|
||||
<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">
|
||||
android:id="@+id/main_linear_layout">
|
||||
|
||||
<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" />
|
||||
<FrameLayout
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Show a profile" />
|
||||
android:background="@color/colorPrimary"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/activity_main_home_btn"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:color/transparent"
|
||||
android:padding="10dp"
|
||||
app:srcCompat="@drawable/ic_home_white_24dp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/activity_main_search_btn"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="10dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:srcCompat="@drawable/ic_search_white_24dp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/activity_main_camera_btn"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="10dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:srcCompat="@drawable/ic_photo_camera_white_24dp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/activity_main_favorite_btn"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="10dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:srcCompat="@drawable/ic_star_white_24dp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/activity_main_account_btn"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:color/transparent"
|
||||
app:srcCompat="@drawable/ic_person_white_24dp" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
@ -40,6 +84,5 @@
|
||||
app:headerLayout="@layout/nav_header"
|
||||
app:menu="@menu/activity_main_drawer" />
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
23
app/src/main/res/layout/fragment_home.xml
Normal file
23
app/src/main/res/layout/fragment_home.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".fragments.HomeFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_start_login"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/start_login" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
@ -4,7 +4,8 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ProfileActivity">
|
||||
android:id="@+id/profile_main_container"
|
||||
tools:context=".fragments.ProfileFragment">
|
||||
|
||||
|
||||
<ImageView
|
||||
@ -27,16 +28,6 @@
|
||||
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"
|
||||
@ -47,6 +38,16 @@
|
||||
app:layout_constraintStart_toStartOf="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/followers"
|
||||
android:layout_width="65dp"
|
||||
@ -83,7 +84,7 @@
|
||||
android:layout_width="156dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:text="No Username"
|
||||
android:text="@string/no_username"
|
||||
app:layout_constraintStart_toStartOf="@+id/profilePicture"
|
||||
app:layout_constraintTop_toBottomOf="@+id/profilePicture" />
|
||||
|
4
app/src/main/res/values/integers.xml
Normal file
4
app/src/main/res/values/integers.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<integer name="swipe_animation_duration">300</integer>
|
||||
</resources>
|
@ -53,4 +53,9 @@
|
||||
<string name="attachment_summary_on">Automatically download attachments for incoming emails
|
||||
</string>
|
||||
<string name="attachment_summary_off">Only download attachments when manually requested</string>
|
||||
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
<string name="start_login">Start Login</string>
|
||||
<string name="no_username">No Username</string>
|
||||
</resources>
|
||||
|
@ -0,0 +1,20 @@
|
||||
package com.h.pixeldroid
|
||||
|
||||
import com.h.pixeldroid.motions.OnSwipeListener
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class OnSwipeListenerUnitTest {
|
||||
|
||||
@Test
|
||||
fun undefinedSwipeRightDoesNothingTest() {
|
||||
val swipeListener = OnSwipeListener(null)
|
||||
assertEquals(Unit, swipeListener.onSwipeRight())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun undefinedSwipeLeftDoesNothingTest() {
|
||||
val swipeListener = OnSwipeListener(null)
|
||||
assertEquals(Unit, swipeListener.onSwipeLeft())
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user