Commit 9af4591a authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Adds the admin panel.

parent f68e4a56
...@@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView ...@@ -17,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.createchannel.presentation.CreateChannelPresenter import chat.rocket.android.createchannel.presentation.CreateChannelPresenter
import chat.rocket.android.createchannel.presentation.CreateChannelView import chat.rocket.android.createchannel.presentation.CreateChannelView
import chat.rocket.android.main.ui.MENU_ACTION_CHATS
import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.members.adapter.MembersAdapter import chat.rocket.android.members.adapter.MembersAdapter
import chat.rocket.android.members.uimodel.MemberUiModel import chat.rocket.android.members.uimodel.MemberUiModel
...@@ -161,7 +162,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback ...@@ -161,7 +162,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
override fun prepareToShowChatList() { override fun prepareToShowChatList() {
with(activity as MainActivity) { with(activity as MainActivity) {
setCheckedNavDrawerItem(R.id.action_chat_rooms) setCheckedNavDrawerItem(MENU_ACTION_CHATS)
openDrawer() openDrawer()
getDrawerLayout().postDelayed(1000) { getDrawerLayout().postDelayed(1000) {
closeDrawer() closeDrawer()
......
...@@ -2,7 +2,6 @@ package chat.rocket.android.helper ...@@ -2,7 +2,6 @@ package chat.rocket.android.helper
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SettingsRepository import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
import chat.rocket.common.model.SimpleUser import chat.rocket.common.model.SimpleUser
...@@ -12,43 +11,13 @@ import javax.inject.Inject ...@@ -12,43 +11,13 @@ import javax.inject.Inject
class UserHelper @Inject constructor( class UserHelper @Inject constructor(
private val localRepository: LocalRepository, private val localRepository: LocalRepository,
private val getCurrentServerInteractor: GetCurrentServerInteractor, private val getCurrentServerInteractor: GetCurrentServerInteractor,
settingsRepository: SettingsRepository private val settingsRepository: SettingsRepository
) { ) {
private val settings: PublicSettings = settingsRepository.get(getCurrentServerInteractor.get()!!)
/**
* Return the display name for the given [user].
* If setting 'Use_Real_Name' is true then the real name will be given, or else
* the username without the '@' is yielded. The fallback for any case is the username, which
* could be null.
*/
fun displayName(user: User): String? {
return if (settings.useRealName()) user.name ?: user.username else user.username
}
fun displayName(user: SimpleUser): String {
return if (settings.useRealName()) user.name ?: user.username ?: "" else user.username ?: ""
}
/**
* Return current logged user's display name.
*
* @see displayName
*/
fun displayName(): String? {
user()?.let {
return displayName(it)
}
return null
}
/** /**
* Return current logged [User]. * Return current logged [User].
*/ */
fun user(): User? { fun user(): User? = getCurrentServerInteractor.get()?.let { localRepository.getCurrentUser(it) }
return localRepository.getCurrentUser(serverUrl())
}
/** /**
* Return the username for the current logged [User]. * Return the username for the current logged [User].
...@@ -56,13 +25,23 @@ class UserHelper @Inject constructor( ...@@ -56,13 +25,23 @@ class UserHelper @Inject constructor(
fun username(): String? = localRepository.get(LocalRepository.CURRENT_USERNAME_KEY, null) fun username(): String? = localRepository.get(LocalRepository.CURRENT_USERNAME_KEY, null)
/** /**
* Whether current [User] is admin on the current server. * Return the display name for the given [user].
* If setting 'Use_Real_Name' is true then the real name will be given, otherwise the username
* without the '@' is yielded.
*/ */
fun isAdmin(): Boolean { fun displayName(user: SimpleUser): String {
return user()?.roles?.find { it.equals("admin", ignoreCase = true) } != null val displayName: String? = getCurrentServerInteractor.get()?.let {
if (settingsRepository.get(it).useRealName()) {
user.name
} else {
user.username
}
}
return displayName ?: ""
} }
private fun serverUrl(): String { /**
return getCurrentServerInteractor.get()!! * Whether current [User] is admin on the current server.
} */
} fun isAdmin(): Boolean = user()?.roles?.find { it.equals("admin", true) } != null
\ No newline at end of file }
...@@ -10,6 +10,7 @@ import chat.rocket.android.profile.ui.ProfileFragment ...@@ -10,6 +10,7 @@ import chat.rocket.android.profile.ui.ProfileFragment
import chat.rocket.android.server.ui.changeServerIntent import chat.rocket.android.server.ui.changeServerIntent
import chat.rocket.android.settings.ui.SettingsFragment import chat.rocket.android.settings.ui.SettingsFragment
import chat.rocket.android.util.extensions.addFragment import chat.rocket.android.util.extensions.addFragment
import chat.rocket.android.webview.adminpanel.ui.AdminPanelWebViewFragment
class MainNavigator(internal val activity: MainActivity) { class MainNavigator(internal val activity: MainActivity) {
...@@ -37,6 +38,12 @@ class MainNavigator(internal val activity: MainActivity) { ...@@ -37,6 +38,12 @@ class MainNavigator(internal val activity: MainActivity) {
} }
} }
fun toAdminPanel(webPageUrl: String, userToken: String) {
activity.addFragment("AdminPanelWebViewFragment", R.id.fragment_container) {
AdminPanelWebViewFragment.newInstance(webPageUrl, userToken)
}
}
fun toChatRoom( fun toChatRoom(
chatRoomId: String, chatRoomId: String,
chatRoomName: String, chatRoomName: String,
......
...@@ -19,6 +19,7 @@ import chat.rocket.android.server.infraestructure.ConnectionManagerFactory ...@@ -19,6 +19,7 @@ import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.adminPanelUrl
import chat.rocket.android.util.extensions.registerPushToken import chat.rocket.android.util.extensions.registerPushToken
import chat.rocket.android.util.extensions.serverLogoUrl import chat.rocket.android.util.extensions.serverLogoUrl
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
...@@ -27,14 +28,12 @@ import chat.rocket.common.RocketChatException ...@@ -27,14 +28,12 @@ import chat.rocket.common.RocketChatException
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.realtime.setDefaultStatus
import chat.rocket.core.internal.rest.logout import chat.rocket.core.internal.rest.logout
import chat.rocket.core.internal.rest.me import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.unregisterPushToken import chat.rocket.core.internal.rest.unregisterPushToken
import chat.rocket.core.model.Myself import chat.rocket.core.model.Myself
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.channels.Channel import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
...@@ -61,7 +60,6 @@ class MainPresenter @Inject constructor( ...@@ -61,7 +60,6 @@ class MainPresenter @Inject constructor(
private val dbManager = dbManagerFactory.create(currentServer) private val dbManager = dbManagerFactory.create(currentServer)
private val client: RocketChatClient = factory.create(currentServer) private val client: RocketChatClient = factory.create(currentServer)
private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!) private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!)
private val userDataChannel = Channel<Myself>() private val userDataChannel = Channel<Myself>()
fun toChatList(chatRoomId: String? = null) = navigator.toChatList(chatRoomId) fun toChatList(chatRoomId: String? = null) = navigator.toChatList(chatRoomId)
...@@ -70,6 +68,10 @@ class MainPresenter @Inject constructor( ...@@ -70,6 +68,10 @@ class MainPresenter @Inject constructor(
fun toSettings() = navigator.toSettings() fun toSettings() = navigator.toSettings()
fun toAdminPanel() = tokenRepository.get(currentServer)?.let {
navigator.toAdminPanel(currentServer.adminPanelUrl(), it.authToken)
}
fun toCreateChannel() = navigator.toCreateChannel() fun toCreateChannel() = navigator.toCreateChannel()
fun loadServerAccounts() { fun loadServerAccounts() {
......
...@@ -9,11 +9,11 @@ import androidx.fragment.app.Fragment ...@@ -9,11 +9,11 @@ import androidx.fragment.app.Fragment
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import android.view.Gravity import android.view.Gravity
import android.view.MenuItem
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import chat.rocket.android.BuildConfig import chat.rocket.android.BuildConfig
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.main.adapter.AccountsAdapter import chat.rocket.android.main.adapter.AccountsAdapter
import chat.rocket.android.main.adapter.Selector import chat.rocket.android.main.adapter.Selector
import chat.rocket.android.main.presentation.MainPresenter import chat.rocket.android.main.presentation.MainPresenter
...@@ -51,6 +51,8 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -51,6 +51,8 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment> lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
@Inject @Inject
lateinit var presenter: MainPresenter lateinit var presenter: MainPresenter
@Inject
lateinit var userHelper: UserHelper
private var isFragmentAdded: Boolean = false private var isFragmentAdded: Boolean = false
private var expanded = false private var expanded = false
private val headerLayout by lazy { view_navigation.getHeaderView(0) } private val headerLayout by lazy { view_navigation.getHeaderView(0) }
...@@ -169,7 +171,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -169,7 +171,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
} }
headerLayout.image_avatar.setOnClickListener { headerLayout.image_avatar.setOnClickListener {
view_navigation.menu.findItem(R.id.action_profile).isChecked = true view_navigation.menu.findItem(MENU_ACTION_PROFILE).isChecked = true
presenter.toUserProfile() presenter.toUserProfile()
drawer_layout.closeDrawer(Gravity.START) drawer_layout.closeDrawer(Gravity.START)
} }
...@@ -221,37 +223,20 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -221,37 +223,20 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
} }
fun setupNavigationView() { fun setupNavigationView() {
view_navigation.setNavigationItemSelectedListener { menuItem -> with (view_navigation.menu) {
menuItem.isChecked = true clear()
setupMenu(this)
}
view_navigation.setNavigationItemSelectedListener {
it.isChecked = true
closeDrawer() closeDrawer()
onNavDrawerItemSelected(menuItem) onNavDrawerItemSelected(it)
true true
} }
toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp) toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp)
toolbar.setNavigationOnClickListener { toolbar.setNavigationOnClickListener { openDrawer() }
openDrawer()
}
}
private fun onNavDrawerItemSelected(menuItem: MenuItem) {
when (menuItem.itemId) {
R.id.action_chat_rooms -> {
presenter.toChatList()
}
R.id.action_profile -> {
presenter.toUserProfile()
}
R.id.action_channel -> {
presenter.toCreateChannel()
}
R.id.action_settings -> {
presenter.toSettings()
}
R.id.action_logout -> {
presenter.logout()
}
}
} }
fun getDrawerLayout(): DrawerLayout = drawer_layout fun getDrawerLayout(): DrawerLayout = drawer_layout
......
package chat.rocket.android.main.ui
import android.view.Menu
import android.view.MenuItem
import chat.rocket.android.R
private const val MENU_SECTION_ONE = 1
private const val MENU_SECTION_TWO = 2
private const val MENU_SECTION_THREE = 3
const val MENU_ACTION_CHATS = 1
private const val MENU_ACTION_CREATE_CHANNEL = 2
const val MENU_ACTION_PROFILE = 3
private const val MENU_ACTION_SETTINGS = 4
private const val MENU_ACTION_ADMIN_PANEL = 5
private const val MENU_ACTION_LOGOUT = 6
internal fun MainActivity.setupMenu(menu: Menu) {
menu.add(
MENU_SECTION_ONE,
MENU_ACTION_CHATS,
Menu.NONE,
R.string.title_chats
).setIcon(R.drawable.ic_chat_bubble_black_24dp)
.isChecked = true
menu.add(
MENU_SECTION_ONE,
MENU_ACTION_CREATE_CHANNEL,
Menu.NONE,
R.string.action_create_channel
).setIcon(R.drawable.ic_create_black_24dp)
menu.add(
MENU_SECTION_TWO,
MENU_ACTION_PROFILE,
Menu.NONE,
R.string.title_profile
).setIcon(R.drawable.ic_person_black_24dp)
menu.add(
MENU_SECTION_TWO,
MENU_ACTION_SETTINGS,
Menu.NONE,
R.string.title_settings
).setIcon(R.drawable.ic_settings_black_24dp)
if (userHelper.isAdmin()) {
menu.add(
MENU_SECTION_TWO,
MENU_ACTION_ADMIN_PANEL,
Menu.NONE,
R.string.title_admin_panel
).setIcon(R.drawable.ic_settings_black_24dp)
}
menu.add(
MENU_SECTION_THREE,
MENU_ACTION_LOGOUT,
Menu.NONE,
R.string.action_logout
).setIcon(R.drawable.ic_logout_black_24dp)
menu.setGroupCheckable(MENU_SECTION_ONE, true, true)
menu.setGroupCheckable(MENU_SECTION_TWO, true, true)
menu.setGroupCheckable(MENU_SECTION_THREE, true, true)
}
internal fun MainActivity.onNavDrawerItemSelected(menuItem: MenuItem) {
when (menuItem.itemId) {
MENU_ACTION_CHATS -> presenter.toChatList()
MENU_ACTION_CREATE_CHANNEL -> presenter.toCreateChannel()
MENU_ACTION_PROFILE -> presenter.toUserProfile()
MENU_ACTION_SETTINGS -> presenter.toSettings()
MENU_ACTION_ADMIN_PANEL -> presenter.toAdminPanel()
MENU_ACTION_LOGOUT -> presenter.logout()
}
}
...@@ -19,9 +19,6 @@ import kotlinx.android.synthetic.main.fragment_settings.* ...@@ -19,9 +19,6 @@ import kotlinx.android.synthetic.main.fragment_settings.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListener { class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListener {
companion object {
fun newInstance() = SettingsFragment()
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
...@@ -69,4 +66,8 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen ...@@ -69,4 +66,8 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen
startActivity(Intent(activity, classType.java)) startActivity(Intent(activity, classType.java))
activity?.overridePendingTransition(R.anim.open_enter, R.anim.open_exit) activity?.overridePendingTransition(R.anim.open_enter, R.anim.open_exit)
} }
companion object {
fun newInstance() = SettingsFragment()
}
} }
...@@ -50,6 +50,8 @@ fun String.termsOfServiceUrl() = "${removeTrailingSlash()}/terms-of-service" ...@@ -50,6 +50,8 @@ fun String.termsOfServiceUrl() = "${removeTrailingSlash()}/terms-of-service"
fun String.privacyPolicyUrl() = "${removeTrailingSlash()}/privacy-policy" fun String.privacyPolicyUrl() = "${removeTrailingSlash()}/privacy-policy"
fun String.adminPanelUrl() = "${removeTrailingSlash()}/admin/info?layout=embedded"
fun String.isValidUrl(): Boolean = Patterns.WEB_URL.matcher(this).matches() fun String.isValidUrl(): Boolean = Patterns.WEB_URL.matcher(this).matches()
fun String.parseColor(): Int { fun String.parseColor(): Int {
......
package chat.rocket.android.webview.adminpanel.ui
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.util.extensions.inflate
import kotlinx.android.synthetic.main.fragment_admin_panel_web_view.*
private const val BUNDLE_WEB_PAGE_URL = "web_page_url"
private const val BUNDLE_USER_TOKEN = "user_token"
class AdminPanelWebViewFragment : Fragment() {
private lateinit var webPageUrl: String
private lateinit var userToken: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bundle = arguments
if (bundle != null) {
webPageUrl = bundle.getString(BUNDLE_WEB_PAGE_URL)
userToken = bundle.getString(BUNDLE_USER_TOKEN)
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = container?.inflate(R.layout.fragment_admin_panel_web_view)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToolbar()
setupWebView()
}
private fun setupToolbar() {
(activity as AppCompatActivity?)?.supportActionBar?.title =
getString(R.string.title_admin_panel)
}
@SuppressLint("SetJavaScriptEnabled")
private fun setupWebView() {
web_view.settings.javaScriptEnabled = true
web_view.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
view_loading.hide()
web_view.evaluateJavascript("Meteor.loginWithToken('$userToken', function() { })") {}
}
}
web_view.loadUrl(webPageUrl)
}
companion object {
fun newInstance(webPageUrl: String, userToken: String) = AdminPanelWebViewFragment().apply {
arguments = Bundle(2).apply {
putString(BUNDLE_WEB_PAGE_URL, webPageUrl)
putString(BUNDLE_USER_TOKEN, userToken)
}
}
}
}
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:viewportWidth="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M10.09,15.59L11.5,17l5,-5 -5,-5 -1.41,1.41L12.67,11H3v2h9.67l-2.58,2.59zM19,3H5c-1.11,0 -2,0.9 -2,2v4h2V5h14v14H5v-4H3v4c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z" /> android:pathData="M10.09,15.59L11.5,17l5,-5 -5,-5 -1.41,1.41L12.67,11H3v2h9.67l-2.58,2.59zM19,3H5c-1.11,0 -2,0.9 -2,2v4h2V5h14v14H5v-4H3v4c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z" />
</vector> </vector>
\ No newline at end of file
...@@ -33,8 +33,7 @@ ...@@ -33,8 +33,7 @@
android:id="@+id/view_navigation" android:id="@+id/view_navigation"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
app:headerLayout="@layout/nav_header" app:headerLayout="@layout/nav_header" />
app:menu="@menu/navigation" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/accounts_list" android:id="@+id/accounts_list"
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".webview.adminpanel.ui.AdminPanelWebViewFragment">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
android:id="@+id/menu_section_1"
android:checkableBehavior="single">
<item
android:id="@+id/action_chat_rooms"
android:checked="true"
android:icon="@drawable/ic_chat_bubble_black_24dp"
android:title="@string/title_chats" />
<item
android:id="@+id/action_channel"
android:icon="@drawable/ic_create_black_24dp"
android:title="@string/action_create_channel" />
</group>
<group
android:id="@+id/menu_section_2"
android:checkableBehavior="single">
<item
android:id="@+id/action_profile"
android:icon="@drawable/ic_person_black_24dp"
android:title="@string/title_profile" />
<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_settings_black_24dp"
android:title="@string/title_settings" />
</group>
<group
android:id="@+id/menu_section_3"
android:checkableBehavior="single">
<item
android:id="@+id/action_logout"
android:icon="@drawable/ic_exit_to_app_black_24dp"
android:title="@string/action_logout" />
</group>
</menu>
\ No newline at end of file
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
<string name="title_profile">Profil</string> <string name="title_profile">Profil</string>
<string name="title_members">Benutzer (%d)</string> <string name="title_members">Benutzer (%d)</string>
<string name="title_settings">Einstellungen</string> <string name="title_settings">Einstellungen</string>
<string name="title_admin_panel">Admin panel</string> <!-- TODO Add translation -->
<string name="title_password">Ändere Passwort</string> <string name="title_password">Ändere Passwort</string>
<string name="title_update_profile">Update Profil</string> <string name="title_update_profile">Update Profil</string>
<string name="title_about">Über</string> <string name="title_about">Über</string>
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
<string name="title_profile">Perfil</string> <string name="title_profile">Perfil</string>
<string name="title_members">Miembros (%d)</string> <string name="title_members">Miembros (%d)</string>
<string name="title_settings">Configuraciones</string> <string name="title_settings">Configuraciones</string>
<string name="title_admin_panel">Admin panel</string> <!-- TODO Add translation -->
<string name="title_password">Cambia la contraseña</string> <string name="title_password">Cambia la contraseña</string>
<string name="title_update_profile">Actualización del perfil</string> <string name="title_update_profile">Actualización del perfil</string>
<string name="title_about">Acerca de</string> <string name="title_about">Acerca de</string>
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
<string name="title_profile">Profil</string> <string name="title_profile">Profil</string>
<string name="title_members">Membres (%d)</string> <string name="title_members">Membres (%d)</string>
<string name="title_settings">Paramètres</string> <string name="title_settings">Paramètres</string>
<string name="title_admin_panel">Admin panel</string> <!-- TODO Add translation -->
<string name="title_password">Changer le mot de passe</string> <string name="title_password">Changer le mot de passe</string>
<string name="title_update_profile">Update profile</string> <string name="title_update_profile">Update profile</string>
<string name="title_about">Sur</string> <string name="title_about">Sur</string>
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
<string name="title_profile">प्रोफाइल</string> <string name="title_profile">प्रोफाइल</string>
<string name="title_members">सदस्य (%d)</string> <string name="title_members">सदस्य (%d)</string>
<string name="title_settings">सेटिंग्स</string> <string name="title_settings">सेटिंग्स</string>
<string name="title_admin_panel">Admin panel</string> <!-- TODO Add translation -->
<string name="title_password">पासवर्ड बदलें</string> <string name="title_password">पासवर्ड बदलें</string>
<string name="title_update_profile">प्रोफ़ाइल अपडेट करें</string> <string name="title_update_profile">प्रोफ़ाइल अपडेट करें</string>
<string name="title_about">परिचय</string> <string name="title_about">परिचय</string>
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
<string name="title_profile">Perfil</string> <string name="title_profile">Perfil</string>
<string name="title_members">Membros (%d)</string> <string name="title_members">Membros (%d)</string>
<string name="title_settings">Configurações</string> <string name="title_settings">Configurações</string>
<string name="title_admin_panel">Painel administrativo</string>
<string name="title_password">Alterar senha</string> <string name="title_password">Alterar senha</string>
<string name="title_update_profile">Editar perfil</string> <string name="title_update_profile">Editar perfil</string>
<string name="title_about">Sobre</string> <string name="title_about">Sobre</string>
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
<string name="title_profile">Профиль</string> <string name="title_profile">Профиль</string>
<string name="title_members">Пользователи (%d)</string> <string name="title_members">Пользователи (%d)</string>
<string name="title_settings">Настройки</string> <string name="title_settings">Настройки</string>
<string name="title_admin_panel">Admin panel</string> <!-- TODO Add translation -->
<string name="title_password">Изменить пароль</string> <string name="title_password">Изменить пароль</string>
<string name="title_update_profile">Обновить профиль</string> <string name="title_update_profile">Обновить профиль</string>
<string name="title_about">О программе</string> <string name="title_about">О программе</string>
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
<string name="title_profile">Profile</string> <string name="title_profile">Profile</string>
<string name="title_members">Members (%d)</string> <string name="title_members">Members (%d)</string>
<string name="title_settings">Settings</string> <string name="title_settings">Settings</string>
<string name="title_admin_panel">Admin panel</string>
<string name="title_password">Change Password</string> <string name="title_password">Change Password</string>
<string name="title_update_profile">Update profile</string> <string name="title_update_profile">Update profile</string>
<string name="title_about">About</string> <string name="title_about">About</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment