diff --git a/app/src/main/java/net/schueller/peertube/activity/ServerAddressBookActivity.kt b/app/src/main/java/net/schueller/peertube/activity/ServerAddressBookActivity.kt index e5fc96e..4a1f294 100644 --- a/app/src/main/java/net/schueller/peertube/activity/ServerAddressBookActivity.kt +++ b/app/src/main/java/net/schueller/peertube/activity/ServerAddressBookActivity.kt @@ -16,12 +16,16 @@ */ package net.schueller.peertube.activity +import android.app.Activity import android.app.AlertDialog import android.content.DialogInterface +import android.content.Intent import android.os.Bundle import android.util.Log +import android.widget.Toast import androidx.activity.viewModels import androidx.fragment.app.FragmentManager +import androidx.preference.PreferenceManager import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import net.schueller.peertube.R @@ -30,6 +34,9 @@ import net.schueller.peertube.database.Server import net.schueller.peertube.database.ServerViewModel import net.schueller.peertube.databinding.ActivityServerAddressBookBinding import net.schueller.peertube.fragment.AddServerFragment +import net.schueller.peertube.helper.APIUrlHelper +import net.schueller.peertube.network.Session +import net.schueller.peertube.service.LoginService import java.util.* class ServerAddressBookActivity : CommonActivity() { @@ -77,8 +84,32 @@ class ServerAddressBookActivity : CommonActivity() { } } + private fun onServerClick(server: Server) { + + val sharedPref = PreferenceManager.getDefaultSharedPreferences(this) + val editor = sharedPref.edit() + val serverUrl = APIUrlHelper.cleanServerUrl(server.serverHost) + editor.putString(getString(R.string.pref_api_base_key), serverUrl) + editor.apply() + + // Logout if logged in + val session = Session.getInstance() + if (session.isLoggedIn) { + session.invalidate() + } + + // attempt authentication if we have a username + if (server.username.isNullOrBlank().not()) { + LoginService.Authenticate(server.username, server.password) + } + + // close this activity + finish() + Toast.makeText(this, getString(R.string.server_selection_set_server, serverUrl), Toast.LENGTH_LONG).show() + } + private fun showServers() { - val adapter = ServerListAdapter(this).also { + val adapter = ServerListAdapter(mutableListOf()) { onServerClick(it) }.also { mBinding.serverListRecyclerview.adapter = it } @@ -110,7 +141,7 @@ class ServerAddressBookActivity : CommonActivity() { // Update the cached copy of the words in the adapter. - mServerViewModel.allServers.observe(this, { servers: List? -> + mServerViewModel.allServers.observe(this, { servers: List -> adapter.setServers(servers) addServerFragment?.let { diff --git a/app/src/main/java/net/schueller/peertube/adapter/ServerListAdapter.java b/app/src/main/java/net/schueller/peertube/adapter/ServerListAdapter.java deleted file mode 100644 index 06bd053..0000000 --- a/app/src/main/java/net/schueller/peertube/adapter/ServerListAdapter.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2020 Stefan Schüller - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package net.schueller.peertube.adapter; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.text.TextUtils; -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.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import net.schueller.peertube.R; - -import net.schueller.peertube.database.Server; -import net.schueller.peertube.helper.APIUrlHelper; -import net.schueller.peertube.network.Session; -import net.schueller.peertube.service.LoginService; - - -import java.util.List; - -import static android.app.Activity.RESULT_OK; - -public class ServerListAdapter extends RecyclerView.Adapter { - - - private final LayoutInflater mInflater; - private List mServers; // Cached copy of Servers - - public ServerListAdapter(Context context) { - this.mInflater = LayoutInflater.from(context); - } - - @NonNull - @Override - public ServerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View itemView = mInflater.inflate(R.layout.row_server_address_book, parent, false); - return new ServerViewHolder(itemView); - } - - @Override - public void onBindViewHolder(@NonNull ServerViewHolder holder, int position) { - - if (mServers != null) { - Server current = mServers.get(position); - holder.serverLabel.setText(current.getServerName()); - holder.serverUrl.setText(current.getServerHost()); - - if (TextUtils.isEmpty(current.getUsername())) { - holder.hasLogin.setVisibility(View.GONE); - } else { - holder.hasLogin.setVisibility(View.VISIBLE); - } - - } else { - // Covers the case of data not being ready yet. - holder.serverLabel.setText(R.string.server_book_no_servers_found); - } - - holder.itemView.setOnClickListener(v -> { - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mInflater.getContext()); - SharedPreferences.Editor editor = sharedPref.edit(); - - String serverUrl = APIUrlHelper.cleanServerUrl(getServerAtPosition(position).getServerHost()); - - editor.putString(mInflater.getContext().getString(R.string.pref_api_base_key), serverUrl); - editor.apply(); - - // Logout if logged in - Session session = Session.getInstance(); - if (session.isLoggedIn()) { - session.invalidate(); - } - - // attempt authentication if we have a username - if (!TextUtils.isEmpty(getServerAtPosition(position).getUsername())) { - LoginService.Authenticate( - getServerAtPosition(position).getUsername(), - getServerAtPosition(position).getPassword() - ); - } - - // tell server list activity to reload list - Intent intent = new Intent(); - ((Activity) mInflater.getContext()).setResult(RESULT_OK, intent); - - // close this activity - ((Activity) mInflater.getContext()).finish(); - - Toast.makeText(mInflater.getContext(), mInflater.getContext().getString(R.string.server_selection_set_server, serverUrl), Toast.LENGTH_LONG).show(); - - }); - - -// -// holder.itemView.setOnLongClickListener(v -> { -// Log.v("ServerListAdapter", "setOnLongClickListener " + position); -// return true; -// }); - - - } - - public void setServers(List Servers) { - mServers = Servers; - this.notifyDataSetChanged(); - } - - // getItemCount() is called many times, and when it is first called, - // mServers has not been updated (means initially, it's null, and we can't return null). - @Override - public int getItemCount() { - if (mServers != null) - return mServers.size(); - else return 0; - } - - static class ServerViewHolder extends RecyclerView.ViewHolder { - TextView serverLabel, serverUrl, serverUsername; - ImageView hasLogin; - - private ServerViewHolder(View itemView) { - super(itemView); - serverLabel = itemView.findViewById(R.id.serverLabelRow); - serverUrl = itemView.findViewById(R.id.serverUrlRow); - hasLogin = itemView.findViewById(R.id.sb_row_has_login_icon); - } - } - - public Server getServerAtPosition (int position) { - return mServers.get(position); - } -} \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/adapter/ServerListAdapter.kt b/app/src/main/java/net/schueller/peertube/adapter/ServerListAdapter.kt new file mode 100644 index 0000000..908a71c --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/adapter/ServerListAdapter.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2020 Stefan Schüller + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package net.schueller.peertube.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import net.schueller.peertube.adapter.ServerListAdapter.ServerViewHolder +import net.schueller.peertube.database.Server +import net.schueller.peertube.databinding.RowServerAddressBookBinding +import net.schueller.peertube.utils.visibleIf + +class ServerListAdapter(private val mServers: MutableList, private val onClick: (Server) -> Unit) : RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ServerViewHolder { + + val binding = RowServerAddressBookBinding.inflate(LayoutInflater.from(parent.context), parent, false) + + return ServerViewHolder(binding) + } + + override fun onBindViewHolder(holder: ServerViewHolder, position: Int) { + + holder.bind(mServers[position]) + +// +// holder.itemView.setOnLongClickListener(v -> { +// Log.v("ServerListAdapter", "setOnLongClickListener " + position); +// return true; +// }); + } + + fun setServers(servers: List) { + mServers.clear() + mServers.addAll(servers) + + notifyDataSetChanged() + } + + // getItemCount() is called many times, and when it is first called, + // mServers has not been updated (means initially, it's null, and we can't return null). + override fun getItemCount(): Int { + return mServers.size + } + + inner class ServerViewHolder (private val binding: RowServerAddressBookBinding) : RecyclerView.ViewHolder(binding.root) { + + fun bind(server: Server) { + + binding.serverLabelRow.text = server.serverName + binding.serverUrlRow.text = server.serverHost + binding.sbRowHasLoginIcon.visibleIf { server.username.isNullOrBlank().not() } + + binding.root.setOnClickListener { onClick(server) } + } + } + + fun getServerAtPosition(position: Int): Server { + return mServers[position] + } +} \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/database/Server.java b/app/src/main/java/net/schueller/peertube/database/Server.java deleted file mode 100644 index 5240e27..0000000 --- a/app/src/main/java/net/schueller/peertube/database/Server.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2020 Stefan Schüller - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package net.schueller.peertube.database; - -import androidx.annotation.NonNull; -import androidx.room.ColumnInfo; -import androidx.room.Entity; -import androidx.room.PrimaryKey; - -@Entity(tableName = "server_table") -public class Server { - - @PrimaryKey(autoGenerate = true) - private int id; - - @NonNull - @ColumnInfo(name = "server_name") - private String serverName; - - @ColumnInfo(name = "server_host") - private String serverHost; - - @ColumnInfo(name = "username") - private String username; - - @ColumnInfo(name = "password") - private String password; - - public Server(@NonNull String serverName) { - this.serverName = serverName; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getServerName() { - return serverName; - } - - public void setServerName(String serverName) { - this.serverName = serverName; - } - - public String getServerHost() { - return serverHost; - } - - public void setServerHost(String serverHost) { - this.serverHost = serverHost; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } -} diff --git a/app/src/main/java/net/schueller/peertube/database/Server.kt b/app/src/main/java/net/schueller/peertube/database/Server.kt new file mode 100644 index 0000000..19f9d7f --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/database/Server.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 Stefan Schüller + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package net.schueller.peertube.database + +import android.os.Parcelable +import androidx.room.PrimaryKey +import androidx.room.ColumnInfo +import androidx.room.Entity +import kotlinx.android.parcel.Parcelize + +@Parcelize +@Entity(tableName = "server_table") +data class Server( + + @PrimaryKey(autoGenerate = true) + var id: Int = 0, + + @ColumnInfo(name = "server_name") + var serverName: String, + + @ColumnInfo(name = "server_host") + var serverHost: String? = null, + + @ColumnInfo(name = "username") + var username: String? = null, + + @ColumnInfo(name = "password") + var password: String? = null + +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/fragment/AddServerFragment.kt b/app/src/main/java/net/schueller/peertube/fragment/AddServerFragment.kt index d6088a1..099a98a 100644 --- a/app/src/main/java/net/schueller/peertube/fragment/AddServerFragment.kt +++ b/app/src/main/java/net/schueller/peertube/fragment/AddServerFragment.kt @@ -42,10 +42,17 @@ class AddServerFragment : Fragment() { private val mServerViewModel: ServerViewModel by activityViewModels() + private var mServer: Server? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + arguments?.let { + mServer = it.getParcelable(SERVER_ARG) + } + } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - Log.d(TAG, "onCreateView") - // Inflate the layout for this fragment mBinding = FragmentAddServerBinding.inflate(inflater, container, false) return mBinding.root } @@ -53,22 +60,20 @@ class AddServerFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - // bind button click + initServerEdit() - mBinding.addServerButton.setOnClickListener { view: View? -> + mBinding.addServerButton.setOnClickListener { var formValid = true hideKeyboard() - - if (mBinding.serverLabel.text.toString().isNullOrBlank()) { + if (mBinding.serverLabel.text.toString().isBlank()) { mBinding.serverLabel.error = getString(R.string.server_book_label_is_required) Toast.makeText(context, R.string.invalid_url, Toast.LENGTH_LONG).show() formValid = false } // validate url - mBinding.serverUrl.apply { APIUrlHelper.cleanServerUrl(text.toString())?.let { @@ -85,7 +90,7 @@ class AddServerFragment : Fragment() { if (formValid) { mBinding.apply { - val server = Server(serverLabel.text.toString()) + val server = Server(serverName = serverLabel.text.toString()) server.serverHost = serverUrl.text.toString() server.username = serverUsername.text.toString() @@ -96,21 +101,26 @@ class AddServerFragment : Fragment() { } } -// Button testServerButton = mView.findViewById(R.id.testServerButton); -// testServerButton.setOnClickListener(view -> { -// Activity act = getActivity(); -// if (act instanceof ServerAddressBookActivity) { -// ((ServerAddressBookActivity) act).testServer(); -// } -// }); - - mBinding.pickServerUrl.setOnClickListener { val intentServer = Intent(activity, SearchServerActivity::class.java) this.startActivityForResult(intentServer, PICK_SERVER) } } + private fun initServerEdit() { + mServer?.let { + mBinding.apply { + serverLabel.setText(it.serverName) + serverUrl.setText(it.serverHost) + serverUsername.setText(it.username) + serverPassword.setText(it.password) + + addServerButton.text = getString(R.string.server_book_add_save_button) + } + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) @@ -136,7 +146,16 @@ class AddServerFragment : Fragment() { } companion object { - const val TAG = "AddServerFragment" - const val PICK_SERVER = 1 + private const val TAG = "AddServerFragment" + private const val PICK_SERVER = 1 + + private const val SERVER_ARG = "server" + + fun newInstance(server: Server) = AddServerFragment().apply { + arguments = Bundle().also { + it.putParcelable(SERVER_ARG, server) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/net/schueller/peertube/utils/Extensions.kt b/app/src/main/java/net/schueller/peertube/utils/Extensions.kt index 14bf8ba..6a4600a 100644 --- a/app/src/main/java/net/schueller/peertube/utils/Extensions.kt +++ b/app/src/main/java/net/schueller/peertube/utils/Extensions.kt @@ -1,10 +1,44 @@ package net.schueller.peertube.utils import android.content.Context +import android.view.View import android.view.inputmethod.InputMethodManager import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment +fun View.gone() { + this.visibility = View.GONE +} + +fun View.visible() { + this.visibility = View.VISIBLE +} + +fun View.invisible() { + this.visibility = View.INVISIBLE +} + +fun View.visibleIf(predicate: () -> Boolean) { + when (predicate.invoke()) { + true -> visible() + else -> gone() + } +} + +fun View.goneIf(predicate: () -> Boolean) { + when (predicate.invoke()) { + true -> gone() + else -> visible() + } +} + +fun View.invisibleIf(predicate: () -> Boolean) { + when (predicate.invoke()) { + true -> invisible() + else -> visible() + } +} + fun Fragment.hideKeyboard(): Boolean { activity?.currentFocus?.let { val imm = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager diff --git a/app/src/main/res/drawable/ic_edit_24.xml b/app/src/main/res/drawable/ic_edit_24.xml new file mode 100644 index 0000000..2844baf --- /dev/null +++ b/app/src/main/res/drawable/ic_edit_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/row_server_address_book.xml b/app/src/main/res/layout/row_server_address_book.xml index aa0911e..7c935cf 100644 --- a/app/src/main/res/layout/row_server_address_book.xml +++ b/app/src/main/res/layout/row_server_address_book.xml @@ -1,6 +1,8 @@ - - - + card_view:layout_constraintTop_toTopOf="parent" + card_view:layout_constraintStart_toStartOf="parent" + android:textAppearance="@style/Base.TextAppearance.AppCompat.Headline" + tools:text="@tools:sample/lorem" + /> - - - - - + + android:layout_height="wrap_content" + card_view:layout_constraintTop_toTopOf="parent" + card_view:layout_constraintEnd_toEndOf="parent" + android:contentDescription="@string/server_book_list_has_login" + android:src="@drawable/ic_baseline_account_circle_24" + /> - + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7c73b7e..d4a765e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -335,6 +335,7 @@ Username Password Add + Save Has Login Current Server Address Book