multiAccount functionnality (#168)

* multiAccount functionnality

* remove sharedpreferences usages

* start fixing tests to work with changes

* remove test of removed functionality

* more fiddling with tests

* fix instance insert being broken

* clean up some more preferences usage

* close db

* try to fix a bunch of issues

* move db close

* add instance to user drawer item

* remove rule that is no longer needed

* correct mock server to fix test

* removed unused stuff

* fix domains not being validated correctly

* update test

* Delete q

* Move image filter application to a thread

* remove unused imports

* remove unused strings

* remove unused strings

* fix buttons (sometimes)

* solve some linter issues, fix saturation brightness contrast not being shown properly

* remove unused strings

* add tests for drawer

* remove unused imports, other linter suggestions

* fix broken auto linter fix
This commit is contained in:
Wv5twkFEKh54vo4tta9yu7dHa3 2020-05-19 09:49:34 +02:00 committed by GitHub
parent d4c026ab44
commit ca307abcde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 715 additions and 928 deletions

View File

@ -113,6 +113,19 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
implementation "com.mikepenz:materialdrawer:8.0.3"
//required support lib modules
implementation "androidx.annotation:annotation:1.1.0"
// Add for NavController support
implementation "com.mikepenz:materialdrawer-nav:8.0.3"
//iconics
implementation "com.mikepenz:materialdrawer-iconics:8.0.3"
implementation 'com.mikepenz:google-material-typeface:3.0.1.4.original-kotlin@aar'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:rules:1.2.0'
@ -129,7 +142,7 @@ dependencies {
// CameraX View class
implementation 'androidx.camera:camera-view:1.0.0-alpha10'
implementation 'com.karumi:dexter:6.1.0'
implementation 'com.karumi:dexter:6.1.2'
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'

View File

@ -1,14 +1,12 @@
package com.h.pixeldroid
import android.Manifest
import android.content.ContentValues
import android.content.Intent
import android.content.Intent.ACTION_CHOOSER
import android.graphics.Bitmap
import android.graphics.Color
import android.media.MediaScannerConnection
import android.os.Environment
import android.provider.MediaStore
import android.webkit.MimeTypeMap
import androidx.fragment.app.testing.launchFragmentInContainer
import androidx.test.espresso.intent.Intents
@ -24,7 +22,6 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import java.io.File
import java.io.OutputStream
class CameraTest {
@ -51,7 +48,7 @@ class CameraTest {
fun takePictureButton() {
var scenario = launchFragmentInContainer<CameraFragment>()
scenario.onFragment { _ ->
scenario.onFragment {
val image = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888)
image.eraseColor(Color.GREEN)
val folder =

View File

@ -1,22 +1,22 @@
package com.h.pixeldroid
import android.content.Context
import android.view.Gravity
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
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.contrib.DrawerActions
import androidx.test.espresso.contrib.DrawerMatchers
import androidx.test.espresso.contrib.NavigationViewActions
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.uiautomator.UiDevice
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.InstanceDatabaseEntity
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.testUtility.MockServer
import com.h.pixeldroid.utils.DBUtils
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ -27,21 +27,41 @@ import org.junit.runner.RunWith
class DrawerMenuTest {
private val mockServer = MockServer()
private lateinit var db: AppDatabase
private lateinit var context: Context
@get:Rule
var globalTimeout: Timeout = Timeout.seconds(30)
@get:Rule
var activityRule: ActivityScenarioRule<MainActivity>
= ActivityScenarioRule(MainActivity::class.java)
@Before
fun before(){
mockServer.start()
val baseUrl = mockServer.getUrl()
val preferences = InstrumentationRegistry.getInstrumentation()
.targetContext.getSharedPreferences("com.h.pixeldroid.pref", Context.MODE_PRIVATE)
preferences.edit().putString("accessToken", "azerty").apply()
preferences.edit().putString("domain", baseUrl.toString()).apply()
context = ApplicationProvider.getApplicationContext()
db = DBUtils.initDB(context)
db.clearAllTables()
db.instanceDao().insertInstance(
InstanceDatabaseEntity(
uri = baseUrl.toString(),
title = "PixelTest"
)
)
db.userDao().insertUser(
UserDatabaseEntity(
user_id = "123",
instance_uri = baseUrl.toString(),
username = "Testi",
display_name = "Testi Testo",
avatar_static = "some_avatar_url",
isActive = true,
accessToken = "token"
)
)
db.close()
// Open Drawer to click on navigation.
ActivityScenario.launch(MainActivity::class.java)
onView(withId(R.id.drawer_layout))
@ -49,10 +69,10 @@ class DrawerMenuTest {
.perform(DrawerActions.open()) // Open Drawer
}
@Test
@Test
fun testDrawerSettingsButton() {
// Start the screen of your activity.
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_settings))
onView(withText(R.string.menu_settings)).perform(click())
// Check that settings activity was opened.
onView(withText(R.string.theme_title)).check(matches(isDisplayed()))
}
@ -60,7 +80,7 @@ class DrawerMenuTest {
@Test
fun testThemeSettings() {
// Start the screen of your activity.
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_settings))
onView(withText(R.string.menu_settings)).perform(click())
val themes = getInstrumentation().targetContext.resources.getStringArray(R.array.theme_entries)
//select theme modes
onView(withText(R.string.theme_title)).perform(click())
@ -81,7 +101,7 @@ class DrawerMenuTest {
@Test
fun testDrawerLogoutButton() {
// Start the screen of your activity.
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_logout))
onView(withText(R.string.logout)).perform(click())
// Check that settings activity was opened.
onView(withId(R.id.connect_instance_button)).check(matches(isDisplayed()))
}
@ -89,38 +109,38 @@ class DrawerMenuTest {
@Test
fun testDrawerProfileButton() {
// Start the screen of your activity.
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_account))
onView(withText(R.string.menu_account)).perform(click())
// Check that profile activity was opened.
onView(withId(R.id.profilePictureImageView)).check(matches(isDisplayed()))
}
@Test
/*@Test
fun testDrawerAvatarClick() {
// Start the screen of your activity.
onView(withId(R.id.drawer_avatar)).perform(ViewActions.click())
onView(withText(R.string.menu_account)).perform(click())
// Check that profile activity was opened.
onView(withId(R.id.profilePictureImageView)).check(matches(isDisplayed()))
}
}*/
@Test
/*@Test
fun testDrawerAccountNameClick() {
// Start the screen of your activity.
onView(withId(R.id.drawer_account_name)).perform(ViewActions.click())
onView(withText("Testi")).perform(click())
// Check that profile activity was opened.
onView(withId(R.id.profilePictureImageView)).check(matches(isDisplayed()))
}
onView(withText("Add Account")).check(matches(isDisplayed()))
}*/
@Test
fun clickFollowers() {
// Open My Profile from drawer
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_account))
onView(withText(R.string.menu_account)).perform(click())
Thread.sleep(1000)
// Open followers list
onView(withId(R.id.nbFollowersTextView)).perform(ViewActions.click())
onView(withId(R.id.nbFollowersTextView)).perform(click())
Thread.sleep(1000)
// Open follower's profile
onView(withText("ete2")).perform(ViewActions.click())
onView(withText("ete2")).perform(click())
Thread.sleep(1000)
onView(withId(R.id.accountNameTextView)).check(matches(withText("Christian")))
@ -129,13 +149,13 @@ class DrawerMenuTest {
@Test
fun clickFollowing() {
// Open My Profile from drawer
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_account))
onView(withText(R.string.menu_account)).perform(click())
Thread.sleep(1000)
// Open followers list
onView(withId(R.id.nbFollowingTextView)).perform(ViewActions.click())
onView(withId(R.id.nbFollowingTextView)).perform(click())
Thread.sleep(1000)
// Open following's profile
onView(withText("Dobios")).perform(ViewActions.click())
onView(withText("Dobios")).perform(click())
Thread.sleep(1000)
onView(withId(R.id.accountNameTextView)).check(matches(withText("Andrew Dobis")))

View File

@ -1,6 +1,5 @@
package com.h.pixeldroid
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.view.View
@ -20,7 +19,6 @@ import androidx.test.rule.GrantPermissionRule
import com.google.android.material.tabs.TabLayout
import com.h.pixeldroid.adapters.ThumbnailAdapter
import com.h.pixeldroid.testUtility.CustomMatchers
import com.h.pixeldroid.testUtility.MockServer
import kotlinx.android.synthetic.main.fragment_edit_image.*
import org.hamcrest.CoreMatchers.allOf
import org.junit.Assert
@ -33,7 +31,6 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class EditPhotoTest {
private val mockServer = MockServer()
private lateinit var activity: PhotoEditActivity
private lateinit var activityScenario: ActivityScenario<PhotoEditActivity>
@ -46,11 +43,6 @@ class EditPhotoTest {
@Before
fun before() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
mockServer.start()
val baseUrl = mockServer.getUrl()
val preferences = context.getSharedPreferences("com.h.pixeldroid.pref", Context.MODE_PRIVATE)
preferences.edit().putString("accessToken", "azerty").apply()
preferences.edit().putString("domain", baseUrl.toString()).apply()
// Launch PhotoEditActivity
val uri: Uri = Uri.parse("android.resource://com.h.pixeldroid/drawable/index")

View File

@ -4,32 +4,29 @@ import android.content.Context
import android.content.Intent
import android.text.SpannableString
import android.text.style.ClickableSpan
import android.view.Gravity
import android.view.View
import android.widget.TextView
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso
import androidx.test.espresso.NoMatchingViewException
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.assertion.ViewAssertions
import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.contrib.DrawerMatchers
import androidx.test.espresso.contrib.NavigationViewActions
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.matcher.IntentMatchers
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
import com.google.android.material.tabs.TabLayout
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.InstanceDatabaseEntity
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.fragments.feeds.PostViewHolder
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.objects.Account.Companion.ACCOUNT_TAG
import com.h.pixeldroid.testUtility.MockServer
import com.h.pixeldroid.utils.DBUtils
import org.hamcrest.CoreMatchers
import org.hamcrest.Matcher
import org.hamcrest.Matchers
@ -45,6 +42,8 @@ import org.junit.runner.RunWith
class IntentTest {
private val mockServer = MockServer()
private lateinit var db: AppDatabase
private lateinit var context: Context
@get:Rule
var globalTimeout: Timeout = Timeout.seconds(100)
@ -59,10 +58,30 @@ class IntentTest {
fun before() {
mockServer.start()
val baseUrl = mockServer.getUrl()
val preferences = InstrumentationRegistry.getInstrumentation()
.targetContext.getSharedPreferences("com.h.pixeldroid.pref", Context.MODE_PRIVATE)
preferences.edit().putString("accessToken", "azerty").apply()
preferences.edit().putString("domain", baseUrl.toString()).apply()
context = ApplicationProvider.getApplicationContext()
db = DBUtils.initDB(context)
db.clearAllTables()
db.instanceDao().insertInstance(
InstanceDatabaseEntity(
uri = baseUrl.toString(),
title = "PixelTest"
)
)
db.userDao().insertUser(
UserDatabaseEntity(
user_id = "123",
instance_uri = baseUrl.toString(),
username = "Testi",
display_name = "Testi Testo",
avatar_static = "some_avatar_url",
isActive = true,
accessToken = "token"
)
)
db.close()
Intents.init()
}
@ -145,14 +164,15 @@ class IntentTest {
}
}
@Test
/*@Test
fun launchesIntent() {
// Open Drawer to click on navigation.
ActivityScenario.launch(MainActivity::class.java)
Espresso.onView(ViewMatchers.withId(R.id.drawer_layout))
.check(ViewAssertions.matches(DrawerMatchers.isClosed(Gravity.LEFT))) // Left Drawer should be closed.
.perform(DrawerActions.open()) // Open Drawer
Espresso.onView(ViewMatchers.withId(R.id.nav_view))
Espresso.onView(ViewMatchers.withId(R.id.drawer))
.perform(NavigationViewActions.navigateTo(R.id.nav_account))
val expectedIntent: Matcher<Intent> = CoreMatchers.allOf(
@ -166,7 +186,7 @@ class IntentTest {
Thread.sleep(1000)
intended(expectedIntent)
}
} */
@After
fun after() {

View File

@ -1,37 +1,20 @@
package com.h.pixeldroid
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_VIEW
import android.net.Uri
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.scrollTo
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.intent.Intents
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.matcher.ViewMatchers.hasErrorText
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
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.platform.app.InstrumentationRegistry
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.rule.ActivityTestRule
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import com.h.pixeldroid.db.InstanceDatabaseEntity
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.utils.DBUtils
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.CoreMatchers.anyOf
import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.Matcher
import org.junit.After

View File

@ -4,21 +4,15 @@ import android.content.Context
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.InstanceDatabaseEntity
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.utils.DBUtils
import kotlinx.android.synthetic.main.activity_login.login_activity_instance_chooser_button
import org.junit.After
import org.junit.Before
import org.junit.Rule
@ -45,6 +39,7 @@ class LoginActivityOfflineTest {
val context = ApplicationProvider.getApplicationContext<Context>()
db = DBUtils.initDB(context)
db.clearAllTables()
db.close()
}
@Test
@ -53,26 +48,6 @@ class LoginActivityOfflineTest {
onView(withId(R.id.login_activity_connection_required_text)).check(matches(isDisplayed()))
}
@Test
fun offlineModeSelectAvailabeLaunchesMainActivityWithStoredAccountInstance() {
db.instanceDao().insertInstance(
InstanceDatabaseEntity(
uri = "some_uri",
title = "PixelTest"
))
db.userDao().insertUser(
UserDatabaseEntity(
user_id = "some_user_id",
instance_uri = "some_uri",
username = "Testi",
display_name = "Testi Testo",
avatar_static = "some_avatar_url"
))
ActivityScenario.launch(LoginActivity::class.java)
onView(withId(R.id.login_activity_instance_chooser_button)).perform(click())
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open())
onView(withId(R.id.drawer_account_name)).check(matches(withText("Testi Testo")))
}
@After
fun after() {

View File

@ -47,27 +47,7 @@ class LoginActivityOnlineTest {
pref.edit().clear().apply()
db = DBUtils.initDB(context)
db.clearAllTables()
}
@Test
fun connectToSavedAccount() {
db.instanceDao().insertInstance(
InstanceDatabaseEntity(
uri = "some_uri",
title = "PixelTest"
)
)
db.userDao().insertUser(
UserDatabaseEntity(
user_id = "some_user_id",
instance_uri = "some_uri",
username = "Testi",
display_name = "Testi Testo",
avatar_static = "some_avatar_url"
)
)
ActivityScenario.launch(LoginActivity::class.java)
onView(withId(R.id.login_activity_instance_chooser_button)).perform(click())
db.close()
}
@Test
@ -85,7 +65,7 @@ class LoginActivityOnlineTest {
ActivityScenario.launch(LoginActivity::class.java)
onView(withId(R.id.connect_instance_button)).perform(click())
onView(withId(R.id.editText)).check(matches(
hasErrorText(context.getString(R.string.login_empty_string_error))
hasErrorText(context.getString(R.string.invalid_domain))
))
}
@ -116,8 +96,30 @@ class LoginActivityOnlineTest {
@Test
fun correctIntentReturnLoadsMainActivity() {
context = ApplicationProvider.getApplicationContext()
db = DBUtils.initDB(context)
db.clearAllTables()
db.instanceDao().insertInstance(
InstanceDatabaseEntity(
uri = server.getUrl().toString(),
title = "PixelTest"
)
)
db.userDao().insertUser(
UserDatabaseEntity(
user_id = "123",
instance_uri = server.getUrl().toString(),
username = "Testi",
display_name = "Testi Testo",
avatar_static = "some_avatar_url",
isActive = true,
accessToken = "token"
)
)
db.close()
pref.edit()
.putString("accessToken", "azerty")
.putString("domain", server.getUrl().toString())
.putString("clientID", "test_id")
.putString("clientSecret", "test_secret")
@ -125,6 +127,7 @@ class LoginActivityOnlineTest {
val uri = Uri.parse("oauth2redirect://com.h.pixeldroid?code=test_code")
val intent = Intent(ACTION_VIEW, uri, context, LoginActivity::class.java)
ActivityScenario.launch<LoginActivity>(intent)
Thread.sleep(1000)
onView(withId(R.id.main_activity_main_linear_layout)).check(matches(isDisplayed()))
}
}

View File

@ -1,15 +1,11 @@
package com.h.pixeldroid
import android.graphics.ColorMatrix
import android.content.Context
import android.view.View.GONE
import android.view.View.VISIBLE
import android.graphics.ColorMatrix
import android.widget.TextView
import androidx.core.view.get
import androidx.core.view.isVisible
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onData
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.action.ViewActions.click
@ -17,10 +13,11 @@ import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition
import androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.google.android.material.tabs.TabLayout
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.InstanceDatabaseEntity
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.fragments.feeds.PostViewHolder
import com.h.pixeldroid.testUtility.CustomMatchers.Companion.clickChildViewWithId
import com.h.pixeldroid.testUtility.CustomMatchers.Companion.first
@ -29,14 +26,9 @@ import com.h.pixeldroid.testUtility.CustomMatchers.Companion.second
import com.h.pixeldroid.testUtility.CustomMatchers.Companion.slowSwipeUp
import com.h.pixeldroid.testUtility.CustomMatchers.Companion.typeTextInViewWithId
import com.h.pixeldroid.testUtility.MockServer
import com.h.pixeldroid.utils.DBUtils
import com.h.pixeldroid.utils.PostUtils.Companion.censorColorMatrix
import com.h.pixeldroid.utils.PostUtils.Companion.uncensorColorMatrix
import kotlinx.android.synthetic.main.fragment_feed.*
import kotlinx.android.synthetic.main.fragment_feed.view.*
import kotlinx.android.synthetic.main.post_fragment.*
import kotlinx.android.synthetic.main.post_fragment.view.*
import org.hamcrest.Matchers.`is`
import org.hamcrest.Matchers.not
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ -49,21 +41,38 @@ class MockedServerTest {
private val mockServer = MockServer()
private lateinit var activityScenario: ActivityScenario<MainActivity>
private lateinit var db: AppDatabase
private lateinit var context: Context
@get:Rule
var globalTimeout: Timeout = Timeout.seconds(100)
@get:Rule
var activityRule: ActivityScenarioRule<MainActivity>
= ActivityScenarioRule(MainActivity::class.java)
@Before
fun before(){
mockServer.start()
val baseUrl = mockServer.getUrl()
val preferences = InstrumentationRegistry.getInstrumentation()
.targetContext.getSharedPreferences("com.h.pixeldroid.pref", Context.MODE_PRIVATE)
preferences.edit().putString("accessToken", "azerty").apply()
preferences.edit().putString("domain", baseUrl.toString()).apply()
context = ApplicationProvider.getApplicationContext()
db = DBUtils.initDB(context)
db.clearAllTables()
db.instanceDao().insertInstance(
InstanceDatabaseEntity(
uri = baseUrl.toString(),
title = "PixelTest"
)
)
db.userDao().insertUser(
UserDatabaseEntity(
user_id = "123",
instance_uri = baseUrl.toString(),
username = "Testi",
display_name = "Testi Testo",
avatar_static = "some_avatar_url",
isActive = true,
accessToken = "token"
)
)
db.close()
activityScenario = ActivityScenario.launch(MainActivity::class.java)
}

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
@ -11,7 +12,11 @@ import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.InstanceDatabaseEntity
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.testUtility.MockServer
import com.h.pixeldroid.utils.DBUtils
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ -22,6 +27,8 @@ import org.junit.runner.RunWith
class PostCreationActivityTest {
private val mockServer = MockServer()
private lateinit var db: AppDatabase
@get:Rule
val globalTimeout: Timeout = Timeout.seconds(30)
@ -31,10 +38,27 @@ class PostCreationActivityTest {
val context = InstrumentationRegistry.getInstrumentation().targetContext
mockServer.start()
val baseUrl = mockServer.getUrl()
val preferences = context.getSharedPreferences("com.h.pixeldroid.pref", Context.MODE_PRIVATE)
preferences.edit().putString("accessToken", "azerty").apply()
preferences.edit().putString("domain", baseUrl.toString()).apply()
db = DBUtils.initDB(context)
db.clearAllTables()
db.instanceDao().insertInstance(
InstanceDatabaseEntity(
uri = baseUrl.toString(),
title = "PixelTest"
)
)
db.userDao().insertUser(
UserDatabaseEntity(
user_id = "123",
instance_uri = baseUrl.toString(),
username = "Testi",
display_name = "Testi Testo",
avatar_static = "some_avatar_url",
isActive = true,
accessToken = "token"
)
)
db.close()
val uri: Uri = Uri.parse("android.resource://com.h.pixeldroid/drawable/index")
val intent = Intent(context, PostCreationActivity::class.java)
.putExtra("picture_uri", uri)

View File

@ -16,7 +16,11 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.InstanceDatabaseEntity
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.testUtility.MockServer
import com.h.pixeldroid.utils.DBUtils
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.camera_ui_container.*
import org.hamcrest.Matcher
@ -66,14 +70,35 @@ class PostFragmentUITests {
@get:Rule
var rule = ActivityScenarioRule(MainActivity::class.java)
private lateinit var db: AppDatabase
@Before
fun setup() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
mockServer.start()
val baseUrl = mockServer.getUrl()
val preferences = InstrumentationRegistry.getInstrumentation()
.targetContext.getSharedPreferences("com.h.pixeldroid.pref", Context.MODE_PRIVATE)
preferences.edit().putString("accessToken", "azerty").apply()
preferences.edit().putString("domain", baseUrl.toString()).apply()
db = DBUtils.initDB(context)
db.clearAllTables()
db.instanceDao().insertInstance(
InstanceDatabaseEntity(
uri = baseUrl.toString(),
title = "PixelTest"
)
)
db.userDao().insertUser(
UserDatabaseEntity(
user_id = "123",
instance_uri = baseUrl.toString(),
username = "Testi",
display_name = "Testi Testo",
avatar_static = "some_avatar_url",
isActive = true,
accessToken = "token"
)
)
db.close()
Thread.sleep(300)
}

View File

@ -18,10 +18,14 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.InstanceDatabaseEntity
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.objects.Attachment
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.testUtility.MockServer
import com.h.pixeldroid.utils.DBUtils
import org.hamcrest.CoreMatchers
import org.hamcrest.Matcher
import org.junit.After
@ -36,6 +40,7 @@ import org.junit.runner.RunWith
class PostTest {
private lateinit var context: Context
private lateinit var db: AppDatabase
@get:Rule
var globalTimeout: Timeout = Timeout.seconds(100)
@ -46,11 +51,27 @@ class PostTest {
val mockServer = MockServer()
mockServer.start()
val baseUrl = mockServer.getUrl()
val preferences = context.getSharedPreferences(
"com.h.pixeldroid.pref",
Context.MODE_PRIVATE)
preferences.edit().putString("accessToken", "azerty").apply()
preferences.edit().putString("domain", baseUrl.toString()).apply()
db = DBUtils.initDB(context)
db.clearAllTables()
db.instanceDao().insertInstance(
InstanceDatabaseEntity(
uri = baseUrl.toString(),
title = "PixelTest"
)
)
db.userDao().insertUser(
UserDatabaseEntity(
user_id = "123",
instance_uri = baseUrl.toString(),
username = "Testi",
display_name = "Testi Testo",
avatar_static = "some_avatar_url",
isActive = true,
accessToken = "token"
)
)
db.close()
Intents.init()
}

View File

@ -166,7 +166,7 @@ class JsonValues {
"created_at": 12121212
}"""
const val instanceJson = """{
"uri": "pixeldroid.epfl",
"uri": "REPLACEWITHDOMAIN",
"title": "PixelDroid",
"description": "Test server description.",
"email": "lejeu@epfl.ch",

View File

@ -10,8 +10,8 @@ class MockServer {
companion object{
private val server = MockWebServer()
private val headerName = "Content-Type"
private val headerValue = "application/json; charset=utf-8"
private const val headerName = "Content-Type"
private const val headerValue = "application/json; charset=utf-8"
}
fun start() {
@ -33,7 +33,7 @@ class MockServer {
.setResponseCode(200).setBody(JsonValues.accountJson)
"/api/v1/instance" -> return MockResponse()
.addHeader(headerName, headerValue)
.setResponseCode(200).setBody(JsonValues.instanceJson)
.setResponseCode(200).setBody(JsonValues.instanceJson.replace("REPLACEWITHDOMAIN", getUrl().toString()))
"/api/v1/media" -> return MockResponse()
.addHeader(headerName, headerValue)
.setResponseCode(200).setBody(JsonValues.mediaUploadResponseJson)

View File

@ -1,14 +1,14 @@
package com.h.pixeldroid
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.fragments.feeds.AccountListFragment
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.objects.Account.Companion.ACCOUNT_ID_TAG
import com.h.pixeldroid.objects.Account.Companion.FOLLOWING_TAG
import com.h.pixeldroid.utils.DBUtils
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
@ -25,11 +25,15 @@ class FollowsActivity : AppCompatActivity() {
val following = intent.getSerializableExtra(FOLLOWING_TAG) as Boolean
if(id == null) {
val preferences = this.getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
val pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
val accessToken = preferences.getString("accessToken", "")
val db = DBUtils.initDB(applicationContext)
val user = db.userDao().getActiveUser()
val domain = user?.instance_uri.orEmpty()
val accessToken = user?.accessToken.orEmpty()
db.close()
val pixelfedAPI = PixelfedAPI.create(domain)
pixelfedAPI.verifyCredentials("Bearer $accessToken").enqueue(object :
Callback<Account> {

View File

@ -6,32 +6,22 @@ import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.ArrayAdapter
import android.widget.Toast
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.app.AppCompatActivity
import androidx.browser.customtabs.CustomTabsIntent
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.InstanceDatabaseEntity
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.objects.Application
import com.h.pixeldroid.objects.Instance
import com.h.pixeldroid.objects.Token
import com.h.pixeldroid.utils.DBUtils
import com.h.pixeldroid.utils.DBUtils.Companion.storeInstance
import com.h.pixeldroid.utils.Utils
import kotlinx.android.synthetic.main.activity_login.connect_instance_button
import kotlinx.android.synthetic.main.activity_login.editText
import kotlinx.android.synthetic.main.activity_login.login_activity_connection_required_text
import kotlinx.android.synthetic.main.activity_login.login_activity_instance_chooser
import kotlinx.android.synthetic.main.activity_login.login_activity_instance_chooser_button
import kotlinx.android.synthetic.main.activity_login.login_activity_instance_chooser_layout
import kotlinx.android.synthetic.main.activity_login.login_activity_instance_chooser_offline_text
import kotlinx.android.synthetic.main.activity_login.login_activity_instance_input_layout
import kotlinx.android.synthetic.main.activity_login.progressLayout
import kotlinx.android.synthetic.main.activity_login.whatsAnInstanceTextView
import okhttp3.internal.toImmutableList
import com.h.pixeldroid.utils.Utils.Companion.normalizeDomain
import kotlinx.android.synthetic.main.activity_login.*
import okhttp3.HttpUrl
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
@ -40,7 +30,6 @@ import retrofit2.Response
class LoginActivity : AppCompatActivity() {
companion object {
private const val TAG = "Login Activity"
private const val PACKAGE_ID = BuildConfig.APPLICATION_ID
private const val SCOPE = "read write follow"
}
@ -51,7 +40,6 @@ class LoginActivity : AppCompatActivity() {
private lateinit var db: AppDatabase
private lateinit var pixelfedAPI: PixelfedAPI
private var inputVisibility: Int = View.GONE
private var chooserVisibility: Int = View.GONE
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -63,18 +51,6 @@ class LoginActivity : AppCompatActivity() {
preferences = getSharedPreferences("$PACKAGE_ID.pref", Context.MODE_PRIVATE)
db = DBUtils.initDB(applicationContext)
// check for stored accounts/instances
val accounts: List<Map<String, String>> = getSavedAccounts()
if (accounts.isNotEmpty()) {
displayChooser(accounts)
login_activity_instance_chooser_button.setOnClickListener {
val choice: Int = login_activity_instance_chooser.selectedItemId.toInt()
setPreferences(accounts[choice])
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
}
if (Utils.hasInternet(applicationContext)) {
connect_instance_button.setOnClickListener {
registerAppToServer(normalizeDomain(editText.text.toString()))
@ -82,55 +58,11 @@ class LoginActivity : AppCompatActivity() {
whatsAnInstanceTextView.setOnClickListener{ whatsAnInstance() }
inputVisibility = View.VISIBLE
} else {
if (accounts.isEmpty()) {
login_activity_connection_required_text.visibility = View.VISIBLE
} else {
login_activity_instance_chooser_offline_text.visibility = View.VISIBLE
}
login_activity_connection_required_text.visibility = View.VISIBLE
}
loadingAnimation(false)
}
private fun getSavedAccounts(): List<Map<String, String>> {
val result = mutableListOf<Map<String, String>>()
val instances = db.instanceDao().getAll()
for (user in db.userDao().getAll()) {
val instance = instances.first {instance ->
instance.uri == user.instance_uri
}
result.add(mapOf(
Pair("username", user.username),
Pair("instance_title", instance.title),
Pair("instance_uri", instance.uri),
Pair("id", user.user_id)
))
}
return result.toImmutableList()
}
private fun displayChooser(accounts: List<Map<String, String>>) {
ArrayAdapter(
this,
android.R.layout.simple_spinner_item,
accounts.map { account ->
"${account["username"]}@${account["instance_title"]}"
}).also {
adapter ->
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
login_activity_instance_chooser.adapter = adapter
}
chooserVisibility = View.VISIBLE
}
private fun setPreferences(account: Map<String, String>) {
if (Utils.hasInternet(applicationContext))
registerAppToServer(normalizeDomain(account["instance_uri"].orEmpty()))
else
preferences.edit()
.putString("user_id", account["id"])
.apply()
}
override fun onStart(){
super.onStart()
val url: Uri? = intent.data
@ -148,8 +80,6 @@ class LoginActivity : AppCompatActivity() {
loadingAnimation(false)
}
override fun onBackPressed() {
}
private fun whatsAnInstance() {
val i = Intent(Intent.ACTION_VIEW)
@ -157,18 +87,27 @@ class LoginActivity : AppCompatActivity() {
startActivity(i)
}
private fun normalizeDomain(domain: String): String {
return "https://" + domain
.replace("http://", "")
.replace("https://", "")
.trim(Char::isWhitespace)
private fun hideKeyboard() {
val view = currentFocus
if (view != null) {
(getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(
view.windowToken,
InputMethodManager.HIDE_NOT_ALWAYS
)
}
}
private fun registerAppToServer(normalizedDomain: String) {
try{
HttpUrl.Builder().host(normalizedDomain.replace("https://", "")).scheme("https").build()
} catch (e: IllegalArgumentException) {
return failedRegistration(getString(R.string.invalid_domain))
}
hideKeyboard()
loadingAnimation(true)
if (normalizedDomain.replace("https://", "").isNullOrBlank())
return failedRegistration(getString(R.string.login_empty_string_error))
PixelfedAPI.create(normalizedDomain).registerApplication(
appName,"$oauthScheme://$PACKAGE_ID", SCOPE
).enqueue(object : Callback<Application> {
@ -250,70 +189,67 @@ class LoginActivity : AppCompatActivity() {
private fun authenticationSuccessful(accessToken: String) {
saveUserAndInstance(accessToken)
preferences.edit().putString("accessToken", accessToken).apply()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
wipeSharedSettings()
}
private fun failedRegistration(message: String = getString(R.string.registration_failed)) {
loadingAnimation(false)
editText.error = message
wipeSharedSettings()
}
private fun wipeSharedSettings(){
preferences.edit().remove("domain").remove("clientId").remove("clientSecret")
.apply()
}
private fun loadingAnimation(on: Boolean){
if(on) {
login_activity_instance_input_layout.visibility = View.GONE
login_activity_instance_chooser_layout.visibility = View.GONE
progressLayout.visibility = View.VISIBLE
}
else {
login_activity_instance_input_layout.visibility = inputVisibility
login_activity_instance_chooser_layout.visibility = chooserVisibility
progressLayout.visibility = View.GONE
}
}
private fun saveUserAndInstance(accessToken: String) {
preferences.edit().putInt("max_toot_chars", Instance.DEFAULT_MAX_TOOT_CHARS).apply()
pixelfedAPI.instance().enqueue(object : Callback<Instance> {
override fun onFailure(call: Call<Instance>, t: Throwable) {
return failedRegistration(getString(R.string.instance_error))
}
override fun onResponse(call: Call<Instance>, response: Response<Instance>) {
if (response.isSuccessful && response.body() != null) {
val instance = response.body() as Instance
storeInstance(instance)
storeUser(accessToken)
storeInstance(db, instance)
storeUser(accessToken, instance.uri)
} else {
return failedRegistration(getString(R.string.instance_error))
}
}
})
}
private fun storeInstance(instance: Instance) {
val maxTootChars = instance.max_toot_chars.toInt()
preferences.edit().putInt("max_toot_chars", maxTootChars).apply()
preferences.edit().putString("instance_uri", instance.uri).apply()
val dbInstance = InstanceDatabaseEntity(
uri = instance.uri,
title = instance.title,
max_toot_chars = maxTootChars,
thumbnail = instance.thumbnail
)
db.instanceDao().insertInstance(dbInstance)
}
private fun storeUser(accessToken: String) {
private fun storeUser(accessToken: String, instance: String) {
pixelfedAPI.verifyCredentials("Bearer $accessToken")
.enqueue(object : Callback<Account> {
override fun onResponse(call: Call<Account>, response: Response<Account>) {
if (response.body() != null && response.isSuccessful) {
db.userDao().deActivateActiveUser()
val user = response.body() as Account
preferences.edit().putString("user_id", user.id).apply()
DBUtils.addUser(
db,
user,
preferences.getString("instance_uri", null).orEmpty()
instance,
activeUser = true,
accessToken = accessToken
)
db.close()
val intent = Intent(this@LoginActivity, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
}
}
override fun onFailure(call: Call<Account>, t: Throwable) {

View File

@ -2,58 +2,68 @@ package com.h.pixeldroid
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.view.View
import androidx.annotation.NonNull
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.GravityCompat
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.navigation.NavigationView
import com.bumptech.glide.Glide
import com.google.android.material.tabs.TabLayoutMediator
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.fragments.CameraFragment
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.fragments.CameraFragment
import com.h.pixeldroid.fragments.SearchDiscoverFragment
import com.h.pixeldroid.fragments.feeds.PostsFeedFragment
import com.h.pixeldroid.fragments.feeds.NotificationsFragment
import com.h.pixeldroid.fragments.feeds.OfflineFeedFragment
import com.h.pixeldroid.fragments.feeds.PostsFeedFragment
import com.h.pixeldroid.fragments.feeds.PublicTimelineFragment
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.utils.DBUtils
import com.h.pixeldroid.utils.ImageConverter
import com.h.pixeldroid.utils.Utils.Companion.hasInternet
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.materialdrawer.iconics.iconicsIcon
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
import com.mikepenz.materialdrawer.model.ProfileDrawerItem
import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.*
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader
import com.mikepenz.materialdrawer.widget.AccountHeaderView
import kotlinx.android.synthetic.main.activity_main.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.nav_header.view.drawer_account_name
import kotlinx.android.synthetic.main.nav_header.view.drawer_avatar
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
class MainActivity : AppCompatActivity() {
private lateinit var preferences: SharedPreferences
private val searchDiscoverFragment: SearchDiscoverFragment = SearchDiscoverFragment()
private lateinit var db: AppDatabase
private lateinit var header: AccountHeaderView
private var user: UserDatabaseEntity? = null
companion object {
const val ADD_ACCOUNT_IDENTIFIER: Long = -13
}
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.AppTheme_NoActionBar)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
preferences = getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
db = DBUtils.initDB(applicationContext)
//get the currently active user
user = db.userDao().getActiveUser()
//Check if we have logged in and gotten an access token
if((hasInternet(applicationContext) && !preferences.contains("accessToken"))
|| (!hasInternet(applicationContext) && !preferences.contains("user_id"))) {
launchActivity(LoginActivity())
if (user == null) {
launchActivity(LoginActivity(), firstTime = true)
} else {
setupDrawer()
val tabs = arrayOf(
@ -69,17 +79,102 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}
private fun setupDrawer() {
nav_view.setNavigationItemSelectedListener(this)
header = AccountHeaderView(this).apply {
headerBackgroundScaleType = ImageView.ScaleType.CENTER_CROP
currentHiddenInList = true
onAccountHeaderListener = { _: View?, profile: IProfile, current: Boolean ->
clickProfile(profile, current)
}
addProfile(ProfileSettingDrawerItem().apply {
identifier = ADD_ACCOUNT_IDENTIFIER
nameRes = R.string.add_account_name
descriptionRes = R.string.add_account_description
iconicsIcon = GoogleMaterial.Icon.gmd_add
}, 0)
attachToSliderView(drawer)
dividerBelowHeader = false
closeDrawerOnProfileListClick = true
}
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
Glide.with(imageView.context)
.load(uri)
.placeholder(placeholder)
.into(imageView)
}
override fun cancel(imageView: ImageView) {
Glide.with(imageView.context).clear(imageView)
}
override fun placeholder(ctx: Context, tag: String?): Drawable {
if (tag == DrawerImageLoader.Tags.PROFILE.name || tag == DrawerImageLoader.Tags.PROFILE_DRAWER_ITEM.name) {
return ctx.getDrawable(R.drawable.ic_default_user)!!
}
return super.placeholder(ctx, tag)
}
})
fillDrawerAccountInfo(user!!.user_id)
//after setting with the values in the db, we make sure to update the database and apply
//with the received one. This happens asynchronously.
getUpdatedAccount()
drawer.itemAdapter.add(
primaryDrawerItem {
nameRes = R.string.menu_account
iconicsIcon = GoogleMaterial.Icon.gmd_person
},
primaryDrawerItem {
nameRes = R.string.menu_settings
iconicsIcon = GoogleMaterial.Icon.gmd_settings
},
primaryDrawerItem {
nameRes = R.string.logout
iconicsIcon = GoogleMaterial.Icon.gmd_close
})
drawer.onDrawerItemClickListener = { v, drawerItem, position ->
when (position){
1 -> launchActivity(ProfileActivity())
2 -> launchActivity(SettingsActivity())
3 -> logOut()
}
false
}
}
private fun logOut(){
db.userDao().deleteActiveUsers()
val remainingUsers = db.userDao().getAll()
if (remainingUsers.isEmpty()){
//no more users, start first-time login flow
launchActivity(LoginActivity(), firstTime = true)
} else {
val newActive = remainingUsers.first()
db.userDao().activateUser(newActive.user_id)
//relaunch the app
launchActivity(MainActivity(), firstTime = true)
}
}
private fun getUpdatedAccount(){
if (hasInternet(applicationContext)) {
val accessToken = preferences.getString("accessToken", "")
val pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
val domain = user?.instance_uri.orEmpty()
val accessToken = user?.accessToken.orEmpty()
val pixelfedAPI = PixelfedAPI.create(domain)
pixelfedAPI.verifyCredentials("Bearer $accessToken")
.enqueue(object : Callback<Account> {
override fun onResponse(call: Call<Account>, response: Response<Account>) {
if (response.body() != null && response.isSuccessful) {
val account = response.body() as Account
DBUtils.addUser(db, account)
fillDrawerAccountInfo(account)
DBUtils.addUser(db, account, domain, accessToken = accessToken)
fillDrawerAccountInfo(account.id)
}
}
@ -87,39 +182,73 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
Log.e("DRAWER ACCOUNT:", t.toString())
}
})
} else {
val userId = preferences.getString("user_id", null).orEmpty()
if (userId.isNotEmpty()) {
val user: UserDatabaseEntity = db.userDao().getUserWithId(userId)
val account = Account(
id = user.user_id,
username = user.username,
display_name = user.display_name,
avatar_static = user.avatar_static
)
fillDrawerAccountInfo(account)
} else {
launchActivity(LoginActivity())
}
}
}
private fun fillDrawerAccountInfo(account: Account) {
val drawerAvatar = nav_view.getHeaderView(0).drawer_avatar
val drawerAccountName = nav_view.getHeaderView(0).drawer_account_name
ImageConverter.setRoundImageFromURL(
View(applicationContext),
account.avatar_static,
drawerAvatar
)
drawerAvatar.setOnClickListener { launchActivity(ProfileActivity()) }
// Set account name
drawerAccountName.apply {
text = account.display_name
setOnClickListener { launchActivity(ProfileActivity()) }
//called when switching profiles, or when clicking on current profile
private fun clickProfile(profile: IProfile, current: Boolean): Boolean {
if(current){
launchActivity(ProfileActivity())
return false
}
//Clicked on add new account
if(profile.identifier == ADD_ACCOUNT_IDENTIFIER){
launchActivity(LoginActivity())
return false
}
db.userDao().deActivateActiveUser()
db.userDao().activateUser(profile.identifier.toString())
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
return false
}
private inline fun primaryDrawerItem(block: PrimaryDrawerItem.() -> Unit): PrimaryDrawerItem {
return PrimaryDrawerItem()
.apply {
isSelectable = false
isIconTinted = true
}
.apply(block)
}
private fun fillDrawerAccountInfo(account: String) {
val users = db.userDao().getAll().toMutableList()
users.sortWith(Comparator { l, r ->
when {
l.isActive && !r.isActive -> -1
r.isActive && !l.isActive -> 1
else -> 0
}
})
val profiles: MutableList<IProfile> = users.map { user ->
ProfileDrawerItem().apply {
isSelected = user.isActive
nameText = user.display_name
iconUrl = user.avatar_static
isNameShown = true
identifier = user.user_id.toLong()
descriptionText = "${user.username}@${user.instance_uri.removePrefix("https://")}"
}
}.toMutableList()
// reuse the already existing "add account" item
for (profile in header.profiles.orEmpty()) {
if (profile.identifier == ADD_ACCOUNT_IDENTIFIER) {
profiles.add(profile)
break
}
}
header.clear()
header.profiles = profiles
header.setActiveProfile(account.toLong())
}
private fun setupTabs(tab_array: Array<Fragment>){
view_pager.adapter = object : FragmentStateAdapter(this) {
override fun createFragment(position: Int): Fragment {
@ -141,26 +270,17 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}.attach()
}
/**
When clicking in the drawer menu, go to the corresponding activity
*/
override fun onNavigationItemSelected(@NonNull item: MenuItem): Boolean {
when (item.itemId){
R.id.nav_account -> launchActivity(ProfileActivity())
R.id.nav_settings -> launchActivity(SettingsActivity())
R.id.nav_logout -> launchActivity(LoginActivity())
}
drawer_layout.closeDrawer(GravityCompat.START)
return true
}
/**
Launches the given activity and put it as the current one
Setting argument firstTime to true means the task history will be reset (as if the app were launched anew into
this activity)
*/
private fun launchActivity(activity: AppCompatActivity) {
private fun launchActivity(activity: AppCompatActivity, firstTime: Boolean = false) {
val intent = Intent(this, activity::class.java)
if(firstTime){
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
startActivity(intent)
}

View File

@ -1,27 +1,20 @@
package com.h.pixeldroid
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.graphics.BitmapFactory
import android.graphics.Point
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
@ -38,11 +31,13 @@ import com.zomato.photofilters.imageprocessors.subfilters.ContrastSubFilter
import com.zomato.photofilters.imageprocessors.subfilters.SaturationSubfilter
import kotlinx.android.synthetic.main.activity_photo_edit.*
import kotlinx.android.synthetic.main.content_photo_edit.*
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors.newSingleThreadExecutor
import java.util.concurrent.Future
// This is an arbitrary number we are using to keep track of the permission
// request. Where an app has multiple context for requesting permission,
@ -88,17 +83,31 @@ class PhotoEditActivity : AppCompatActivity(), FilterListFragmentListener, EditI
System.loadLibrary("NativeImageProcessor")
}
companion object{
private var executor: ExecutorService = newSingleThreadExecutor()
private var future: Future<*>? = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_photo_edit)
//TODO move to xml:
setSupportActionBar(toolbar)
supportActionBar!!.title = "Edit"
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
supportActionBar!!.setHomeButtonEnabled(true)
val cropButton: FloatingActionButton = findViewById(R.id.cropImageButton)
cropUri = intent.getParcelableExtra("picture_uri")
// set on-click listener
cropButton.setOnClickListener {
startCrop()
}
loadImage()
val file = File.createTempFile("temp_compressed_img", ".png", cacheDir)
file.writeBitmap(compressedImage!!)
@ -109,14 +118,9 @@ class PhotoEditActivity : AppCompatActivity(), FilterListFragmentListener, EditI
setupViewPager(viewPager)
tabLayout.setupWithViewPager(viewPager)
outputDirectory = getOutputDirectory()
val cropButton: FloatingActionButton = findViewById(R.id.cropImageButton)
// set on-click listener
cropButton.setOnClickListener {
startCrop()
}
}
//<editor-fold desc="ON LAUNCH">
private fun loadImage() {
originalImage = MediaStore.Images.Media.getBitmap(contentResolver, cropUri)
@ -192,49 +196,55 @@ class PhotoEditActivity : AppCompatActivity(), FilterListFragmentListener, EditI
contrastFinal = CONTRAST_START
}
//</editor-fold>
//<editor-fold desc="EDITS">
private fun applyFilterAndShowImage(filter: Filter, image: Bitmap?) {
image_preview.setImageBitmap(filter.processFilter(image!!.copy(BITMAP_CONFIG, true)))
future?.cancel(true)
future = executor.submit {
val bitmap = filter.processFilter(image!!.copy(BITMAP_CONFIG, true))
image_preview.post {
image_preview.setImageBitmap(bitmap)
}
}
}
override fun onBrightnessChange(brightness: Int) {
brightnessFinal = brightness
val myFilter = Filter()
myFilter.addSubFilter(BrightnessSubFilter(brightness))
myFilter.addEditFilters(brightness, saturationFinal, contrastFinal)
applyFilterAndShowImage(myFilter, filteredImage)
}
override fun onSaturationChange(saturation: Float) {
saturationFinal = saturation
val myFilter = Filter()
myFilter.addSubFilter(SaturationSubfilter(saturation))
myFilter.addEditFilters(brightnessFinal, saturation, contrastFinal)
applyFilterAndShowImage(myFilter, filteredImage)
}
override fun onContrastChange(contrast: Float) {
contrastFinal = contrast
val myFilter = Filter()
myFilter.addSubFilter(ContrastSubFilter(contrast))
myFilter.addEditFilters(brightnessFinal, saturationFinal, contrast)
applyFilterAndShowImage(myFilter, filteredImage)
}
private fun addEditFilters(filter: Filter, br: Int, sa: Float, co: Float): Filter {
filter.addSubFilter(BrightnessSubFilter(br))
filter.addSubFilter(ContrastSubFilter(co))
filter.addSubFilter(SaturationSubfilter(sa))
return filter
private fun Filter.addEditFilters(br: Int, sa: Float, co: Float): Filter {
addSubFilter(BrightnessSubFilter(br))
addSubFilter(ContrastSubFilter(co))
addSubFilter(SaturationSubfilter(sa))
return this
}
override fun onEditStarted() {
}
override fun onEditCompleted() {
val bitmap = filteredImage.copy(BITMAP_CONFIG, true)
val myFilter = Filter()
addEditFilters(myFilter, brightnessFinal, saturationFinal, contrastFinal)
myFilter.addEditFilters(brightnessFinal, saturationFinal, contrastFinal)
val bitmap = filteredImage.copy(BITMAP_CONFIG, true)
compressedImage = myFilter.processFilter(bitmap)
}
@ -268,7 +278,7 @@ class PhotoEditActivity : AppCompatActivity(), FilterListFragmentListener, EditI
val newBr = if(brightnessFinal != 0) BRIGHTNESS_START/brightnessFinal else 0
val newSa = if(saturationFinal != 0.0f) SATURATION_START/saturationFinal else 0.0f
val newCo = if(contrastFinal != 0.0f) CONTRAST_START/contrastFinal else 0.0f
val myFilter = addEditFilters(Filter(), newBr, newSa, newCo)
val myFilter = Filter().addEditFilters(newBr, newSa, newCo)
filteredImage = myFilter.processFilter(filteredImage)
}
@ -319,8 +329,7 @@ class PhotoEditActivity : AppCompatActivity(), FilterListFragmentListener, EditI
}
private fun applyFinalFilters(image: Bitmap?) {
var editFilter = Filter()
editFilter = addEditFilters(editFilter, brightnessFinal, saturationFinal, contrastFinal)
val editFilter = Filter().addEditFilters(brightnessFinal, saturationFinal, contrastFinal)
finalImage = editFilter.processFilter(image!!.copy(BITMAP_CONFIG, true))
if (actualFilter!=null) finalImage = actualFilter!!.processFilter(finalImage)

View File

@ -1,8 +1,6 @@
package com.h.pixeldroid
import android.Manifest
import android.app.Application
import android.view.WindowManager
import androidx.preference.PreferenceManager
import com.h.pixeldroid.utils.ThemeUtils

View File

@ -1,7 +1,5 @@
package com.h.pixeldroid
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.View
@ -13,15 +11,16 @@ import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.objects.Status.Companion.DISCOVER_TAG
import com.h.pixeldroid.objects.Status.Companion.DOMAIN_TAG
import com.h.pixeldroid.objects.Status.Companion.POST_TAG
import com.h.pixeldroid.utils.DBUtils
import kotlinx.android.synthetic.main.activity_post.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class PostActivity : AppCompatActivity() {
private lateinit var preferences: SharedPreferences
private lateinit var postFragment : PostFragment
lateinit var domain : String
private lateinit var accessToken : String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -29,11 +28,13 @@ class PostActivity : AppCompatActivity() {
val status = intent.getSerializableExtra(POST_TAG) as Status?
val discoverPost: DiscoverPost? = intent.getSerializableExtra(DISCOVER_TAG) as DiscoverPost?
val db = DBUtils.initDB(applicationContext)
preferences = getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
domain = preferences.getString("domain", "")!!
val user = db.userDao().getActiveUser()
domain = user?.instance_uri.orEmpty()
accessToken = user?.accessToken.orEmpty()
db.close()
postFragment = PostFragment()
val arguments = Bundle()
@ -52,7 +53,6 @@ class PostActivity : AppCompatActivity() {
discoverPost: DiscoverPost
) {
val api = PixelfedAPI.create(domain)
val accessToken = preferences.getString("accessToken", "") ?: ""
val id = discoverPost.url?.substringAfterLast('/') ?: ""
api.getStatus("Bearer $accessToken", id).enqueue(object : Callback<Status> {

View File

@ -1,8 +1,6 @@
package com.h.pixeldroid
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
@ -16,8 +14,11 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import com.google.android.material.textfield.TextInputEditText
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.objects.Attachment
import com.h.pixeldroid.objects.Instance
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.DBUtils
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
@ -38,9 +39,11 @@ class PostCreationActivity : AppCompatActivity() {
private lateinit var accessToken: String
private lateinit var pixelfedAPI: PixelfedAPI
private lateinit var preferences: SharedPreferences
private lateinit var pictureFrame: ImageView
private lateinit var image: File
private var user: UserDatabaseEntity? = null
private var maxLength: Int = Instance.DEFAULT_MAX_TOOT_CHARS
private var description: String = ""
@ -55,11 +58,24 @@ class PostCreationActivity : AppCompatActivity() {
pictureFrame = findViewById(R.id.post_creation_picture_frame)
pictureFrame.setImageURI(image.toUri())
preferences = getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
accessToken = preferences.getString("accessToken", "")!!
val db = DBUtils.initDB(applicationContext)
user = db.userDao().getActiveUser()
val instances = db.instanceDao().getAll()
db.close()
maxLength = if (user!=null){
val thisInstances =
instances.filter { instanceDatabaseEntity ->
instanceDatabaseEntity.uri.contains(user!!.instance_uri)
}
thisInstances.first().max_toot_chars
} else {
Instance.DEFAULT_MAX_TOOT_CHARS
}
val domain = user?.instance_uri.orEmpty()
accessToken = user?.accessToken.orEmpty()
pixelfedAPI = PixelfedAPI.create(domain)
// check if the picture is alright
// TODO
@ -99,7 +115,6 @@ class PostCreationActivity : AppCompatActivity() {
private fun setDescription(): Boolean {
val textField = findViewById<TextInputEditText>(R.id.new_post_description_input_field)
val content = textField.text.toString()
val maxLength = preferences.getInt("max_toot_chars", 500)
if (content.length > maxLength) {
// error, too much characters
textField.error = "Description must contain $maxLength characters at most."

View File

@ -1,8 +1,6 @@
package com.h.pixeldroid
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Typeface
import android.net.Uri
import android.os.Bundle
@ -16,33 +14,38 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.adapters.ProfilePostsRecyclerViewAdapter
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.objects.Account.Companion.ACCOUNT_TAG
import com.h.pixeldroid.objects.Relationship
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.DBUtils
import com.h.pixeldroid.utils.ImageConverter
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class ProfileActivity : AppCompatActivity() {
private lateinit var preferences : SharedPreferences
private lateinit var pixelfedAPI : PixelfedAPI
private lateinit var adapter : ProfilePostsRecyclerViewAdapter
private lateinit var recycler : RecyclerView
private var accessToken : String? = null
private lateinit var accessToken : String
private lateinit var domain : String
private var account: Account? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profile)
preferences = this.getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE)
pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
accessToken = preferences.getString("accessToken", "")
val db = DBUtils.initDB(applicationContext)
val user = db.userDao().getActiveUser()
domain = user?.instance_uri.orEmpty()
pixelfedAPI = PixelfedAPI.create(domain)
accessToken = user?.accessToken.orEmpty()
db.close()
// Set posts RecyclerView as a grid with 3 columns
recycler = findViewById(R.id.profilePostsRecyclerView)
@ -139,7 +142,7 @@ class ProfileActivity : AppCompatActivity() {
}
private fun onClickEditButton() {
val url = "${preferences.getString("domain", "")}/settings/home"
val url = "$domain/settings/home"
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
if(browserIntent.resolveActivity(packageManager) != null) {

View File

@ -2,7 +2,6 @@ package com.h.pixeldroid
import android.app.SearchManager
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
@ -17,7 +16,6 @@ import com.h.pixeldroid.fragments.feeds.search.SearchPostsFragment
import com.h.pixeldroid.objects.Results
class SearchActivity : AppCompatActivity() {
private lateinit var preferences: SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -26,11 +24,15 @@ class SearchActivity : AppCompatActivity() {
var query = intent.getSerializableExtra("searchFeed") as String
query = query.trim()
val searchType = if (query.startsWith("#")){
Results.SearchType.hashtags
} else if(query.startsWith("@")){
Results.SearchType.accounts
} else Results.SearchType.statuses
val searchType = when {
query.startsWith("#") -> {
Results.SearchType.hashtags
}
query.startsWith("@") -> {
Results.SearchType.accounts
}
else -> Results.SearchType.statuses
}
if(searchType != Results.SearchType.statuses) query = query.drop(1)

View File

@ -3,9 +3,7 @@ package com.h.pixeldroid
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.h.pixeldroid.utils.ThemeUtils.Companion.setThemeFromPreferences

View File

@ -5,7 +5,7 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
class EditPhotoViewPagerAdapter (manager: FragmentManager):
FragmentPagerAdapter(manager, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
FragmentPagerAdapter(manager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
private val fragmentList = ArrayList<Fragment>()
private val fragmentTitleList = ArrayList<String>()

View File

@ -12,8 +12,7 @@ import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.ImageConverter.Companion.setSquareImageFromURL
/**
* [RecyclerView.Adapter] that can display a list of [PostMiniature]s and makes a call to the
* specified [OnListFragmentInteractionListener].
* [RecyclerView.Adapter] that can display a list of [Status]s
*/
class ProfilePostsRecyclerViewAdapter: RecyclerView.Adapter<ProfilePostsRecyclerViewAdapter.ViewHolder>() {
private val posts: ArrayList<Status> = ArrayList()

View File

@ -46,12 +46,7 @@ class ThumbnailAdapter (private val context: Context,
}
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
var thumbnail: ImageView
var filterName: TextView
init {
thumbnail = itemView.thumbnail
filterName = itemView.filter_name
}
var thumbnail: ImageView = itemView.thumbnail
var filterName: TextView = itemView.filter_name
}
}

View File

@ -13,9 +13,18 @@ interface UserDao {
@Query("SELECT * FROM users")
fun getAll(): List<UserDatabaseEntity>
@Query("SELECT * FROM users WHERE isActive=1 LIMIT 1")
fun getActiveUser(): UserDatabaseEntity?
@Query("UPDATE users SET isActive=0 WHERE isActive=1")
fun deActivateActiveUser()
@Query("UPDATE users SET isActive=1 WHERE user_id=:id")
fun activateUser(id: String)
@Query("DELETE FROM users WHERE isActive=1")
fun deleteActiveUsers()
@Query("SELECT * FROM users WHERE user_id=:id LIMIT 1")
fun getUserWithId(id: String): UserDatabaseEntity
@Query("UPDATE users SET username = :username, display_name = :display_name, avatar_static = :avatar_static WHERE user_id=:user_id")
fun updateUser(user_id: String, username: String, display_name: String, avatar_static: String)
}

View File

@ -19,5 +19,7 @@ data class UserDatabaseEntity (
var instance_uri: String,
var username: String,
var display_name: String,
var avatar_static: String
var avatar_static: String,
var isActive: Boolean,
var accessToken: String
)

View File

@ -8,7 +8,6 @@ import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.hardware.display.DisplayManager
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
@ -31,13 +30,10 @@ import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.h.pixeldroid.PhotoEditActivity
import com.h.pixeldroid.PostCreationActivity
import com.h.pixeldroid.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.math.abs
@ -70,10 +66,6 @@ class CameraFragment : Fragment() {
private var imageCapture: ImageCapture? = null
private var camera: Camera? = null
private val displayManager by lazy {
requireContext().getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
}
/** Blocking camera operations are performed using this executor */
private lateinit var cameraExecutor: ExecutorService
@ -276,7 +268,7 @@ class CameraFragment : Fragment() {
if (cursor != null && cursor.moveToFirst()) {
val uri = Uri.parse(cursor.getString(1)).path ?: ""
setGalleryThumbnail(uri)
cursor.close();
cursor.close()
}
}

View File

@ -53,15 +53,12 @@ class FilterListFragment : Fragment(), FilterListFragmentListener {
fun displayImage(bitmap: Bitmap?) {
val r = Runnable {
val tbImage: Bitmap?
if (bitmap == null) {
tbImage = MediaStore.Images.Media.getBitmap(requireActivity().contentResolver, PhotoEditActivity.URI.picture_uri)
val tbImage: Bitmap = (if (bitmap == null) {
MediaStore.Images.Media.getBitmap(requireActivity().contentResolver, PhotoEditActivity.URI.picture_uri)
} else {
tbImage = Bitmap.createScaledBitmap(bitmap, 100, 100, false)
}
if (tbImage == null)
return@Runnable
Bitmap.createScaledBitmap(bitmap, 100, 100, false)
})
?: return@Runnable
setupFilter(tbImage)

View File

@ -1,6 +1,5 @@
package com.h.pixeldroid.fragments
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
@ -9,13 +8,13 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
import com.h.pixeldroid.BuildConfig
import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.fragments.feeds.PostViewHolder
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.objects.Status.Companion.DOMAIN_TAG
import com.h.pixeldroid.objects.Status.Companion.POST_TAG
import com.h.pixeldroid.utils.DBUtils
class PostFragment : Fragment() {
@ -25,28 +24,29 @@ class PostFragment : Fragment() {
savedInstanceState: Bundle?
): View? {
val current_status = arguments?.getSerializable(POST_TAG) as Status?
val domain = arguments?.getString(DOMAIN_TAG)!!
val statusDomain = arguments?.getString(DOMAIN_TAG)!!
val root: View = inflater.inflate(R.layout.post_fragment, container, false)
val picRequest = Glide.with(this)
.asDrawable().fitCenter()
.placeholder(ColorDrawable(Color.GRAY))
current_status?.setupPost(root, picRequest, this, domain, true)
current_status?.setupPost(root, picRequest, this, statusDomain, true)
//Setup arguments needed for the onclicklisteners
val holder = PostViewHolder(root, requireContext())
val db = DBUtils.initDB(requireContext())
val preferences = requireActivity().getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
val accessToken = preferences.getString("accessToken", "")
val api = PixelfedAPI.create("${preferences.getString("domain", "")}")
val user = db.userDao().getActiveUser()
val domain = user?.instance_uri.orEmpty()
val accessToken = user?.accessToken.orEmpty()
val api = PixelfedAPI.create(domain)
current_status?.setDescription(root, api, "Bearer $accessToken")
//Activate onclickListeners
current_status?.activateLiker(holder, api, "Bearer $accessToken", current_status!!.favourited)
current_status?.activateReblogger(holder, api, "Bearer $accessToken", current_status!!.reblogged)
current_status?.activateLiker(holder, api, "Bearer $accessToken", current_status.favourited)
current_status?.activateReblogger(holder, api, "Bearer $accessToken", current_status.reblogged)
current_status?.activateCommenter(holder, api, "Bearer $accessToken")
current_status?.showComments(holder, api, "Bearer $accessToken")

View File

@ -1,7 +1,5 @@
package com.h.pixeldroid.fragments
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -10,21 +8,14 @@ import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.h.pixeldroid.BuildConfig
import com.h.pixeldroid.R
import com.h.pixeldroid.adapters.ProfilePostsRecyclerViewAdapter
import com.h.pixeldroid.api.PixelfedAPI
/**
* A fragment representing a list of Items.
* Activities containing this fragment MUST implement the
* [ProfilePostsFragment.OnListFragmentInteractionListener] interface.
* A fragment representing a list of statuses of a profile.
*/
class ProfilePostsFragment : Fragment() {
private lateinit var preferences: SharedPreferences
private lateinit var pixelfedAPI: PixelfedAPI
private var accessToken: String? = null
private var columnCount = 3
@ -33,11 +24,7 @@ class ProfilePostsFragment : Fragment() {
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_profile_posts_list, container, false)
preferences = requireActivity().getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
accessToken = preferences.getString("accessToken", "")
// Set the adapter
if (view is RecyclerView) {

View File

@ -1,8 +1,6 @@
package com.h.pixeldroid.fragments
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@ -16,7 +14,6 @@ import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.h.pixeldroid.BuildConfig
import com.h.pixeldroid.PostActivity
import com.h.pixeldroid.R
import com.h.pixeldroid.SearchActivity
@ -24,6 +21,7 @@ import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.objects.DiscoverPost
import com.h.pixeldroid.objects.DiscoverPosts
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.DBUtils
import com.h.pixeldroid.utils.ImageConverter
import retrofit2.Call
import retrofit2.Callback
@ -35,7 +33,6 @@ import retrofit2.Response
class SearchDiscoverFragment : Fragment() {
private lateinit var api: PixelfedAPI
private lateinit var preferences: SharedPreferences
private lateinit var recycler : RecyclerView
private lateinit var adapter : DiscoverRecyclerViewAdapter
private lateinit var accessToken: String
@ -43,7 +40,6 @@ class SearchDiscoverFragment : Fragment() {
private lateinit var discoverRefreshLayout: SwipeRefreshLayout
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@ -67,11 +63,14 @@ class SearchDiscoverFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
preferences = requireActivity().getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
api = PixelfedAPI.create("${preferences.getString("domain", "")}")
accessToken = preferences.getString("accessToken", "") ?: ""
val db = DBUtils.initDB(requireContext())
val user = db.userDao().getActiveUser()
val domain = user?.instance_uri.orEmpty()
api = PixelfedAPI.create(domain)
accessToken = user?.accessToken.orEmpty()
discoverProgressBar = view.findViewById(R.id.discoverProgressBar)
discoverRefreshLayout = view.findViewById(R.id.discoverRefreshLayout)

View File

@ -1,7 +1,6 @@
package com.h.pixeldroid.fragments.feeds
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@ -20,10 +19,12 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.h.pixeldroid.BuildConfig
import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.objects.FeedContent
import com.h.pixeldroid.utils.DBUtils
import kotlinx.android.synthetic.main.fragment_feed.view.*
import retrofit2.Call
import retrofit2.Callback
@ -36,12 +37,15 @@ open class FeedFragment<T: FeedContent, VH: RecyclerView.ViewHolder?>: Fragment(
protected var accessToken: String? = null
protected lateinit var pixelfedAPI: PixelfedAPI
protected lateinit var preferences: SharedPreferences
protected lateinit var list : RecyclerView
protected lateinit var adapter : FeedsRecyclerViewAdapter<T, VH>
protected lateinit var swipeRefreshLayout: SwipeRefreshLayout
internal lateinit var loadingIndicator: ProgressBar
private var user: UserDatabaseEntity? = null
private lateinit var db: AppDatabase
override fun onCreateView(
inflater: LayoutInflater,
@ -54,12 +58,11 @@ open class FeedFragment<T: FeedContent, VH: RecyclerView.ViewHolder?>: Fragment(
swipeRefreshLayout = view.findViewById(R.id.swipeRefreshLayout)
loadingIndicator = view.findViewById(R.id.progressBar)
list = swipeRefreshLayout.list
preferences = requireActivity().getSharedPreferences(
"${BuildConfig.APPLICATION_ID}.pref", Context.MODE_PRIVATE
)
list.layoutManager = LinearLayoutManager(context)
pixelfedAPI = PixelfedAPI.create("${preferences.getString("domain", "")}")
accessToken = preferences.getString("accessToken", "")
db = DBUtils.initDB(requireContext())
user = db.userDao().getActiveUser()
pixelfedAPI = PixelfedAPI.create(user?.instance_uri.orEmpty())
accessToken = user?.accessToken.orEmpty()
return view
}

View File

@ -9,7 +9,6 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.paging.LivePagedListBuilder
@ -81,7 +80,7 @@ class NotificationsFragment : FeedFragment<Notification, NotificationsFragment.N
private fun makeContent(): LiveData<PagedList<Notification>> {
fun makeInitialCall(requestedLoadSize: Int): Call<List<Notification>> {
return pixelfedAPI
.notifications("Bearer $accessToken", min_id="1", limit="$requestedLoadSize")
.notifications("Bearer $accessToken", limit="$requestedLoadSize")
}
fun makeAfterCall(requestedLoadSize: Int, key: String): Call<List<Notification>> {
return pixelfedAPI

View File

@ -20,20 +20,26 @@ import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader
import com.bumptech.glide.util.ViewPreloadSizeProvider
import com.h.pixeldroid.R
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.DBUtils
import retrofit2.Call
open class PostsFeedFragment : FeedFragment<Status, PostViewHolder>() {
lateinit var picRequest: RequestBuilder<Drawable>
lateinit var domain : String
private var user: UserDatabaseEntity? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = super.onCreateView(inflater, container, savedInstanceState)
domain = preferences.getString("domain", "")!!
val db = DBUtils.initDB(requireContext())
user = db.userDao().getActiveUser()
domain = user?.instance_uri.orEmpty()
//RequestBuilder that is re-used for every image
picRequest = Glide.with(this)
.asDrawable().fitCenter()

View File

@ -6,7 +6,6 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.lifecycle.LiveData
@ -14,21 +13,11 @@ import androidx.lifecycle.Observer
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.ListPreloader
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader
import com.bumptech.glide.util.ViewPreloadSizeProvider
import com.h.pixeldroid.R
import com.h.pixeldroid.fragments.feeds.AccountListFragment
import com.h.pixeldroid.fragments.feeds.FeedFragment
import com.h.pixeldroid.fragments.feeds.FeedsRecyclerViewAdapter
import com.h.pixeldroid.fragments.feeds.NotificationsFragment
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.objects.Notification
import com.h.pixeldroid.objects.Results
import com.h.pixeldroid.objects.Tag
import kotlinx.android.synthetic.main.account_list_entry.view.*
import kotlinx.android.synthetic.main.fragment_tags.view.*
import retrofit2.Call
import retrofit2.Callback

View File

@ -5,7 +5,6 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.LiveData
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList

View File

@ -7,25 +7,19 @@ import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.text.Spanned
import android.text.method.LinkMovementMethod
import android.util.Log
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.*
import androidx.core.text.toSpanned
import android.widget.TextView
import android.widget.LinearLayout
import android.widget.Toast
import android.widget.PopupMenu
import android.widget.ImageView
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.bumptech.glide.RequestBuilder
import com.google.android.material.tabs.TabLayoutMediator
import com.h.pixeldroid.fragments.ImageFragment
import com.h.pixeldroid.R
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.fragments.ImageFragment
import com.h.pixeldroid.fragments.feeds.PostViewHolder
import com.h.pixeldroid.utils.HtmlUtils.Companion.getDomain
import com.h.pixeldroid.utils.HtmlUtils.Companion.parseHTMLText
@ -45,12 +39,10 @@ import com.karumi.dexter.listener.PermissionDeniedResponse
import com.karumi.dexter.listener.PermissionGrantedResponse
import com.karumi.dexter.listener.single.BasePermissionListener
import kotlinx.android.synthetic.main.post_fragment.view.*
import kotlinx.android.synthetic.main.post_fragment.view.postDate
import kotlinx.android.synthetic.main.post_fragment.view.postDomain
import java.io.Serializable
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.*
import kotlin.collections.ArrayList
/*
@ -96,9 +88,7 @@ data class Status(
{
companion object {
const val SAVE_TO_GALLERY_WRITE_PERMISSION = 1
const val POST_TAG = "postTag"
const val POST_FRAG_TAG = "postFragTag"
const val DOMAIN_TAG = "domainTag"
const val DISCOVER_TAG = "discoverTag"
}
@ -270,7 +260,7 @@ data class Status(
//Set comment initial visibility
rootView.findViewById<LinearLayout>(R.id.commentIn).visibility = View.GONE
rootView.findViewById<LinearLayout>(R.id.commentIn).visibility = GONE
}
fun setDescription(rootView: View, api : PixelfedAPI, credential: String) {
@ -295,13 +285,11 @@ data class Status(
//Activate the button
setEventListener { _, buttonState ->
if (buttonState) {
Log.e("REBLOG", "Reblogged post")
// Button is active
reblogPost(holder, api, credential, this@Status)
} else {
Log.e("REBLOG", "Undo Reblogged post")
// Button is inactive
undoReblogPost(holder, api, credential, this@Status)
} else {
// Button is inactive
reblogPost(holder, api, credential, this@Status)
}
//show animation or not?
true
@ -323,11 +311,11 @@ data class Status(
//Activate the liker
setEventListener { _, buttonState ->
if (buttonState) {
// Button is active
likePostCall(holder, api, credential, this@Status)
} else {
// Button is inactive
// Button is active, unlike
unLikePostCall(holder, api, credential, this@Status)
} else {
// Button is inactive, like
likePostCall(holder, api, credential, this@Status)
}
//show animation or not?
true

View File

@ -3,8 +3,11 @@ package com.h.pixeldroid.utils
import android.content.Context
import androidx.room.Room
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.InstanceDatabaseEntity
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.objects.Account
import com.h.pixeldroid.objects.Instance
import com.h.pixeldroid.utils.Utils.Companion.normalizeDomain
class DBUtils {
companion object {
@ -14,26 +17,39 @@ class DBUtils {
AppDatabase::class.java, "pixeldroid"
).allowMainThreadQueries().build()
}
fun addUser(db: AppDatabase, account: Account, instance_uri: String = "") {
if (instance_uri.isEmpty()) {
db.userDao().updateUser(
user_id = account.id,
username = account.username,
display_name = account.display_name,
avatar_static = account.avatar_static
)
private fun normalizeOrNot(uri: String): String{
return if(uri.startsWith("http://localhost")){
uri
} else {
db.userDao().insertUser(
normalizeDomain(uri)
}
}
fun addUser(db: AppDatabase, account: Account, instance_uri: String, activeUser: Boolean = true, accessToken: String) {
db.userDao().insertUser(
UserDatabaseEntity(
user_id = account.id,
instance_uri = instance_uri,
//make sure not to normalize to https when localhost, to allow testing
instance_uri = normalizeOrNot(instance_uri),
username = account.username,
display_name = account.display_name,
avatar_static = account.avatar_static
avatar_static = account.avatar_static,
isActive = activeUser,
accessToken = accessToken
)
)
}
}
fun storeInstance(db: AppDatabase, instance: Instance) {
val maxTootChars = instance.max_toot_chars.toInt()
val dbInstance = InstanceDatabaseEntity(
//make sure not to normalize to https when localhost, to allow testing
uri = normalizeOrNot(instance.uri),
title = instance.title,
max_toot_chars = maxTootChars,
thumbnail = instance.thumbnail
)
db.instanceDao().insertInstance(dbInstance)
}
}
}

View File

@ -2,8 +2,6 @@ package com.h.pixeldroid.utils
import android.content.Context
import android.net.ConnectivityManager
import androidx.room.Room
import com.h.pixeldroid.db.AppDatabase
class Utils {
companion object {
@ -12,6 +10,13 @@ class Utils {
return cm.activeNetwork != null
}
fun normalizeDomain(domain: String): String {
return "https://" + domain
.replace("http://", "")
.replace("https://", "")
.trim(Char::isWhitespace)
}
}
}

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="#000000" />
<item android:state_enabled="false" android:color="#000000" />
<item android:state_focused="true" android:color="#000000" />
<item android:color="#FFFFFF" />
</selector>

View File

@ -1,9 +0,0 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="135"
android:centerColor="#009688"
android:endColor="#00695C"
android:startColor="#4DB6AC"
android:type="linear" />
</shape>

View File

@ -1,9 +0,0 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="135"
android:centerColor="#009688"
android:endColor="#00695C"
android:startColor="#4DB6AC"
android:type="linear" />
</shape>

View File

@ -26,41 +26,6 @@
app:srcCompat="@drawable/ic_fred_phone"
android:contentDescription="TODO" />
<LinearLayout
android:id="@+id/login_activity_instance_chooser_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="60dp"
android:layout_marginBottom="15dp"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/login_activity_instance_chooser_offline_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/you_are_in_offline_mode"
android:textAlignment="center"
android:visibility="gone"/>
<Spinner
android:id="@+id/login_activity_instance_chooser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="15dp"/>
<Button
android:id="@+id/login_activity_instance_chooser_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/colorButtonBg"
android:textColor="@color/colorButtonText"
android:text="@string/enter"/>
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/login_activity_instance_input_layout"
android:layout_width="250dp"

View File

@ -33,14 +33,11 @@
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
<com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
android:id="@+id/drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header"
app:menu="@menu/activity_main_drawer" />
android:fitsSystemWindows="true" />
</androidx.drawerlayout.widget.DrawerLayout>

View File

@ -1,29 +0,0 @@
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".fragments.feeds.PostsFeedFragment">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/feedList"
android:name="com.h.pixeldroid.FeedFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/post_fragment" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

View File

@ -1,7 +1,6 @@
<?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">

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:id="@+id/drawer_avatar"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/ic_default_user"
android:contentDescription="TODO" />
<TextView
android:id="@+id/drawer_account_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="@string/menu_slideshow"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<TextView
android:id="@+id/drawer_account_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_subtitle" />
</LinearLayout>

View File

@ -68,7 +68,7 @@
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></androidx.viewpager2.widget.ViewPager2>
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/postTabs"
@ -77,7 +77,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/postPager"
app:tabMode="auto"></com.google.android.material.tabs.TabLayout>
app:tabMode="auto" />
<ImageView
android:id="@+id/postPicture"

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu 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"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_account"
android:title="@string/menu_account" />
<item
android:id="@+id/nav_settings"
android:title="@string/menu_settings"
android:icon="@drawable/ic_settings"/>
<item
android:id="@+id/nav_logout"
android:title="@string/logout" />
</group>
</menu>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="menu_slideshow">اسم الحساب</string>
<string name="token_error">خطأ في الحصول على الرمز المميز</string>
<string name="title_activity_settings2">الإعدادات</string>
<string name="theme_title">حلة التطبيق</string>
@ -10,15 +9,11 @@
<string name="registration_failed">لا يمكن تسجيل التطبيق على هذا الخادم</string>
<string name="browser_launch_failed">تعذر إطلاق متصفح الويب. هل لديك واحد؟</string>
<string name="app_name">PixelDroid</string>
<string name="menu_subtitle">معلومات عن الحساب</string>
<string name="menu_account">ملفي التعريفي</string>
<string name="menu_settings">الإعدادات</string>
<string name="invalid_domain">اسم النطاق غير صالح</string>
<string name="auth_failed">فشلت المصادقة</string>
<string name="followed_notification">يتابعك %1$s</string>
<string name="take_a_picture">التقط صورة</string>
<string name="upload_a_picture">حمّل صورة</string>
<string name="or">أو</string>
<string name="description">الوصف…</string>
<string name="send">ارسل</string>
<string name="whats_an_instance">ماذا نعني بمثيل الخادم؟</string>
@ -30,25 +25,18 @@
<string name="image_download_success">تم التنزيل بنجاح</string>
<string name="switch_camera_button_alt">تبديل الكاميرا</string>
<string name="gallery_button_alt">المعرض</string>
<string name="delete_title">تأكيد</string>
<string name="share_picture">شارِك الصورة…</string>
<string name="NoCommentsToShow">لا توجد تعليقات في هذا المنشور…</string>
<string name="CommentDisplay">لإظهاره…</string>
<string name="connect_to_pixelfed">لِج إلى PixelFed</string>
<string name="login_empty_string_error">لا يجب ترك العنوان فارغًا!</string>
<string name="lbl_brightness">السطوع</string>
<string name="image_download_failed">فشل التنزيل ، حاول مجددًا مِن فضلك</string>
<string name="liked_notification">أعجِب %1$s بمنشورك</string>
<string name="create_a_new_post">انشئ منشورًا جديدًا!</string>
<string name="capture_mode_camera">الكاميرا</string>
<string name="domain_of_your_instance">اسم نطاق مثيل خادمك</string>
<string name="login_connection_required_once">يجب عليك الاتصال بالأنترنت ولو لمرة واحدة قصد استخدام PixelDroid :(</string>
<string name="enter">أدخل</string>
<string name="attachment_summary_off">تنزيل المرفقات فقط عندما يُطلَب ذلك يدويًا</string>
<string name="capture_button_alt">لقطة شاشة</string>
<string name="you_are_in_offline_mode">إنك غير متصل الآن ولكنه لا يزال بإمكانك عرض بعض المحتوى!</string>
<string name="auth_error_toast_msg">لقد أجاب الخادم بخطأ ، حاول مجددًا!</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / وسائط مخفية
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / وسائط مخفية
\n (اضعط للعرض)</string>
<string name="lbl_contrast">تباين عالٍ</string>
<string name="lbl_saturation">التشبّع اللوني</string>

View File

@ -3,7 +3,6 @@
<string name="shared_notification">%1$s ha compartit la teva publicació</string>
<string name="mention_notification">%1$s t\'ha esmentat</string>
<string name="followed_notification">%1$s et segueix</string>
<string name="attachment_summary_off">Baixar fitxers adjunts només quan es sol·liciti manualment</string>
<string name="title_activity_settings2">Configuració</string>
<string name="token_error">S\'ha produït un error en obtenir el token</string>
<string name="auth_failed">No s\'ha pogut autenticar</string>
@ -12,8 +11,6 @@
<string name="invalid_domain">Domini no vàlid</string>
<string name="menu_settings">Configuració</string>
<string name="menu_account">El meu perfil</string>
<string name="menu_subtitle">Informació del compte</string>
<string name="menu_slideshow">Nom del compte</string>
<string name="app_name">PixelDroid</string>
<string name="share_picture">Compartir imatge…</string>
<string name="image_download_success">La imatge s\'ha descarrega\'t correctament</string>
@ -24,10 +21,6 @@
<string name="whats_an_instance">Què és una instancia\?</string>
<string name="send">enviar</string>
<string name="description">Descripció…</string>
<string name="or">o</string>
<string name="upload_a_picture">Puja una imatge</string>
<string name="take_a_picture">Fes una foto</string>
<string name="create_a_new_post">Crea una nova publicació!</string>
<string name="liked_notification">%1$s ha dona\'t m\'agrada a la teva publicació</string>
<string name="theme_title">Tema de l\'applicació</string>
<string name="switch_camera_button_alt">Canviar la càmera</string>
@ -40,16 +33,11 @@
<string name="tab_edit">EDICIÓ</string>
<string name="capture_button_alt">Captura</string>
<string name="gallery_button_alt">Galeria</string>
<string name="capture_mode_camera">Càmera</string>
<string name="delete_title">Confirmar</string>
<string name="NoCommentsToShow">No hi ha comentaris en aquesta publicació …</string>
<string name="CommentDisplay">mostrar…</string>
<string name="domain_of_your_instance">Domini de la teva instancia</string>
<string name="connect_to_pixelfed">Connectat a Pixelfed</string>
<string name="you_are_in_offline_mode">Estàs en mode fora de línia, però encara pots veure algun contingut!</string>
<string name="enter">Entrar</string>
<string name="login_empty_string_error">L\'adreça de la instància no pot estar buida!</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Imatges ocultes
\n(fes clic per mostrar)</string>
<string name="auth_error_toast_msg">El servidor ha respost amb un error, torna-ho a provar!</string>
</resources>

View File

@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">PixelDroid</string>
<string name="menu_slideshow">Benutzername</string>
<string name="menu_subtitle">Kontoinformationen</string>
<string name="menu_account">Mein Profil</string>
<string name="menu_settings">Einstellungen</string>
<string name="invalid_domain">Ungültige Domäne</string>
@ -10,19 +8,14 @@
<string name="auth_failed">Authentifizierung fehlgeschlagen</string>
<string name="token_error">Fehler beim Erhalten des Token</string>
<string name="title_activity_settings2">Einstellungen</string>
<string name="or">oder</string>
<string name="theme_header">Erscheinungsbild</string>
<string name="followed_notification">%1$s folgt dir</string>
<string name="mention_notification">%1$s hat dich erwähnt</string>
<string name="shared_notification">%1$s hat deinen Beitrag geteilt</string>
<string name="liked_notification">%1$s hat deinen Beitrag favorisiert</string>
<string name="take_a_picture">Ein Foto aufnehmen</string>
<string name="upload_a_picture">Ein Foto hochladen</string>
<string name="send">senden</string>
<string name="whats_an_instance">Was ist eine Instanz\?</string>
<string name="theme_title">Erscheinungsbild</string>
<string name="attachment_summary_off">Anhänge nur herunterladen, wenn sie manuell angefordert werden</string>
<string name="create_a_new_post">Neuen Beitrag erstellen!</string>
<string name="description">Beschreibung…</string>
<string name="save_to_gallery">In Galerie speichern…</string>
<string name="image_download_failed">Der Download ist fehlgeschlagen, bitte versuchen Sie es erneut</string>
@ -39,17 +32,12 @@
<string name="image_download_success">Bild erfolgreich heruntergeladen</string>
<string name="capture_button_alt">Erfassen</string>
<string name="gallery_button_alt">Galerie</string>
<string name="capture_mode_camera">Kamera</string>
<string name="delete_title">Bestätigen</string>
<string name="share_picture">Foto teilen…</string>
<string name="CommentDisplay">zeigen…</string>
<string name="domain_of_your_instance">Domain Ihrer Instanz</string>
<string name="connect_to_pixelfed">Mit Pixelfed verbinden</string>
<string name="login_connection_required_once">Sie müssen mindestens einmal mit dem Internet verbunden sein, um PixelDroid verwenden zu können :(</string>
<string name="you_are_in_offline_mode">Sie befinden sich im Offline-Modus, aber Sie können immer noch einige Inhalte ansehen!</string>
<string name="auth_error_toast_msg">Server hat mit einem Fehler geantwortet, versuchen Sie es erneut!</string>
<string name="login_empty_string_error">Instanz-Adresse kann nicht leer sein!</string>
<string name="switch_camera_button_alt">Kamera wechseln</string>
<string name="registration_failed">Konnte die App nicht mit diesem Server verbinden</string>
<string name="enter">Enter</string>
</resources>

View File

@ -6,16 +6,11 @@
<string name="invalid_domain">Dominio no válido</string>
<string name="menu_settings">Ajustes</string>
<string name="menu_account">Mi perfil</string>
<string name="menu_subtitle">Información de la cuenta</string>
<string name="menu_slideshow">Nombre de la cuenta</string>
<string name="app_name">PixelDroid</string>
<string name="token_error">Error al obtener el token</string>
<string name="title_activity_settings2">Ajustes</string>
<string name="shared_notification">%1$s compartió tu publicación</string>
<string name="liked_notification">%1$s le gustó tu publicación</string>
<string name="create_a_new_post">¡Crear una nueva publicación!</string>
<string name="take_a_picture">Tomar una foto</string>
<string name="upload_a_picture">Subir una foto</string>
<string name="description">Descripción…</string>
<string name="send">enviar</string>
<string name="whats_an_instance">¿Qué es una instancia\?</string>
@ -25,10 +20,8 @@
<string name="image_download_downloading">Descargando…</string>
<string name="image_download_success">La imagen se descargó con éxito</string>
<string name="share_picture">Compartir foto…</string>
<string name="attachment_summary_off">Descargar únicamente los archivos adjuntos cuando se solicite manualmente</string>
<string name="followed_notification">%1$s te siguió</string>
<string name="mention_notification">%1$s te mencionó</string>
<string name="or">o</string>
<string name="switch_camera_button_alt">Cambiar cámara</string>
<string name="theme_title">Tema de la Aplicación</string>
<string name="theme_header">Tema</string>
@ -39,16 +32,11 @@
<string name="tab_edit">EDITAR</string>
<string name="capture_button_alt">Capturar</string>
<string name="gallery_button_alt">Galería</string>
<string name="capture_mode_camera">Cámara</string>
<string name="delete_title">Confirmar</string>
<string name="NoCommentsToShow">No hay comentarios en esta publicación…</string>
<string name="CommentDisplay">para mostrar…</string>
<string name="domain_of_your_instance">Dominio de tu nodo</string>
<string name="connect_to_pixelfed">Conectar con Pixelfed</string>
<string name="you_are_in_offline_mode">Estás en modo sin conexión, ¡pero todavía puedes ver algo de contenido!</string>
<string name="enter">Entrar</string>
<string name="auth_error_toast_msg">El servidor ha respondido con un error, ¡inténtalo de nuevo!</string>
<string name="login_empty_string_error">¡La dirección del nodo no puede estar vacía!</string>
<string name="login_connection_required_once">Necesitar conectarte a Internet al menos una vez para utilizar PixelDroid :(</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Contenido Oculto
\n (haz clic para mostrar)</string>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="create_a_new_post">Sortu argitalpen berri bat!</string>
<string name="liked_notification">%1$s erabiltzaileak zure argitalpena gogoko du</string>
<string name="shared_notification">%1$s erabiltzaileak zure argitalpena partekatu du</string>
<string name="share_picture">Partekatu irudia…</string>
@ -12,12 +11,8 @@
<string name="whats_an_instance">Zer da instantzia bat\?</string>
<string name="send">bidali</string>
<string name="description">Deskribapena…</string>
<string name="or">edo</string>
<string name="upload_a_picture">Kargatu argazki bat</string>
<string name="take_a_picture">Atera argazki bat</string>
<string name="mention_notification">%1$s erabiltzaileak aipatu zaitu</string>
<string name="followed_notification">%1$s jarraitzen hasi zaizu</string>
<string name="attachment_summary_off">Eskuz eskatzean bakarrik deskargatu eranskinak</string>
<string name="title_activity_settings2">Ezarpenak</string>
<string name="token_error">Errorea tokena eskuratzean</string>
<string name="auth_failed">Ezin izan da autentifikatu</string>
@ -26,12 +21,8 @@
<string name="invalid_domain">Domeinu baliogabea</string>
<string name="menu_settings">Ezarpenak</string>
<string name="menu_account">Nire profila</string>
<string name="menu_subtitle">Kontuaren informazioa</string>
<string name="menu_slideshow">Kontuaren izena</string>
<string name="app_name">PixelDroid</string>
<string name="capture_mode_camera">Kamera</string>
<string name="gallery_button_alt">Galeria</string>
<string name="delete_title">Berretsi</string>
<string name="NoCommentsToShow">Iruzkinik gabeko argitalpena…</string>
<string name="you_are_in_offline_mode">Lineaz kanpo editatzeko moduan zaude, baina hala ere eduki batzuk ikus ditzakezu!</string>
<string name="theme_title">Aplikazioaren gaia</string>
@ -44,12 +35,9 @@
<string name="tab_filters">IRAGAZKIAK</string>
<string name="connect_to_pixelfed">Konektatu Pixelfedera</string>
<string name="login_connection_required_once">PixelDroid erabili ahal izateko Internetera gutxienez behin konektatu behar duzu :(</string>
<string name="enter">Sartu</string>
<string name="auth_error_toast_msg">Zerbitzariak errore batekin erantzun du, saiatu berriro!</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">Eduki-abisua / Multimedia ezkutatuta
\n (egin klik erakusteko)</string>
<string name="lbl_brightness">DISTIRA</string>
<string name="CommentDisplay">erakutsi…</string>
<string name="login_empty_string_error">Instantziaren helbidea hutsik dago!</string>
<string name="domain_of_your_instance">Zure instantziaren domeinua</string>
</resources>

View File

@ -1,11 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="create_a_new_post">مطلب جدیدی بگذارید!</string>
<string name="login_connection_required_once">برای استفاده از پیکسل‌دروید باید لااقل یک مرتبه به اینترنت وصل شوید :(</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">رسانهٔ پنهان / نامناسب برای محیط کار / دارای هشدار
\n(برای نمایش، کلیک کنید)</string>
<string name="menu_slideshow">نام حساب</string>
<string name="menu_subtitle">اطلاعات حساب</string>
<string name="menu_settings">تنظیمات</string>
<string name="invalid_domain">دامنه نامعتبر</string>
<string name="browser_launch_failed">نتوانستیم مرورگر را باز کنیم. آیا اصلا مرورگری دارید؟</string>
@ -18,9 +15,6 @@
<string name="mention_notification">%1$s به شما اشاره کرد</string>
<string name="shared_notification">%1$s مطلب شما را هم‌رسانی کرد</string>
<string name="liked_notification">%1$s مطلب شما را پسندید</string>
<string name="take_a_picture">عکسی بگیرید</string>
<string name="upload_a_picture">تصویری بارگذاری کنید</string>
<string name="or">یا</string>
<string name="description">توضیحات…</string>
<string name="send">بفرست</string>
<string name="whats_an_instance">یک نمونه چیست؟</string>
@ -37,19 +31,13 @@
<string name="capture_button_alt">دریافت</string>
<string name="switch_camera_button_alt">تغییر دوربین</string>
<string name="gallery_button_alt">نگارخانه</string>
<string name="capture_mode_camera">دوربین</string>
<string name="delete_title">تایید</string>
<string name="share_picture">هم‌رسانی تصویر…</string>
<string name="NoCommentsToShow">نظری روی این مطلب نیست…</string>
<string name="CommentDisplay">برای نمایش…</string>
<string name="domain_of_your_instance">دامنهٔ نمونهٔ شما</string>
<string name="connect_to_pixelfed">اتصال به پیکسل‌فد</string>
<string name="you_are_in_offline_mode">شما در حالت برخط نیستید، اما همچنان می‌توانید برخی محتواها را ببینید!</string>
<string name="enter">ورود</string>
<string name="auth_error_toast_msg">کارساز، پاسخی حاوی خطا فرستاد، دوباره تلاش کنید!</string>
<string name="login_empty_string_error">نشانی نمونه نمی‌تواند خالی باشد!</string>
<string name="app_name">پیکسل‌دروید</string>
<string name="menu_account">نمایهٔ من</string>
<string name="registration_failed">نتوانستیم برنامه را روی این کارساز ثبت کنیم</string>
<string name="attachment_summary_off">پیوست‌ها تنها در صورت درخواستی دستی بارگیری شوند</string>
</resources>

View File

@ -3,17 +3,11 @@
<string name="registration_failed">Impossible d\'enregistrer l\'application sur ce serveur</string>
<string name="auth_failed">Impossible d\'authentifier</string>
<string name="title_activity_settings2">Réglages</string>
<string name="menu_slideshow">Nom du compte</string>
<string name="menu_subtitle">Informations du compte</string>
<string name="menu_account">Mon profil</string>
<string name="menu_settings">Réglages</string>
<string name="attachment_summary_off">Télécharger uniquement les pièces jointes lorsque demandé manuellement</string>
<string name="followed_notification">%1$s vous a suivi</string>
<string name="shared_notification">%1$s a partagé votre publication</string>
<string name="liked_notification">%1$s a aimé(e) votre publication</string>
<string name="take_a_picture">Prendre une photo</string>
<string name="upload_a_picture">Mettre en ligne une photo</string>
<string name="or">ou</string>
<string name="description">Description…</string>
<string name="send">envoyer</string>
<string name="whats_an_instance">Qu\'est-ce qu\'une instance \?</string>
@ -27,7 +21,6 @@
<string name="browser_launch_failed">Impossible de lancer un navigateur, en avez-vous un \?</string>
<string name="mention_notification">%1$s vous a mentionné</string>
<string name="app_name">PixelDroid</string>
<string name="create_a_new_post">Créez une nouvelle publication !</string>
<string name="token_error">Erreur lors de l\'obtention du jeton</string>
<string name="connect_to_pixelfed">Se connecter à PixelFed</string>
<string name="theme_title">Thème de lapplication</string>
@ -40,16 +33,11 @@
<string name="capture_button_alt">Capturer</string>
<string name="switch_camera_button_alt">Changer de caméra</string>
<string name="gallery_button_alt">Gallerie</string>
<string name="capture_mode_camera">Appareil photo</string>
<string name="delete_title">Confirmer</string>
<string name="NoCommentsToShow">Aucun commentaire dans cette publication…</string>
<string name="domain_of_your_instance">Domaine de votre instance</string>
<string name="you_are_in_offline_mode">Vous êtes en mode hors ligne mais vous pouvez continuer accéder à un certain contenu !</string>
<string name="enter">Entrez</string>
<string name="login_empty_string_error">Ladresse de linstance ne peut être laissée vide !</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Média caché
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Média caché
\n (appuyez pour afficher)</string>
<string name="CommentDisplay">pour afficher…</string>
<string name="login_connection_required_once">Vous devez vous connecter à Internet au moins une fois afin de pouvoir utiliser PixelDroid :(</string>
<string name="auth_error_toast_msg">Le serveur a répondu avec une erreur, veuillez réessayer !</string>
</resources>

View File

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="menu_slideshow">Nome da conta</string>
<string name="menu_subtitle">Información da conta</string>
<string name="menu_account">Perfil</string>
<string name="menu_settings">Axustes</string>
<string name="invalid_domain">Dominio non válido</string>
@ -15,10 +13,6 @@
<string name="mention_notification">%1$s mencionoute</string>
<string name="liked_notification">a %1$s gustoulle a publicación</string>
<string name="shared_notification">%1$s comparteu a publicación</string>
<string name="create_a_new_post">Crea una publicación!</string>
<string name="take_a_picture">Fai unha foto</string>
<string name="upload_a_picture">Sube unha imaxe</string>
<string name="or">ou</string>
<string name="description">Descrición…</string>
<string name="send">enviar</string>
<string name="whats_an_instance">Que é unha instancia\?</string>
@ -34,8 +28,6 @@
<string name="capture_button_alt">Facer foto</string>
<string name="switch_camera_button_alt">Cambiar de cámara</string>
<string name="gallery_button_alt">Galería</string>
<string name="capture_mode_camera">Cámara</string>
<string name="delete_title">Confirmar</string>
<string name="share_picture">Compartir foto…</string>
<string name="NoCommentsToShow">Sen comentarios na publicación…</string>
<string name="image_download_failed">Fallou a descarga, inténtao outra vez</string>
@ -44,12 +36,8 @@
<string name="connect_to_pixelfed">Conectar con Pixelfed</string>
<string name="login_connection_required_once">Tes que conectarte cando menos unha vez a internet para usar PixelDroid :(</string>
<string name="you_are_in_offline_mode">Non tes conexión, pero aínda así podes ver algún contido!</string>
<string name="enter">Entrar</string>
<string name="auth_error_toast_msg">O servidor respondeu cun erro, inténtao outra vez!</string>
<string name="login_empty_string_error">O enderezo da instancia non pode estar baleiro!</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Agochado
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Agochado
\n(preme para amosar)</string>
<string name="app_name">PixelDroid</string>
<string name="registration_failed">Non puidemos rexistrar a aplicación neste servidor</string>
<string name="attachment_summary_off">Descargar anexos só cando se solicite manualmente</string>
</resources>

View File

@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="menu_slideshow">Nome account</string>
<string name="title_activity_settings2">Impostazioni</string>
<string name="attachment_summary_off">Scarica gli allegati solo quando richiesto manualmente</string>
<string name="menu_account">Profilo personale</string>
<string name="menu_settings">Impostazioni</string>
<string name="app_name">PixelDroid</string>
@ -14,11 +12,7 @@
<string name="shared_notification">%1$s ha condiviso il tuo post</string>
<string name="followed_notification">%1$s ti ha seguito</string>
<string name="mention_notification">%1$s ti ha menzionato</string>
<string name="take_a_picture">Fai una foto</string>
<string name="upload_a_picture">Carica una foto</string>
<string name="liked_notification">%1$s è piaciuto il tuo post</string>
<string name="create_a_new_post">Crea un nuovo post!</string>
<string name="or">o</string>
<string name="tab_filters">FILTRI</string>
<string name="send">invia</string>
<string name="lbl_brightness">LUMINOSITÀ</string>
@ -26,15 +20,11 @@
<string name="whats_an_instance">Cos\'è un\'istanza\?</string>
<string name="logout">Disconnettersi</string>
<string name="lbl_saturation">SATURAZIONE</string>
<string name="enter">Entrare</string>
<string name="menu_subtitle">Informazioni account</string>
<string name="delete_title">Conferma</string>
<string name="connect_to_pixelfed">Connetti a Pixelfed</string>
<string name="lbl_contrast">CONTRASTO</string>
<string name="save_to_gallery">Salva nella galleria…</string>
<string name="image_download_failed">Il download non è riuscito, per favore riprova</string>
<string name="share_picture">Condividi immagine…</string>
<string name="auth_error_toast_msg">Il server ha risposto con un errore, riprovare!</string>
<string name="image_download_downloading">Download in corso…</string>
<string name="image_download_success">Immagine scaricata con successo</string>
<string name="NoCommentsToShow">Nessun commento in questo post…</string>
@ -45,11 +35,9 @@
<string name="capture_button_alt">Acquisizione</string>
<string name="switch_camera_button_alt">Cambia fotocamera</string>
<string name="gallery_button_alt">Galleria</string>
<string name="capture_mode_camera">Fotocamera</string>
<string name="domain_of_your_instance">Dominio della tua istanza</string>
<string name="login_connection_required_once">È necessario connettersi a Internet almeno una volta per utilizzare PixelDroid :(</string>
<string name="you_are_in_offline_mode">Sei in modalità offline, ma puoi comunque visualizzare alcuni contenuti!</string>
<string name="login_empty_string_error">L\'indirizzo dell\'istanza non può essere vuoto!</string>
<string name="invalid_domain">Dominio non valido</string>
<string name="tab_edit">MODIFICA</string>
</resources>

View File

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="menu_slideshow">アカウント名</string>
<string name="menu_subtitle">アカウント情報</string>
<string name="menu_account">プロフィール</string>
<string name="menu_settings">設定</string>
<string name="invalid_domain">無効なドメイン</string>
@ -10,12 +8,8 @@
<string name="title_activity_settings2">設定</string>
<string name="theme_title">テーマ設定</string>
<string name="theme_header">テーマ</string>
<string name="attachment_summary_off">要求された場合にのみ添付ファイルをダウンロードする</string>
<string name="followed_notification">%1$s さんにフォローされました</string>
<string name="liked_notification">%1$s さんがあなたの投稿をお気に入りに登録しました</string>
<string name="take_a_picture">写真を撮影</string>
<string name="upload_a_picture">画像をアップロード</string>
<string name="or">または</string>
<string name="description">説明…</string>
<string name="send">送信</string>
<string name="whats_an_instance">インスタンスとは?</string>
@ -30,24 +24,18 @@
<string name="capture_button_alt">キャプチャー</string>
<string name="switch_camera_button_alt">カメラを切り替え</string>
<string name="gallery_button_alt">ギャラリー</string>
<string name="capture_mode_camera">カメラ</string>
<string name="delete_title">確認</string>
<string name="share_picture">画像を共有…</string>
<string name="CommentDisplay">表示する…</string>
<string name="domain_of_your_instance">あなたの参加しているインスタンスのドメイン</string>
<string name="connect_to_pixelfed">Pixelfedに接続</string>
<string name="login_connection_required_once">PixelDroidを利用するにははじめにインターネットにアクセスする必要があります</string>
<string name="auth_error_toast_msg">サーバーでエラーが発生しました。もう一度お試しください。</string>
<string name="login_empty_string_error">インスタンスアドレスを空欄にすることはできません</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Hidden Media
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Hidden Media
\n (クリックで表示)</string>
<string name="enter">入る</string>
<string name="app_name">PixelDroid</string>
<string name="registration_failed">このサーバーにアプリケーションを登録することができませんでした</string>
<string name="browser_launch_failed">ブラウザが起動できませんでした。インストールされているか確認してください。</string>
<string name="mention_notification">%1$s さんがあなたにメンションしました</string>
<string name="shared_notification">%1$s さんがあなたの投稿を再共有しました</string>
<string name="create_a_new_post">新しい投稿を作成</string>
<string name="tab_edit">編集</string>
<string name="image_download_failed">ダウンロードに失敗しました、もう一度実行してください</string>
<string name="NoCommentsToShow">この投稿にはコメントがありません…</string>

View File

@ -9,6 +9,5 @@
<color name="filterLabelNormal">#8A8889</color>
<color name="filterLabelSelected">#221F20</color>
<color name="colorOptionMenu">#FF3990</color>
<color name="colorPrimaryError">#FF0000</color>
</resources>

View File

@ -6,6 +6,8 @@
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="materialDrawerStyle">@style/Widget.MaterialDrawerStyle</item>
<item name="materialDrawerHeaderStyle">@style/Widget.MaterialDrawerHeaderStyle</item>
</style>
<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/theme_night</item>

View File

@ -9,21 +9,14 @@
<string name="invalid_domain">Ongeldig domein</string>
<string name="menu_settings">Instellingen</string>
<string name="menu_account">Mijn profiel</string>
<string name="menu_subtitle">Account informatie</string>
<string name="menu_slideshow">Account naam</string>
<string name="logout">Log uit</string>
<string name="whats_an_instance">Wat is een instance\?</string>
<string name="send">stuur</string>
<string name="description">Beschrijving…</string>
<string name="or">of</string>
<string name="upload_a_picture">Upload een foto</string>
<string name="take_a_picture">Maak een foto</string>
<string name="create_a_new_post">Schrijf een nieuw bericht!</string>
<string name="liked_notification">%1$s vond je bericht leuk</string>
<string name="shared_notification">%1$s heeft je bericht gedeeld</string>
<string name="mention_notification">%1$s heeft je genoemd</string>
<string name="followed_notification">%1$s volgt je</string>
<string name="attachment_summary_off">Bijlagen alleen downloaden bij handmatige toestemming</string>
<string name="auth_failed">Kon niet authenticeren</string>
<string name="app_name">PixelDroid</string>
<string name="save_to_gallery">Opslaan in gallerij…</string>
@ -31,8 +24,7 @@
<string name="image_download_downloading">Word gedownload…</string>
<string name="image_download_success">Afbeelding met succes gedownload</string>
<string name="share_picture">Afbeelding delen…</string>
<string name="capture_mode_camera">Camera</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Verborgen Media
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Verborgen Media
\n (Klik om weer te geven)</string>
<string name="lbl_brightness">Helderheid</string>
<string name="lbl_contrast">CONTRAST</string>
@ -42,14 +34,10 @@
<string name="capture_button_alt">Vastleggen</string>
<string name="switch_camera_button_alt">Van camera wisselen</string>
<string name="gallery_button_alt">Gallerij</string>
<string name="enter">Enter</string>
<string name="delete_title">Bevestigen</string>
<string name="NoCommentsToShow">Geen reacties op dit bericht…</string>
<string name="CommentDisplay">weer te geven…</string>
<string name="domain_of_your_instance">Domein van je instance</string>
<string name="connect_to_pixelfed">Met Pixelfed verbinden</string>
<string name="login_connection_required_once">Je moet in ieder geval één keer met het internet verbonden zijn geweest om PixelDroid te kunnen gebruiken :(</string>
<string name="you_are_in_offline_mode">Je bent in de offline modus, maar je kan nog steeds bepaalde inhoud zien!</string>
<string name="auth_error_toast_msg">De server heeft gereageerd met een foutmelding, probeer opnieuw!</string>
<string name="login_empty_string_error">Instance adres mag niet leeg zijn!</string>
</resources>

View File

@ -8,9 +8,6 @@
<string name="followed_notification">%1$s подписался на вас</string>
<string name="mention_notification">%1$s упомянул вас</string>
<string name="shared_notification">%1$s поделился вашим пост</string>
<string name="create_a_new_post">Создайте новый пост!</string>
<string name="upload_a_picture">Загрузите изображение</string>
<string name="or">или</string>
<string name="send">отправить</string>
<string name="logout">Выйти</string>
<string name="lbl_brightness">ЯРКОСТЬ</string>
@ -24,31 +21,22 @@
<string name="image_download_success">Изображение успешно загружено</string>
<string name="switch_camera_button_alt">Переключить камеру</string>
<string name="gallery_button_alt">Галерея</string>
<string name="capture_mode_camera">Камера</string>
<string name="delete_title">Подтвердить</string>
<string name="NoCommentsToShow">Нет комментариев под этим постом…</string>
<string name="CommentDisplay">показать…</string>
<string name="domain_of_your_instance">Домен вашего инстанса</string>
<string name="connect_to_pixelfed">Подключение к Pixelfed</string>
<string name="menu_slideshow">Имя аккаунта</string>
<string name="app_name">PixelDroid</string>
<string name="menu_subtitle">Информация об аккаунте</string>
<string name="menu_account">Мой профиль</string>
<string name="menu_settings">Настройки</string>
<string name="invalid_domain">Неправильное доменное имя</string>
<string name="browser_launch_failed">Не удалось запустить браузер, есть ли он у вас\?</string>
<string name="attachment_summary_off">Вложения скачиваются только вручную по запросу</string>
<string name="liked_notification">%1$s понравился ваш пост</string>
<string name="take_a_picture">Выберите изображение</string>
<string name="description">Описание…</string>
<string name="image_download_failed">Скачивание не удалось, попробуйте ещё раз</string>
<string name="share_picture">Поделиться изображение…</string>
<string name="login_connection_required_once">Вам необходимо подключение к интернету что бы использовать PixelDroid :(</string>
<string name="you_are_in_offline_mode">Вы в оффлайн режиме, но вы можете видеть некоторый контент!</string>
<string name="enter">Войти</string>
<string name="auth_error_toast_msg">Сервер ответил ошибокой, попробуйте ещё раз!</string>
<string name="login_empty_string_error">Адрес инстанса не может быть пустым!</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Скрытое медиа
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Скрытое медиа
\n (кликните что бы показать)</string>
<string name="registration_failed">Не удалось зарегистрировать приложение на этом инстансе</string>
<string name="capture_button_alt">Захватить</string>

View File

@ -4,13 +4,10 @@
<string name="invalid_domain">Ogiltig domän</string>
<string name="menu_settings">Inställningar</string>
<string name="menu_account">Min profil</string>
<string name="menu_subtitle">Kontoinformation</string>
<string name="menu_slideshow">Kontonamn</string>
<string name="app_name">PixelDroid</string>
<string name="browser_launch_failed">Kunde inte starta en webbläsare, har du en\?</string>
<string name="token_error">Fel vid hämtning av token</string>
<string name="auth_failed">Kunde inte autentisera</string>
<string name="attachment_summary_off">Enbart nedladdade bilagor när manuellt efterfrågade</string>
<string name="title_activity_settings2">Inställningar</string>
<string name="domain_of_your_instance">Instansens domän</string>
<string name="save_to_gallery">Spara till galleri…</string>
@ -24,12 +21,7 @@
<string name="mention_notification">%1$s nämnde dig</string>
<string name="shared_notification">%1$s delande ditt inlägg</string>
<string name="liked_notification">%1$s gillar ditt inlägg</string>
<string name="create_a_new_post">Skapa ett nytt inlägg!</string>
<string name="take_a_picture">Ta en bild</string>
<string name="upload_a_picture">Ladda upp en bild</string>
<string name="or">eller</string>
<string name="description">Beskrivning…</string>
<string name="enter">Enter</string>
<string name="send">skicka</string>
<string name="whats_an_instance">Vad är en instans\?</string>
<string name="logout">Logga av</string>
@ -41,15 +33,11 @@
<string name="capture_button_alt">Lagra</string>
<string name="switch_camera_button_alt">Byt kamera</string>
<string name="gallery_button_alt">Galleri</string>
<string name="capture_mode_camera">Kamera</string>
<string name="delete_title">Bekräfta</string>
<string name="share_picture">Dela bild…</string>
<string name="NoCommentsToShow">Inga kommentarer på detta inlägg…</string>
<string name="CommentDisplay">att visa…</string>
<string name="connect_to_pixelfed">Anslut till Pixelfed</string>
<string name="you_are_in_offline_mode">Du är i nedkopplad läge, men du kan ändå se lite innehåll!</string>
<string name="auth_error_toast_msg">Servern svarade med ett fel, försök igen!</string>
<string name="login_empty_string_error">Instansadressen får inte vara tom!</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Dold media
\n(Tryck för att visa)</string>
</resources>

View File

@ -2,17 +2,12 @@
<resources>
<string name="browser_launch_failed">Не вдалося відкрити браузер, він у вас є\?</string>
<string name="image_download_failed">Не вдалося завантажити, спробуйте знову</string>
<string name="menu_subtitle">Інформація про акаунт</string>
<string name="menu_account">Мій профіль</string>
<string name="invalid_domain">Недоступний домен</string>
<string name="title_activity_settings2">Налаштування</string>
<string name="theme_title">Тема застосунку</string>
<string name="theme_header">Тема</string>
<string name="mention_notification">%1$s згадав(-ла) вас</string>
<string name="create_a_new_post">Створити новий пост!</string>
<string name="take_a_picture">Сфотографувати</string>
<string name="upload_a_picture">Завантажити фото</string>
<string name="or">або</string>
<string name="description">Опис…</string>
<string name="send">відправити</string>
<string name="lbl_brightness">Яскравість</string>
@ -24,8 +19,6 @@
<string name="image_download_success">Зображення успішно завантажено</string>
<string name="switch_camera_button_alt">Перемкнути камеру</string>
<string name="gallery_button_alt">Галерея</string>
<string name="capture_mode_camera">Камера</string>
<string name="delete_title">Підтвердити</string>
<string name="share_picture">Поділитися фотографією…</string>
<string name="logout">Вийти</string>
<string name="NoCommentsToShow">Немає коментарів до цієї публікації…</string>

View File

@ -1,8 +0,0 @@
<resources>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="menu_slideshow">用户名</string>
<string name="registration_failed">无法在此服务器上注册应用程序</string>
<string name="browser_launch_failed">无法跳转至浏览器,请确认是否安装</string>
<string name="image_download_success">成功下载图像</string>
@ -13,18 +12,12 @@
<string name="send">发送</string>
<string name="logout">注销</string>
<string name="app_name">PixelDroid</string>
<string name="menu_subtitle">用户信息</string>
<string name="title_activity_settings2">配置</string>
<string name="theme_title">应用主题</string>
<string name="attachment_summary_off">仅在手动请求时下载附件</string>
<string name="followed_notification">关注了你</string>
<string name="mention_notification">提到了你</string>
<string name="shared_notification">分享了你的帖文</string>
<string name="liked_notification">给你的帖文点赞</string>
<string name="create_a_new_post">创建一条新帖文!</string>
<string name="take_a_picture">拍照</string>
<string name="upload_a_picture">上传图片</string>
<string name="or"></string>
<string name="description">描述……</string>
<string name="whats_an_instance">什么是实例?</string>
<string name="lbl_brightness">亮度</string>
@ -38,15 +31,10 @@
<string name="capture_button_alt">拍摄</string>
<string name="switch_camera_button_alt">切换摄像头</string>
<string name="gallery_button_alt">相册</string>
<string name="capture_mode_camera">相机</string>
<string name="delete_title">确认</string>
<string name="NoCommentsToShow">这条帖文下没有评论……</string>
<string name="CommentDisplay">显示……</string>
<string name="domain_of_your_instance">实例的域名</string>
<string name="you_are_in_offline_mode">您处于离线模式,但仍可以查看已缓存内容!</string>
<string name="login_empty_string_error">请输入实例地址!</string>
<string name="auth_error_toast_msg">服务器报错误,请重试!</string>
<string name="enter">输入</string>
<string name="connect_to_pixelfed">连接至 Pixelfed</string>
<string name="share_picture">分享图片……</string>
<string name="login_connection_required_once">您至少需要连接到互联网一次才能使用 PixelDroid :(</string>

View File

@ -1,15 +1,4 @@
<resources>
<!-- Reply Preference -->
<string-array name="reply_entries">
<item>Reply</item>
<item>Reply to all</item>
</string-array>
<string-array name="reply_values">
<item>reply</item>
<item>reply_all</item>
</string-array>
<string-array name="theme_values">
<item>default</item>
<item>light</item>

View File

@ -11,6 +11,5 @@
<color name="colorButtonText">#FFFFFF</color>
<color name="filterLabelNormal">#8A8889</color>
<color name="filterLabelSelected">#221F20</color>
<color name="colorOptionMenu">#FF3990</color>
<color name="colorPrimaryError">#FF0000</color>
</resources>

View File

@ -1,10 +1,4 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="nav_header_vertical_spacing">8dp</dimen>
<dimen name="nav_header_height">176dp</dimen>
<dimen name="margin_xsmall">16dp</dimen>
<dimen name="margin_small">32dp</dimen>
<dimen name="margin_medium">48dp</dimen>

View File

@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">PixelDroid</string>
<string name="menu_slideshow">Account name</string>
<string name="menu_subtitle">Account information</string>
<string name="menu_account">My Profile</string>
<string name="menu_settings">Settings</string>
<string name="invalid_domain">"Invalid domain"</string>
@ -10,25 +8,21 @@
<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>
<string name="instance_error">"Could not get instance information"</string>
<string name="title_activity_settings2">Settings</string>
<!-- Theme Preferences -->
<string name="theme_title">Application Theme</string>
<string name="theme_header">Theme</string>
<string name="attachment_summary_off">Only download attachments when manually requested</string>
<string name="followed_notification">%1$s followed you</string>
<string name="mention_notification">%1$s mentioned you</string>
<string name="shared_notification">%1$s shared your post</string>
<string name="liked_notification">%1$s liked your post</string>
<string name="create_a_new_post">Create a new post!</string>
<string name="take_a_picture">Take a picture</string>
<string name="upload_a_picture">Upload a picture</string>
<string name="or">or</string>
<string name="description">Description…</string>
<string name="send">send</string>
<string name="whats_an_instance">"What's an instance?"</string>
<string name="logout">Logout</string>
<string name="logout">Log out</string>
<string name="lbl_brightness">BRIGHTNESS</string>
<string name="lbl_contrast">CONTRAST</string>
@ -43,18 +37,15 @@
<string name="capture_button_alt">Capture</string>
<string name="switch_camera_button_alt">Switch camera</string>
<string name="gallery_button_alt">Gallery</string>
<string name="capture_mode_camera">Camera</string>
<string name="delete_title">Confirm</string>
<string name="share_picture">Share picture…</string>
<string name="NoCommentsToShow">No comments on this post…</string>
<string name="CommentDisplay"> to show…</string>
<string name="domain_of_your_instance">Domain of your instance</string>
<string name="connect_to_pixelfed">Connect to Pixelfed</string>
<string name="login_connection_required_once">You need to connect to the internet at least once to use PixelDroid :(</string>
<string name="login_connection_required_once">You need to be online to be able to add the first account and use PixelDroid :(</string>
<string name="you_are_in_offline_mode">You are in offline mode, but you can still view some content!</string>
<string name="enter">Enter</string>
<string name="auth_error_toast_msg">Server has responded with an error, try again!</string>
<string name="login_empty_string_error">Instance address cannot be empty!</string>
<string name="add_account_name">Add Account</string>
<string name="add_account_description">Add another Pixelfed Account</string>
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Hidden Media \n (click to show)</string>
</resources>

View File

@ -6,6 +6,8 @@
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="materialDrawerStyle">@style/Widget.MaterialDrawerStyle</item>
<item name="materialDrawerHeaderStyle">@style/Widget.MaterialDrawerHeaderStyle</item>
</style>
<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/theme</item>
@ -32,4 +34,10 @@
<item name="android:background">@android:color/holo_orange_light</item>
<item name="android:textAppearance">@android:style/TextAppearance.Large</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>