diff --git a/CHANGELOG.md b/CHANGELOG.md index f054d1b..ea2b717 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### Version 1.0.25 Tag: v1.0.25 (2019-01-20) + * Account overview page and videos list + * Turkish (tr) Translation added (@oktay454) + ### Version 1.0.24 Tag: v1.0.24 (2019-01-09) * Set video quality (@digiwizkid) * BN Strings update (@digiwizkid) diff --git a/app/build.gradle b/app/build.gradle index 6ef20cd..5b0ca7b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,8 +6,8 @@ android { applicationId "net.schueller.peertube" minSdkVersion 21 targetSdkVersion 28 - versionCode 1024 - versionName "1.0.24" + versionCode 1025 + versionName "1.0.25" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" ext { libVersions = [ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index de4a1d2..073b0ba 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -52,10 +52,12 @@ - + videosLanguages; + + private ChannelAdapter channelAdapter; + private VideoAdapter videoAdapter; + + private RecyclerView recyclerViewVideos; + private RecyclerView recyclerViewChannels; + + private SwipeRefreshLayout swipeRefreshLayoutVideos; + private SwipeRefreshLayout swipeRefreshLayoutChannels; + private CoordinatorLayout aboutView; + //private TextView emptyView; + + private Boolean isLoadingVideos; + + private GetUserService userService; + + private String displayNameAndHost; @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.menu_top_user, menu); + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - // Set an icon in the ActionBar - menu.findItem(R.id.action_logout).setIcon( - new IconicsDrawable(this, FontAwesome.Icon.faw_sign_out_alt).actionBar()); + setContentView(R.layout.activity_account); - return true; - } + apiBaseURL = APIUrlHelper.getUrlWithVersion(this); + + userService = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class); + + recyclerViewVideos = findViewById(R.id.account_video_recyclerView); + recyclerViewChannels = findViewById(R.id.account_channel_recyclerView); + + swipeRefreshLayoutVideos = findViewById(R.id.account_swipeRefreshLayout_videos); + swipeRefreshLayoutChannels = findViewById(R.id.account_swipeRefreshLayout_channels); + aboutView = findViewById(R.id.account_about); + + RecyclerView.LayoutManager layoutManagerVideos = new LinearLayoutManager(AccountActivity.this); + recyclerViewVideos.setLayoutManager(layoutManagerVideos); + + RecyclerView.LayoutManager layoutManagerVideosChannels = new LinearLayoutManager(AccountActivity.this); + recyclerViewChannels.setLayoutManager(layoutManagerVideosChannels); + + videoAdapter = new VideoAdapter(new ArrayList<>(), AccountActivity.this); + recyclerViewVideos.setAdapter(videoAdapter); + + channelAdapter = new ChannelAdapter(new ArrayList<>(), AccountActivity.this); + recyclerViewChannels.setAdapter(channelAdapter); - @Override - public boolean onOptionsItemSelected(MenuItem item) { + swipeRefreshLayoutVideos.setOnRefreshListener(() -> { + // Refresh items + if (!isLoadingVideos) { + videosCurrentStart = 0; + loadAccountVideos(displayNameAndHost); + } + }); - switch (item.getItemId()) { - // action with ID action_refresh was selected + // get video ID + Intent intent = getIntent(); + displayNameAndHost = intent.getStringExtra(VideoListActivity.EXTRA_ACCOUNTDISPLAYNAME); + Log.v(TAG, "click: " + displayNameAndHost); - case R.id.action_logout: - Session.getInstance().invalidate(); - Intent intent = new Intent(this, LoginActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - this.startActivity(intent); - finish(); - return true; - default: - break; - } - return super.onOptionsItemSelected(item); + createBottomBarNavigation(); + + videosStart = 0; + videosCount = 25; + videosCurrentStart = 0; + videosFilter = ""; + videosSort = "-publishedAt"; + videosNsfw = ""; + + + // Attaching the layout to the toolbar object + Toolbar toolbar = findViewById(R.id.tool_bar_account); + // Setting toolbar as the ActionBar with setSupportActionBar() call + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle(displayNameAndHost); + getSupportActionBar().setHomeAsUpIndicator( + new IconicsDrawable(this, FontAwesome.Icon.faw_chevron_left).actionBar() + ); + + loadAccountVideos(displayNameAndHost); + } @Override @@ -100,76 +159,178 @@ public class AccountActivity extends CommonActivity { return false; } - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + private void loadAccount(String ownerString) { - setContentView(R.layout.activity_account); + // get video details from api + Call call = userService.getAccount(ownerString); - // Attaching the layout to the toolbar object - Toolbar toolbar = findViewById(R.id.tool_bar_user); - // Setting toolbar as the ActionBar with setSupportActionBar() call - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeAsUpIndicator( - new IconicsDrawable(this, FontAwesome.Icon.faw_chevron_left).actionBar() - ); - - - init(); - } - - private void init() { - // try to get user data - getUserData(); - } - - private boolean getUserData() { - - // TODO - - - String apiBaseURL = APIUrlHelper.getUrlWithVersion(this); - - GetUserService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class); - - Call call = service.getMe(); - - call.enqueue(new Callback() { + call.enqueue(new Callback() { @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful()) { + Account account = response.body(); - Me me = response.body(); + String owner = MetaDataHelper.getOwnerString(account.getName(), + account.getHost(), + AccountActivity.this + ); - TextView username = findViewById(R.id.account_username); - TextView email = findViewById(R.id.account_email); + // set view data + TextView ownerStringView = findViewById(R.id.account_owner_string); + ownerStringView.setText(owner); - username.setText(me.getUsername()); - email.setText(me.getEmail()); + TextView followers = findViewById(R.id.account_followers); + followers.setText(account.getFollowersCount().toString()); - Log.v(TAG, me.getEmail()); + TextView description = findViewById(R.id.account_description); + description.setText(account.getDescription()); + TextView joined = findViewById(R.id.account_joined); + joined.setText(account.getCreatedAt().toString()); + + + } else { + Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); } } @Override - public void onFailure(Call call, Throwable t) { - + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Log.wtf(TAG, t.fillInStackTrace()); + Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); } }); - return true; } - @Override - protected void onResume() { - super.onResume(); - init(); + private void loadAccountVideos(String displayNameAndHost) { + + isLoadingVideos = false; + + GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetVideoDataService.class); + Call call; + + call = service.getAccountVideosData(displayNameAndHost, videosStart, videosCount, videosSort); + + call.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + + Log.v(TAG, response.toString()); + + if (response.isSuccessful()) { + if (videosCurrentStart == 0) { + videoAdapter.clearData(); + } + + if (response.body() != null) { + videoAdapter.setData(response.body().getVideoArrayList()); + } + + } else{ + Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); + + } + + isLoadingVideos = false; + swipeRefreshLayoutVideos.setRefreshing(false); + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Log.wtf("err", t.fillInStackTrace()); + Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); + isLoadingVideos = false; + swipeRefreshLayoutVideos.setRefreshing(false); + } + }); + } + + private void loadAccountChannels(String displayNameAndHost) { + + // get video details from api + Call call = userService.getAccountChannels(displayNameAndHost); + + call.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + + + if (response.isSuccessful()) { + ChannelList channelList = response.body(); + + + + } else { + Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); + } + + + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Log.wtf(TAG, t.fillInStackTrace()); + Toast.makeText(AccountActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); + } + }); + } + + + + private void createBottomBarNavigation() { + + // Get Bottom Navigation + BottomNavigationView navigation = findViewById(R.id.account_navigation); + + // Always show text label + navigation.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED); + + // Add Icon font + Menu navMenu = navigation.getMenu(); + navMenu.findItem(R.id.account_navigation_about).setIcon( + new IconicsDrawable(this, FontAwesome.Icon.faw_user)); + navMenu.findItem(R.id.account_navigation_channels).setIcon( + new IconicsDrawable(this, FontAwesome.Icon.faw_list)); + navMenu.findItem(R.id.account_navigation_videos).setIcon( + new IconicsDrawable(this, FontAwesome.Icon.faw_video)); + + // Click Listener + navigation.setOnNavigationItemSelectedListener(menuItem -> { + switch (menuItem.getItemId()) { + case R.id.account_navigation_about: + + swipeRefreshLayoutVideos.setVisibility(View.GONE); + swipeRefreshLayoutChannels.setVisibility(View.GONE); + aboutView.setVisibility(View.VISIBLE); + loadAccount(displayNameAndHost); + + return true; + case R.id.account_navigation_channels: + + swipeRefreshLayoutVideos.setVisibility(View.GONE); + swipeRefreshLayoutChannels.setVisibility(View.VISIBLE); + aboutView.setVisibility(View.GONE); + loadAccountChannels(displayNameAndHost); + + return true; + case R.id.account_navigation_videos: + + swipeRefreshLayoutVideos.setVisibility(View.VISIBLE); + swipeRefreshLayoutChannels.setVisibility(View.GONE); + aboutView.setVisibility(View.GONE); + loadAccountVideos(displayNameAndHost); + + return true; + + } + return false; + }); } } diff --git a/app/src/main/java/net/schueller/peertube/activity/LoginActivity.java b/app/src/main/java/net/schueller/peertube/activity/LoginActivity.java index 56fa0e4..991931b 100644 --- a/app/src/main/java/net/schueller/peertube/activity/LoginActivity.java +++ b/app/src/main/java/net/schueller/peertube/activity/LoginActivity.java @@ -40,15 +40,11 @@ import net.schueller.peertube.network.AuthenticationService; import net.schueller.peertube.network.RetrofitInstance; import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -import static net.schueller.peertube.helper.Constants.DEFAULT_THEME; -import static net.schueller.peertube.helper.Constants.THEME_PREF_KEY; - public class LoginActivity extends CommonActivity { private String TAG = "LoginActivity"; @@ -103,6 +99,15 @@ public class LoginActivity extends CommonActivity { String email = mEmailView.getText().toString(); String password = mPasswordView.getText().toString(); + //check values + if (email.isEmpty()) { + Toast.makeText(LoginActivity.this, "Email/Username is empty", Toast.LENGTH_LONG).show(); + return; + } + if (password.isEmpty()) { + Toast.makeText(LoginActivity.this, "Password is empty", Toast.LENGTH_LONG).show(); + return; + } // make http call to login and save access tokens String apiBaseURL = APIUrlHelper.getUrlWithVersion(this); @@ -148,7 +153,7 @@ public class LoginActivity extends CommonActivity { Log.wtf(TAG, "Logged in"); - Intent intent = new Intent(context, AccountActivity.class); + Intent intent = new Intent(context, MeActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); context.startActivity(intent); diff --git a/app/src/main/java/net/schueller/peertube/activity/MeActivity.java b/app/src/main/java/net/schueller/peertube/activity/MeActivity.java new file mode 100644 index 0000000..4153d74 --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/activity/MeActivity.java @@ -0,0 +1,162 @@ +/* + * Copyright 2018 Stefan Schüller + * + * License: GPL-3.0+ + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.schueller.peertube.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.widget.TextView; + +import com.mikepenz.fontawesome_typeface_library.FontAwesome; +import com.mikepenz.iconics.IconicsDrawable; + +import net.schueller.peertube.R; +import net.schueller.peertube.helper.APIUrlHelper; +import net.schueller.peertube.model.Me; +import net.schueller.peertube.network.GetUserService; +import net.schueller.peertube.network.RetrofitInstance; +import net.schueller.peertube.network.Session; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.Toolbar; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class MeActivity extends CommonActivity { + + + private static final String TAG = "MeActivity"; + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu_top_account, menu); + + // Set an icon in the ActionBar + menu.findItem(R.id.action_logout).setIcon( + new IconicsDrawable(this, FontAwesome.Icon.faw_sign_out_alt).actionBar()); + + return true; + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + switch (item.getItemId()) { + // action with ID action_refresh was selected + + case R.id.action_logout: + Session.getInstance().invalidate(); + Intent intent = new Intent(this, LoginActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + this.startActivity(intent); + finish(); + return true; + default: + break; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public boolean onSupportNavigateUp() { + finish(); // close this activity as oppose to navigating up + + return false; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_me); + + // Attaching the layout to the toolbar object + Toolbar toolbar = findViewById(R.id.tool_bar_me); + // Setting toolbar as the ActionBar with setSupportActionBar() call + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeAsUpIndicator( + new IconicsDrawable(this, FontAwesome.Icon.faw_chevron_left).actionBar() + ); + + + init(); + } + + private void init() { + // try to get user data + getUserData(); + } + + private boolean getUserData() { + + // TODO + + + String apiBaseURL = APIUrlHelper.getUrlWithVersion(this); + + GetUserService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetUserService.class); + + Call call = service.getMe(); + + call.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + + if (response.isSuccessful()) { + + Me me = response.body(); + + TextView username = findViewById(R.id.account_username); + TextView email = findViewById(R.id.account_email); + + username.setText(me.getUsername()); + email.setText(me.getEmail()); + + Log.v(TAG, me.getEmail()); + + } + + + } + + @Override + public void onFailure(Call call, Throwable t) { + + } + }); + + return true; + } + + @Override + protected void onResume() { + super.onResume(); + + init(); + + } +} diff --git a/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java b/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java index 95a0f73..f69700a 100644 --- a/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java +++ b/app/src/main/java/net/schueller/peertube/activity/VideoListActivity.java @@ -70,7 +70,8 @@ public class VideoListActivity extends CommonActivity { private String TAG = "VideoListActivity"; - public static final String EXTRA_VIDEOID = "VIDEOID "; + public static final String EXTRA_VIDEOID = "VIDEOID"; + public static final String EXTRA_ACCOUNTDISPLAYNAME = "ACCOUNTDISPLAYNAMEANDHOST"; private VideoAdapter videoAdapter; private SwipeRefreshLayout swipeRefreshLayout; @@ -288,7 +289,7 @@ public class VideoListActivity extends CommonActivity { @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { Log.wtf("err", t.fillInStackTrace()); - Toast.makeText(VideoListActivity.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show(); + Toast.makeText(VideoListActivity.this, getString(R.string.api_error), Toast.LENGTH_SHORT).show(); isLoading = false; swipeRefreshLayout.setRefreshing(false); } @@ -427,7 +428,7 @@ public class VideoListActivity extends CommonActivity { Intent intent = new Intent(this, LoginActivity.class); this.startActivity(intent); } else { - Intent intent = new Intent(this, AccountActivity.class); + Intent intent = new Intent(this, MeActivity.class); this.startActivity(intent); } diff --git a/app/src/main/java/net/schueller/peertube/adapter/ChannelAdapter.java b/app/src/main/java/net/schueller/peertube/adapter/ChannelAdapter.java new file mode 100644 index 0000000..082256b --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/adapter/ChannelAdapter.java @@ -0,0 +1,175 @@ +/* + * Copyright 2018 Stefan Schüller + * + * License: GPL-3.0+ + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.schueller.peertube.adapter; + +import android.content.Context; +import android.content.Intent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mikepenz.iconics.Iconics; +import com.squareup.picasso.Picasso; + +import net.schueller.peertube.R; +import net.schueller.peertube.activity.VideoPlayActivity; +import net.schueller.peertube.helper.APIUrlHelper; +import net.schueller.peertube.helper.MetaDataHelper; +import net.schueller.peertube.intents.Intents; +import net.schueller.peertube.model.Avatar; +import net.schueller.peertube.model.Video; + +import java.util.ArrayList; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.PopupMenu; +import androidx.recyclerview.widget.RecyclerView; + +import static net.schueller.peertube.activity.VideoListActivity.EXTRA_VIDEOID; + +public class ChannelAdapter extends RecyclerView.Adapter { + + + private ArrayList