From 34c61df3620b838fdd7703afbe1b64d43fd228c0 Mon Sep 17 00:00:00 2001 From: Erik Cavazos Date: Sat, 11 Feb 2023 23:41:23 -0600 Subject: [PATCH] building business logic --- app/build.gradle | 10 ++- app/src/main/AndroidManifest.xml | 2 + .../main/java/com/isolaatti/MainActivity.kt | 4 +- app/src/main/java/com/isolaatti/MainModule.kt | 22 ++--- .../main/java/com/isolaatti/MyApplication.kt | 2 + .../main/java/com/isolaatti/auth/Module.kt | 24 ++++++ .../java/com/isolaatti/comments/Module.kt | 4 + .../comments/data/remote/CommentDto.kt | 8 ++ .../comments/data/remote/CommentToPostDto.kt | 6 ++ .../comments/data/remote/CommentsApi.kt | 10 +++ .../data/repository/CommentsRepositoryImpl.kt | 8 ++ .../comments/domain/CommentRepository.kt | 5 ++ .../comments/domain/model/Comment.kt | 12 +++ .../connectivity/AuthenticationInterceptor.kt | 26 ++++++ .../isolaatti/connectivity/RetrofitClient.kt | 43 ++-------- .../java/com/isolaatti/followers/Module.kt | 4 + .../followers/data/remote/FollowersApi.kt | 23 +++++ .../java/com/isolaatti/home/HomeActivity.kt | 7 ++ .../main/java/com/isolaatti/home/Module.kt | 27 ++++++ .../home/feed/data/remote/FeedApi.kt | 10 +++ .../home/feed/data/remote/FeedDto.kt | 6 ++ .../home/feed/data/remote/PostDto.kt | 12 +++ .../data/repository/FeedRepositoryImpl.kt | 20 +++++ .../isolaatti/home/feed/domain/model/Post.kt | 13 +++ .../feed/domain/repository/FeedRepository.kt | 8 ++ .../home/feed/presentation/FeedViewModel.kt | 26 +++++- .../isolaatti/home/feed/ui/FeedFragment.kt | 61 ++++++++++++-- .../home/feed/ui/FeedRecyclerViewAdapter.kt | 62 ++++++++++++++ .../com/isolaatti/login/LogInViewModel.kt | 2 +- .../main/java/com/isolaatti/posts/Module.kt | 4 + .../isolaatti/posts/data/remote/PostsApi.kt | 23 +++++ .../main/java/com/isolaatti/profile/Module.kt | 23 +++++ .../profile/data/remote/ProfileApi.kt | 14 ++++ .../profile/data/remote/ProfileListItemDto.kt | 7 ++ .../profile/data/remote/UserProfileDto.kt | 17 ++++ .../data/repository/ProfileRepositoryImpl.kt | 14 ++++ .../profile/domain/ProfileRepository.kt | 9 ++ .../profile/presentation/ProfileViewModel.kt | 9 ++ .../isolaatti/profile/ui/AudiosFragment.kt | 21 +++++ .../profile/ui/DiscussionsFragment.kt | 22 +++++ .../isolaatti/profile/ui/ImagesFragment.kt | 22 +++++ .../isolaatti/profile/ui/ProfileActivity.kt | 70 ++++++++++++++++ .../settings/ui/ChangePasswordFragment.kt | 21 +++++ .../settings/ui/FeedSettingsFragment.kt | 22 +++++ .../isolaatti/settings/ui/SessionsFragment.kt | 22 +++++ .../isolaatti/settings/ui/SettingsActivity.kt | 17 ++++ .../isolaatti/settings/ui/SettingsFragment.kt | 22 +++++ .../utils/IntIdentificationWrapper.kt | 3 + .../isolaatti/utils/PicassoImagesPluginDef.kt | 19 +++++ .../main/java/com/isolaatti/utils/UrlGen.kt | 7 ++ .../res/drawable/baseline_arrow_back_24.xml | 5 ++ app/src/main/res/drawable/comments_solid.xml | 9 ++ .../res/drawable/hands_clapping_solid.xml | 9 ++ app/src/main/res/layout/activity_profile.xml | 84 +++++++++++++++++++ app/src/main/res/layout/activity_settings.xml | 18 ++++ app/src/main/res/layout/fragment_audios.xml | 17 ++++ .../main/res/layout/fragment_discussions.xml | 17 ++++ app/src/main/res/layout/fragment_feed.xml | 46 +++++++++- app/src/main/res/layout/fragment_images.xml | 17 ++++ app/src/main/res/layout/fragment_settings.xml | 30 +++++++ .../fragment_settings_change_password.xml | 16 ++++ .../fragment_settings_feed_settings.xml | 16 ++++ .../res/layout/fragment_settings_sessions.xml | 17 ++++ app/src/main/res/layout/post_layout.xml | 75 +++++++++++++++++ app/src/main/res/menu/home_drawer_menu.xml | 3 + app/src/main/res/menu/profile_menu.xml | 5 ++ .../res/navigation/profile_navigation.xml | 19 +++++ .../res/navigation/settings_navigation.xml | 33 ++++++++ app/src/main/res/values/strings.xml | 4 + app/src/main/res/values/themes.xml | 5 ++ build.gradle | 4 +- gradle.properties | 3 +- 72 files changed, 1245 insertions(+), 62 deletions(-) create mode 100644 app/src/main/java/com/isolaatti/auth/Module.kt create mode 100644 app/src/main/java/com/isolaatti/comments/Module.kt create mode 100644 app/src/main/java/com/isolaatti/comments/data/remote/CommentDto.kt create mode 100644 app/src/main/java/com/isolaatti/comments/data/remote/CommentToPostDto.kt create mode 100644 app/src/main/java/com/isolaatti/comments/data/remote/CommentsApi.kt create mode 100644 app/src/main/java/com/isolaatti/comments/data/repository/CommentsRepositoryImpl.kt create mode 100644 app/src/main/java/com/isolaatti/comments/domain/CommentRepository.kt create mode 100644 app/src/main/java/com/isolaatti/comments/domain/model/Comment.kt create mode 100644 app/src/main/java/com/isolaatti/connectivity/AuthenticationInterceptor.kt create mode 100644 app/src/main/java/com/isolaatti/followers/Module.kt create mode 100644 app/src/main/java/com/isolaatti/followers/data/remote/FollowersApi.kt create mode 100644 app/src/main/java/com/isolaatti/home/Module.kt create mode 100644 app/src/main/java/com/isolaatti/home/feed/data/remote/FeedApi.kt create mode 100644 app/src/main/java/com/isolaatti/home/feed/data/remote/FeedDto.kt create mode 100644 app/src/main/java/com/isolaatti/home/feed/data/remote/PostDto.kt create mode 100644 app/src/main/java/com/isolaatti/home/feed/data/repository/FeedRepositoryImpl.kt create mode 100644 app/src/main/java/com/isolaatti/home/feed/domain/model/Post.kt create mode 100644 app/src/main/java/com/isolaatti/home/feed/domain/repository/FeedRepository.kt create mode 100644 app/src/main/java/com/isolaatti/home/feed/ui/FeedRecyclerViewAdapter.kt create mode 100644 app/src/main/java/com/isolaatti/posts/Module.kt create mode 100644 app/src/main/java/com/isolaatti/posts/data/remote/PostsApi.kt create mode 100644 app/src/main/java/com/isolaatti/profile/Module.kt create mode 100644 app/src/main/java/com/isolaatti/profile/data/remote/ProfileApi.kt create mode 100644 app/src/main/java/com/isolaatti/profile/data/remote/ProfileListItemDto.kt create mode 100644 app/src/main/java/com/isolaatti/profile/data/remote/UserProfileDto.kt create mode 100644 app/src/main/java/com/isolaatti/profile/data/repository/ProfileRepositoryImpl.kt create mode 100644 app/src/main/java/com/isolaatti/profile/domain/ProfileRepository.kt create mode 100644 app/src/main/java/com/isolaatti/profile/presentation/ProfileViewModel.kt create mode 100644 app/src/main/java/com/isolaatti/profile/ui/AudiosFragment.kt create mode 100644 app/src/main/java/com/isolaatti/profile/ui/DiscussionsFragment.kt create mode 100644 app/src/main/java/com/isolaatti/profile/ui/ImagesFragment.kt create mode 100644 app/src/main/java/com/isolaatti/profile/ui/ProfileActivity.kt create mode 100644 app/src/main/java/com/isolaatti/settings/ui/ChangePasswordFragment.kt create mode 100644 app/src/main/java/com/isolaatti/settings/ui/FeedSettingsFragment.kt create mode 100644 app/src/main/java/com/isolaatti/settings/ui/SessionsFragment.kt create mode 100644 app/src/main/java/com/isolaatti/settings/ui/SettingsActivity.kt create mode 100644 app/src/main/java/com/isolaatti/settings/ui/SettingsFragment.kt create mode 100644 app/src/main/java/com/isolaatti/utils/IntIdentificationWrapper.kt create mode 100644 app/src/main/java/com/isolaatti/utils/PicassoImagesPluginDef.kt create mode 100644 app/src/main/java/com/isolaatti/utils/UrlGen.kt create mode 100644 app/src/main/res/drawable/baseline_arrow_back_24.xml create mode 100644 app/src/main/res/drawable/comments_solid.xml create mode 100644 app/src/main/res/drawable/hands_clapping_solid.xml create mode 100644 app/src/main/res/layout/activity_profile.xml create mode 100644 app/src/main/res/layout/activity_settings.xml create mode 100644 app/src/main/res/layout/fragment_audios.xml create mode 100644 app/src/main/res/layout/fragment_discussions.xml create mode 100644 app/src/main/res/layout/fragment_images.xml create mode 100644 app/src/main/res/layout/fragment_settings.xml create mode 100644 app/src/main/res/layout/fragment_settings_change_password.xml create mode 100644 app/src/main/res/layout/fragment_settings_feed_settings.xml create mode 100644 app/src/main/res/layout/fragment_settings_sessions.xml create mode 100644 app/src/main/res/layout/post_layout.xml create mode 100644 app/src/main/res/menu/profile_menu.xml create mode 100644 app/src/main/res/navigation/profile_navigation.xml create mode 100644 app/src/main/res/navigation/settings_navigation.xml diff --git a/app/build.gradle b/app/build.gradle index e27dfc8..0af2361 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -63,7 +63,7 @@ dependencies { // Material 3 - implementation "com.google.android.material:material:1.9.0-alpha01" + implementation "com.google.android.material:material:1.8.0" // Navigation def nav_version = "2.5.3" @@ -77,6 +77,14 @@ dependencies { // Data security implementation "androidx.security:security-crypto:1.0.0" + + // Markwon + final def markwon_version = '4.6.2' + + implementation "io.noties.markwon:core:$markwon_version" + implementation "io.noties.markwon:editor:$markwon_version" + implementation "io.noties.markwon:image-picasso:$markwon_version" + implementation "io.noties.markwon:linkify:$markwon_version" } kapt { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d55a12b..9e40c5f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,6 +24,8 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/MainActivity.kt b/app/src/main/java/com/isolaatti/MainActivity.kt index e753492..b7b9c99 100644 --- a/app/src/main/java/com/isolaatti/MainActivity.kt +++ b/app/src/main/java/com/isolaatti/MainActivity.kt @@ -25,7 +25,9 @@ class MainActivity : ComponentActivity() { val currentToken = authRepository.getCurrentToken() if(currentToken == null) { - startActivity(Intent(this@MainActivity, LogInActivity::class.java)) + startActivity(Intent(this@MainActivity, LogInActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NO_HISTORY + }) } else { startActivity(Intent(this@MainActivity, HomeActivity::class.java)) } diff --git a/app/src/main/java/com/isolaatti/MainModule.kt b/app/src/main/java/com/isolaatti/MainModule.kt index 588753b..3dbf0e8 100644 --- a/app/src/main/java/com/isolaatti/MainModule.kt +++ b/app/src/main/java/com/isolaatti/MainModule.kt @@ -1,27 +1,29 @@ package com.isolaatti -import com.isolaatti.auth.data.AuthRepositoryImpl -import com.isolaatti.auth.data.local.TokenStorage -import com.isolaatti.auth.data.remote.AuthApi import com.isolaatti.auth.domain.AuthRepository +import com.isolaatti.connectivity.AuthenticationInterceptor import com.isolaatti.connectivity.RetrofitClient +import com.squareup.picasso.Picasso +import com.squareup.picasso.RequestCreator import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent import dagger.hilt.components.SingletonComponent +import io.noties.markwon.image.AsyncDrawable +import io.noties.markwon.image.picasso.PicassoImagesPlugin @Module @InstallIn(SingletonComponent::class) class MainModule { @Provides - fun provideAuthApi():AuthApi { - return RetrofitClient.client.create(AuthApi::class.java) + fun provideAuthenticationInterceptor(authRepository: dagger.Lazy): AuthenticationInterceptor { + return AuthenticationInterceptor(authRepository) + } + @Provides + fun provideRetrofitClient(authenticationInterceptor: AuthenticationInterceptor) : RetrofitClient { + return RetrofitClient(authenticationInterceptor) } - @Provides - fun provideAuthRepository(tokenStorage: TokenStorage, authApi: AuthApi): AuthRepository { - return AuthRepositoryImpl(tokenStorage, authApi) - } + } \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/MyApplication.kt b/app/src/main/java/com/isolaatti/MyApplication.kt index 469563a..e9a0bcf 100644 --- a/app/src/main/java/com/isolaatti/MyApplication.kt +++ b/app/src/main/java/com/isolaatti/MyApplication.kt @@ -5,12 +5,14 @@ import com.isolaatti.auth.data.AuthRepositoryImpl import com.isolaatti.auth.data.local.TokenStorage import com.isolaatti.auth.data.remote.AuthApi import com.isolaatti.auth.domain.AuthRepository +import com.isolaatti.connectivity.RetrofitClient import dagger.Provides import dagger.hilt.android.HiltAndroidApp import javax.inject.Singleton @HiltAndroidApp class MyApplication : Application() { + override fun onCreate() { super.onCreate() } diff --git a/app/src/main/java/com/isolaatti/auth/Module.kt b/app/src/main/java/com/isolaatti/auth/Module.kt new file mode 100644 index 0000000..d326293 --- /dev/null +++ b/app/src/main/java/com/isolaatti/auth/Module.kt @@ -0,0 +1,24 @@ +package com.isolaatti.auth + +import com.isolaatti.auth.data.AuthRepositoryImpl +import com.isolaatti.auth.data.local.TokenStorage +import com.isolaatti.auth.data.remote.AuthApi +import com.isolaatti.auth.domain.AuthRepository +import com.isolaatti.connectivity.RetrofitClient +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +class Module { + @Provides + fun provideAuthApi(retrofitClient: RetrofitClient): AuthApi { + return retrofitClient.client.create(AuthApi::class.java) + } + @Provides + fun provideAuthRepository(tokenStorage: TokenStorage, authApi: AuthApi): AuthRepository { + return AuthRepositoryImpl(tokenStorage, authApi) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/comments/Module.kt b/app/src/main/java/com/isolaatti/comments/Module.kt new file mode 100644 index 0000000..4c517ea --- /dev/null +++ b/app/src/main/java/com/isolaatti/comments/Module.kt @@ -0,0 +1,4 @@ +package com.isolaatti.comments + +class Module { +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/comments/data/remote/CommentDto.kt b/app/src/main/java/com/isolaatti/comments/data/remote/CommentDto.kt new file mode 100644 index 0000000..f8be4ef --- /dev/null +++ b/app/src/main/java/com/isolaatti/comments/data/remote/CommentDto.kt @@ -0,0 +1,8 @@ +package com.isolaatti.comments.data.remote + +import com.isolaatti.comments.domain.model.Comment + +data class CommentDto( + val comment: Comment, + val username: String +) diff --git a/app/src/main/java/com/isolaatti/comments/data/remote/CommentToPostDto.kt b/app/src/main/java/com/isolaatti/comments/data/remote/CommentToPostDto.kt new file mode 100644 index 0000000..67512ea --- /dev/null +++ b/app/src/main/java/com/isolaatti/comments/data/remote/CommentToPostDto.kt @@ -0,0 +1,6 @@ +package com.isolaatti.comments.data.remote + +data class CommentToPostDto( + val content: String, + val audioId: String? +) diff --git a/app/src/main/java/com/isolaatti/comments/data/remote/CommentsApi.kt b/app/src/main/java/com/isolaatti/comments/data/remote/CommentsApi.kt new file mode 100644 index 0000000..db7a6d8 --- /dev/null +++ b/app/src/main/java/com/isolaatti/comments/data/remote/CommentsApi.kt @@ -0,0 +1,10 @@ +package com.isolaatti.comments.data.remote + +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.POST + +interface CommentsApi { + @POST("Posting/Post/{postId}/Comment") + fun postComment(@Body commentToPost: CommentToPostDto): Call +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/comments/data/repository/CommentsRepositoryImpl.kt b/app/src/main/java/com/isolaatti/comments/data/repository/CommentsRepositoryImpl.kt new file mode 100644 index 0000000..20fc4a2 --- /dev/null +++ b/app/src/main/java/com/isolaatti/comments/data/repository/CommentsRepositoryImpl.kt @@ -0,0 +1,8 @@ +package com.isolaatti.comments.data.repository + +import com.isolaatti.comments.data.remote.CommentsApi +import com.isolaatti.comments.domain.CommentRepository +import javax.inject.Inject + +class CommentsRepositoryImpl @Inject constructor(commentsApi: CommentsApi) : CommentRepository { +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/comments/domain/CommentRepository.kt b/app/src/main/java/com/isolaatti/comments/domain/CommentRepository.kt new file mode 100644 index 0000000..d4cf464 --- /dev/null +++ b/app/src/main/java/com/isolaatti/comments/domain/CommentRepository.kt @@ -0,0 +1,5 @@ +package com.isolaatti.comments.domain + +interface CommentRepository { + +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/comments/domain/model/Comment.kt b/app/src/main/java/com/isolaatti/comments/domain/model/Comment.kt new file mode 100644 index 0000000..d33fd1c --- /dev/null +++ b/app/src/main/java/com/isolaatti/comments/domain/model/Comment.kt @@ -0,0 +1,12 @@ +package com.isolaatti.comments.domain.model + +data class Comment( + val id: Long, + val textContent: String, + val userId: Int, + val postId: Long, + val date: String, + val responseForCommentId: Long?, + val linkedDiscussionId: Long?, + val linkedCommentId: Long? +) diff --git a/app/src/main/java/com/isolaatti/connectivity/AuthenticationInterceptor.kt b/app/src/main/java/com/isolaatti/connectivity/AuthenticationInterceptor.kt new file mode 100644 index 0000000..e488b1d --- /dev/null +++ b/app/src/main/java/com/isolaatti/connectivity/AuthenticationInterceptor.kt @@ -0,0 +1,26 @@ +package com.isolaatti.connectivity + +import com.isolaatti.auth.domain.AuthRepository +import okhttp3.Interceptor +import okhttp3.Response + +class AuthenticationInterceptor(private val authRepository: dagger.Lazy) : Interceptor { + + override fun intercept(chain: Interceptor.Chain): Response { + val url = chain.request().url() + val path = url.url().path + if(RetrofitClient.excludedUrlsFromAuthentication.contains(path)){ + return chain.proceed(chain.request()) + } + + // Add auth header here + val tokenDto = authRepository.get().getCurrentToken() + tokenDto?.token?.let { + val request = chain.request().newBuilder().addHeader("sessionToken", it) .build() + return chain.proceed(request) + } + + return chain.proceed(chain.request()) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/connectivity/RetrofitClient.kt b/app/src/main/java/com/isolaatti/connectivity/RetrofitClient.kt index ff23864..cf6016e 100644 --- a/app/src/main/java/com/isolaatti/connectivity/RetrofitClient.kt +++ b/app/src/main/java/com/isolaatti/connectivity/RetrofitClient.kt @@ -1,53 +1,28 @@ package com.isolaatti.connectivity -import android.util.Log -import com.isolaatti.auth.domain.AuthRepository -import okhttp3.Interceptor import okhttp3.OkHttpClient -import okhttp3.Response import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import javax.inject.Inject -import javax.inject.Provider -object RetrofitClient { - // These urls don't need auth header - private val excludedUrlsFromAuthentication = listOf( - "/api/LogIn" - ) - - class AuthenticationInterceptor : Interceptor { - - @Inject lateinit var authRepository: Provider - - override fun intercept(chain: Interceptor.Chain): Response { - val url = chain.request().url() - val path = url.url().path - if(excludedUrlsFromAuthentication.contains(path)){ - return chain.proceed(chain.request()) - } - - // Add auth header here - val tokenDto = authRepository.get().getCurrentToken() - tokenDto?.token?.let { - val request = chain.request().newBuilder().addHeader("sessionToken", it) .build() - return chain.proceed(request) - } - - return chain.proceed(chain.request()) - } +class RetrofitClient @Inject constructor(private val authenticationInterceptor: AuthenticationInterceptor) { + companion object { + // These urls don't need auth header + val excludedUrlsFromAuthentication = listOf( + "/api/LogIn" + ) + const val BASE_URL = "https://isolaatti.com/api/" } - private val okHttpClient get() = OkHttpClient.Builder() - .addInterceptor(AuthenticationInterceptor()) + .addInterceptor(authenticationInterceptor) .build() val client: Retrofit get() = Retrofit.Builder() - .baseUrl("https://isolaatti.com/api/") + .baseUrl(BASE_URL) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() diff --git a/app/src/main/java/com/isolaatti/followers/Module.kt b/app/src/main/java/com/isolaatti/followers/Module.kt new file mode 100644 index 0000000..d36fd9b --- /dev/null +++ b/app/src/main/java/com/isolaatti/followers/Module.kt @@ -0,0 +1,4 @@ +package com.isolaatti.followers + +class Module { +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/followers/data/remote/FollowersApi.kt b/app/src/main/java/com/isolaatti/followers/data/remote/FollowersApi.kt new file mode 100644 index 0000000..91f81fe --- /dev/null +++ b/app/src/main/java/com/isolaatti/followers/data/remote/FollowersApi.kt @@ -0,0 +1,23 @@ +package com.isolaatti.followers.data.remote + +import com.isolaatti.profile.data.remote.ProfileListItemDto +import com.isolaatti.utils.IntIdentificationWrapper +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Path + +interface FollowersApi { + @GET("Following/FollowersOf/{userId}") + fun getFollowersOfUser(@Path("userId") userId: Int): Call> + + @GET("Following/FollowingsOf/{userId}") + fun getFollowingsOfUser(@Path("userId") userId: Int): Call> + + @POST("Following/Follow") + fun followUser(@Body id: IntIdentificationWrapper): Call + + @POST("Following/Unfollow") + fun unfollowUser(@Body id: IntIdentificationWrapper): Call +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/HomeActivity.kt b/app/src/main/java/com/isolaatti/home/HomeActivity.kt index def8a28..1fe5c43 100644 --- a/app/src/main/java/com/isolaatti/home/HomeActivity.kt +++ b/app/src/main/java/com/isolaatti/home/HomeActivity.kt @@ -2,19 +2,24 @@ package com.isolaatti.home import android.os.Bundle import android.view.Menu +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.content.res.AppCompatResources import androidx.core.app.ActivityCompat +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.setupWithNavController import com.google.android.material.search.SearchBar import com.isolaatti.R import com.isolaatti.databinding.ActivityHomeBinding +import com.isolaatti.home.feed.presentation.FeedViewModel import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class HomeActivity : AppCompatActivity() { lateinit var viewBinding: ActivityHomeBinding + val feedViewModel: FeedViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -22,6 +27,8 @@ class HomeActivity : AppCompatActivity() { setContentView(viewBinding.root) val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment viewBinding.bottomNavigation.setupWithNavController(navHostFragment.navController) + + feedViewModel.getFeed() } override fun onCreateOptionsMenu(menu: Menu?): Boolean { diff --git a/app/src/main/java/com/isolaatti/home/Module.kt b/app/src/main/java/com/isolaatti/home/Module.kt new file mode 100644 index 0000000..13eaf9b --- /dev/null +++ b/app/src/main/java/com/isolaatti/home/Module.kt @@ -0,0 +1,27 @@ +package com.isolaatti.home + +import com.isolaatti.connectivity.RetrofitClient +import com.isolaatti.home.feed.data.remote.FeedApi +import com.isolaatti.home.feed.data.repository.FeedRepositoryImpl +import com.isolaatti.home.feed.domain.repository.FeedRepository +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ActivityComponent +import dagger.hilt.android.scopes.ActivityScoped +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class Module { + @Provides + fun provideFeedApi(retrofitClient: RetrofitClient): FeedApi { + return retrofitClient.client.create(FeedApi::class.java) + } + + @Provides + fun provideFeedRepository(feedApi: FeedApi): FeedRepository { + return FeedRepositoryImpl(feedApi) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/feed/data/remote/FeedApi.kt b/app/src/main/java/com/isolaatti/home/feed/data/remote/FeedApi.kt new file mode 100644 index 0000000..4ae8a30 --- /dev/null +++ b/app/src/main/java/com/isolaatti/home/feed/data/remote/FeedApi.kt @@ -0,0 +1,10 @@ +package com.isolaatti.home.feed.data.remote + +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Query + +interface FeedApi { + @GET("Feed") + fun fetchFeed(@Query("lastId") lastId: Long, @Query("length") length: Int): Call +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/feed/data/remote/FeedDto.kt b/app/src/main/java/com/isolaatti/home/feed/data/remote/FeedDto.kt new file mode 100644 index 0000000..9e6d795 --- /dev/null +++ b/app/src/main/java/com/isolaatti/home/feed/data/remote/FeedDto.kt @@ -0,0 +1,6 @@ +package com.isolaatti.home.feed.data.remote + +data class FeedDto( + val data: List, + val moreContent: Boolean +) \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/feed/data/remote/PostDto.kt b/app/src/main/java/com/isolaatti/home/feed/data/remote/PostDto.kt new file mode 100644 index 0000000..7f055fd --- /dev/null +++ b/app/src/main/java/com/isolaatti/home/feed/data/remote/PostDto.kt @@ -0,0 +1,12 @@ +package com.isolaatti.home.feed.data.remote + +import com.isolaatti.home.feed.domain.model.Post + +data class PostDto( + val post: Post, + val numberOfLikes: Int, + val numberOfComments: Int, + val userName: String, + val squadName: String?, + val liked: Boolean +) \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/feed/data/repository/FeedRepositoryImpl.kt b/app/src/main/java/com/isolaatti/home/feed/data/repository/FeedRepositoryImpl.kt new file mode 100644 index 0000000..dd9fb5e --- /dev/null +++ b/app/src/main/java/com/isolaatti/home/feed/data/repository/FeedRepositoryImpl.kt @@ -0,0 +1,20 @@ +package com.isolaatti.home.feed.data.repository + +import com.isolaatti.home.feed.data.remote.FeedApi +import com.isolaatti.home.feed.data.remote.FeedDto +import com.isolaatti.home.feed.domain.repository.FeedRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import retrofit2.awaitResponse +import javax.inject.Inject + +class FeedRepositoryImpl @Inject constructor(private val feedApi: FeedApi): FeedRepository { + override fun getNextPage(lastId: Long, count: Int): Flow = flow { + val response = feedApi.fetchFeed(lastId, count).awaitResponse().body() + if(response != null){ + emit(response) + } else { + emit(null) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/feed/domain/model/Post.kt b/app/src/main/java/com/isolaatti/home/feed/domain/model/Post.kt new file mode 100644 index 0000000..89b51f1 --- /dev/null +++ b/app/src/main/java/com/isolaatti/home/feed/domain/model/Post.kt @@ -0,0 +1,13 @@ +package com.isolaatti.home.feed.domain.model + +data class Post( + val id: Long, + val textContent: String, + val userId: Int, + val privacy: Int, + val date: String, + val audioId: String, + val squadId: String, + val linkedDiscussionId: Long, + val linkedCommentId: Long +) \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/feed/domain/repository/FeedRepository.kt b/app/src/main/java/com/isolaatti/home/feed/domain/repository/FeedRepository.kt new file mode 100644 index 0000000..df9c9ba --- /dev/null +++ b/app/src/main/java/com/isolaatti/home/feed/domain/repository/FeedRepository.kt @@ -0,0 +1,8 @@ +package com.isolaatti.home.feed.domain.repository + +import com.isolaatti.home.feed.data.remote.FeedDto +import kotlinx.coroutines.flow.Flow + +interface FeedRepository { + fun getNextPage(lastId: Long, count: Int): Flow +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/feed/presentation/FeedViewModel.kt b/app/src/main/java/com/isolaatti/home/feed/presentation/FeedViewModel.kt index b3f0164..1e235f2 100644 --- a/app/src/main/java/com/isolaatti/home/feed/presentation/FeedViewModel.kt +++ b/app/src/main/java/com/isolaatti/home/feed/presentation/FeedViewModel.kt @@ -1,7 +1,29 @@ package com.isolaatti.home.feed.presentation +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.isolaatti.home.feed.data.remote.FeedDto +import com.isolaatti.home.feed.domain.repository.FeedRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch +import javax.inject.Inject -class FeedViewModel : ViewModel() { - // TODO: Implement the ViewModel +@HiltViewModel +class FeedViewModel @Inject constructor(private val feedRepository: FeedRepository) : ViewModel() { + + private val _feed: MutableLiveData = MutableLiveData() + val feed: LiveData get() = _feed + + private fun getLastId(): Long = try {_feed.value?.data?.last()?.post?.id ?: 0} catch (e: NoSuchElementException) { 0 } + + fun getFeed() { + viewModelScope.launch { + feedRepository.getNextPage(0, 20).collect { + _feed.postValue(it) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/feed/ui/FeedFragment.kt b/app/src/main/java/com/isolaatti/home/feed/ui/FeedFragment.kt index 30b91f9..8e3b741 100644 --- a/app/src/main/java/com/isolaatti/home/feed/ui/FeedFragment.kt +++ b/app/src/main/java/com/isolaatti/home/feed/ui/FeedFragment.kt @@ -1,23 +1,37 @@ package com.isolaatti.home.feed.ui +import android.content.Intent import androidx.lifecycle.ViewModelProvider import android.os.Bundle import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.fragment.app.activityViewModels +import androidx.recyclerview.widget.LinearLayoutManager import com.isolaatti.R import com.isolaatti.databinding.FragmentFeedBinding import com.isolaatti.home.feed.presentation.FeedViewModel +import com.isolaatti.profile.ui.ProfileActivity +import com.isolaatti.settings.ui.SettingsActivity +import com.isolaatti.utils.PicassoImagesPluginDef +import dagger.hilt.android.AndroidEntryPoint +import io.noties.markwon.AbstractMarkwonPlugin +import io.noties.markwon.Markwon +import io.noties.markwon.MarkwonConfiguration +import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute +import io.noties.markwon.linkify.LinkifyPlugin +@AndroidEntryPoint class FeedFragment : Fragment() { companion object { fun newInstance() = FeedFragment() } - private lateinit var viewModel: FeedViewModel + private val viewModel: FeedViewModel by activityViewModels() private lateinit var viewBinding: FragmentFeedBinding + private lateinit var adapter: FeedRecyclerViewAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -25,15 +39,46 @@ class FeedFragment : Fragment() { ): View? { viewBinding = FragmentFeedBinding.inflate(inflater) - viewBinding.searchBar.setNavigationOnClickListener { - viewBinding.drawerLayout.openDrawer(viewBinding.homeDrawer) - } return viewBinding.root } - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - viewModel = ViewModelProvider(this).get(FeedViewModel::class.java) - // TODO: Use the ViewModel + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + viewBinding.topAppBar.setNavigationOnClickListener { + viewBinding.drawerLayout.openDrawer(viewBinding.homeDrawer) + } + + viewBinding.homeDrawer.setNavigationItemSelectedListener { + when(it.itemId) { + R.id.my_profile_menu_item -> { + startActivity(Intent(requireActivity(), ProfileActivity::class.java)) + true + } + R.id.settings_menu_item -> { + startActivity(Intent(requireActivity(), SettingsActivity::class.java)) + true + } + else -> {true} + } + } + + val markwon = Markwon.builder(requireContext()) + .usePlugin(object: AbstractMarkwonPlugin() { + override fun configureConfiguration(builder: MarkwonConfiguration.Builder) { + builder + .imageDestinationProcessor(ImageDestinationProcessorRelativeToAbsolute + .create("https://isolaatti.com/")) + } + }) + .usePlugin(PicassoImagesPluginDef.picassoImagePlugin) + .usePlugin(LinkifyPlugin.create()) + .build() + adapter = FeedRecyclerViewAdapter(markwon) + viewBinding.feedRecyclerView.adapter = adapter + viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext()) + viewModel.feed.observe(viewLifecycleOwner){ + adapter.submitList(it.data) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/home/feed/ui/FeedRecyclerViewAdapter.kt b/app/src/main/java/com/isolaatti/home/feed/ui/FeedRecyclerViewAdapter.kt new file mode 100644 index 0000000..869ccc5 --- /dev/null +++ b/app/src/main/java/com/isolaatti/home/feed/ui/FeedRecyclerViewAdapter.kt @@ -0,0 +1,62 @@ +package com.isolaatti.home.feed.ui + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView.ViewHolder +import com.isolaatti.R +import com.isolaatti.home.feed.data.remote.PostDto +import com.isolaatti.utils.UrlGen.userProfileImage +import com.squareup.picasso.Picasso +import io.noties.markwon.Markwon +import java.text.DateFormat +import java.util.Date + +class FeedRecyclerViewAdapter(private val markwon: Markwon) : ListAdapter(DIFF_CALLBACK) { + inner class FeedViewHolder(itemView: View) : ViewHolder(itemView) { + fun bindView(postDto: PostDto) { + val username: TextView = itemView.findViewById(R.id.text_view_username) + username.text = postDto.userName + + val profileImageView: ImageView = itemView.findViewById(R.id.avatar_picture) + Picasso.get().load(userProfileImage(postDto.post.userId)).into(profileImageView) + + val dateTextView: TextView = itemView.findViewById(R.id.text_view_date) + dateTextView.text = postDto.post.date + + val content: TextView = itemView.findViewById(R.id.post_content) + markwon.setMarkdown(content, postDto.post.textContent) + + } + } + + + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedViewHolder { + val view = LayoutInflater.from(parent.context).inflate(R.layout.post_layout, parent, false) + + return FeedViewHolder(view) + } + + override fun onBindViewHolder(holder: FeedViewHolder, position: Int) { + holder.bindView(getItem(position)) + } + + companion object { + val DIFF_CALLBACK = object: DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: PostDto, newItem: PostDto): Boolean { + return oldItem.post.id == newItem.post.id + } + + override fun areContentsTheSame(oldItem: PostDto, newItem: PostDto): Boolean { + return oldItem.post.id == newItem.post.id && oldItem.post.textContent == newItem.post.textContent + } + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/login/LogInViewModel.kt b/app/src/main/java/com/isolaatti/login/LogInViewModel.kt index 600399a..17a6751 100644 --- a/app/src/main/java/com/isolaatti/login/LogInViewModel.kt +++ b/app/src/main/java/com/isolaatti/login/LogInViewModel.kt @@ -14,7 +14,7 @@ import javax.inject.Inject @HiltViewModel class LogInViewModel @Inject constructor(private val authRepository: AuthRepository): ViewModel() { - val signInSuccess: MutableLiveData = MutableLiveData(false) + val signInSuccess: MutableLiveData = MutableLiveData() val formIsValid: MutableLiveData = MutableLiveData(false) val emailUserInputIsValid: MutableLiveData = MutableLiveData(false) val passwordUserInputIsValid: MutableLiveData = MutableLiveData(false) diff --git a/app/src/main/java/com/isolaatti/posts/Module.kt b/app/src/main/java/com/isolaatti/posts/Module.kt new file mode 100644 index 0000000..022a0b3 --- /dev/null +++ b/app/src/main/java/com/isolaatti/posts/Module.kt @@ -0,0 +1,4 @@ +package com.isolaatti.posts + +class Module { +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/posts/data/remote/PostsApi.kt b/app/src/main/java/com/isolaatti/posts/data/remote/PostsApi.kt new file mode 100644 index 0000000..c05fa82 --- /dev/null +++ b/app/src/main/java/com/isolaatti/posts/data/remote/PostsApi.kt @@ -0,0 +1,23 @@ +package com.isolaatti.posts.data.remote + +import com.isolaatti.home.feed.data.remote.FeedDto +import com.isolaatti.home.feed.data.remote.PostDto +import com.isolaatti.profile.data.remote.ProfileListItemDto +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + +interface PostsApi { + @GET("Fetch/PostsOfUser/{userId}") + fun postsOfUser(@Path("userId") userId: Int, + @Query("length") length: Int, + @Query("lastId") lastId: Long, + @Query("olderFirst") olderFirst: Boolean): Call + + @GET("Fetch/Post/{postId}") + fun getPost(@Path("postId") postId: Long): Call + + @GET("Fetch/Post/{postId}/LikedBy") + fun getLikedBy(@Path("postId") postId: Long): Call> +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/profile/Module.kt b/app/src/main/java/com/isolaatti/profile/Module.kt new file mode 100644 index 0000000..453d96d --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/Module.kt @@ -0,0 +1,23 @@ +package com.isolaatti.profile + +import com.isolaatti.connectivity.RetrofitClient +import com.isolaatti.profile.data.remote.ProfileApi +import com.isolaatti.profile.data.repository.ProfileRepositoryImpl +import com.isolaatti.profile.domain.ProfileRepository +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn + +@Module +@InstallIn +class Module { + @Provides + fun provideProfileApi(retrofitClient: RetrofitClient): ProfileApi { + return retrofitClient.client.create(ProfileApi::class.java) + } + + @Provides + fun provideProfileRepository(profileApi: ProfileApi): ProfileRepository { + return ProfileRepositoryImpl(profileApi) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/profile/data/remote/ProfileApi.kt b/app/src/main/java/com/isolaatti/profile/data/remote/ProfileApi.kt new file mode 100644 index 0000000..de8d95f --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/data/remote/ProfileApi.kt @@ -0,0 +1,14 @@ +package com.isolaatti.profile.data.remote + +import com.isolaatti.home.feed.data.remote.FeedDto +import retrofit2.Call +import retrofit2.http.GET +import retrofit2.http.Path + +interface ProfileApi { + + @GET("Fetch/UserProfile/{userId}") + fun userProfile(@Path("userId") userId: Int): Call + + +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/profile/data/remote/ProfileListItemDto.kt b/app/src/main/java/com/isolaatti/profile/data/remote/ProfileListItemDto.kt new file mode 100644 index 0000000..05e3e53 --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/data/remote/ProfileListItemDto.kt @@ -0,0 +1,7 @@ +package com.isolaatti.profile.data.remote + +data class ProfileListItemDto( + val id: Int, + val name: String, + val profileImageId: String? +) \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/profile/data/remote/UserProfileDto.kt b/app/src/main/java/com/isolaatti/profile/data/remote/UserProfileDto.kt new file mode 100644 index 0000000..b3cfae9 --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/data/remote/UserProfileDto.kt @@ -0,0 +1,17 @@ +package com.isolaatti.profile.data.remote + +data class UserProfileDto( + val id: Int, + val name: String, + val email: String, + val numberOfFollowers: Int, + val numberOfFollowing: Int, + val numberOfLikes: Int, + val numberOfPosts: Int, + val isUserItself: Boolean, + val followingThisUser: Boolean, + val thisUserIsFollowingMe: Boolean, + val profileImageId: String?, + val descriptionText: String, + val descriptionAudioId: String? +) diff --git a/app/src/main/java/com/isolaatti/profile/data/repository/ProfileRepositoryImpl.kt b/app/src/main/java/com/isolaatti/profile/data/repository/ProfileRepositoryImpl.kt new file mode 100644 index 0000000..43006a1 --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/data/repository/ProfileRepositoryImpl.kt @@ -0,0 +1,14 @@ +package com.isolaatti.profile.data.repository + +import com.isolaatti.profile.data.remote.ProfileApi +import com.isolaatti.profile.data.remote.UserProfileDto +import com.isolaatti.profile.domain.ProfileRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import retrofit2.await + +class ProfileRepositoryImpl(private val profileApi: ProfileApi) : ProfileRepository { + override fun getProfile(): Flow = flow { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/profile/domain/ProfileRepository.kt b/app/src/main/java/com/isolaatti/profile/domain/ProfileRepository.kt new file mode 100644 index 0000000..8fd59fe --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/domain/ProfileRepository.kt @@ -0,0 +1,9 @@ +package com.isolaatti.profile.domain + +import com.isolaatti.profile.data.remote.ProfileApi +import com.isolaatti.profile.data.remote.UserProfileDto +import kotlinx.coroutines.flow.Flow + +interface ProfileRepository { + fun getProfile(): Flow +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/profile/presentation/ProfileViewModel.kt b/app/src/main/java/com/isolaatti/profile/presentation/ProfileViewModel.kt new file mode 100644 index 0000000..adf3707 --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/presentation/ProfileViewModel.kt @@ -0,0 +1,9 @@ +package com.isolaatti.profile.presentation + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class ProfileViewModel @Inject constructor() : ViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/profile/ui/AudiosFragment.kt b/app/src/main/java/com/isolaatti/profile/ui/AudiosFragment.kt new file mode 100644 index 0000000..97a6d0a --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/ui/AudiosFragment.kt @@ -0,0 +1,21 @@ +package com.isolaatti.profile.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.isolaatti.databinding.FragmentAudiosBinding + +class AudiosFragment : Fragment() { + lateinit var viewBinding: FragmentAudiosBinding + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewBinding = FragmentAudiosBinding.inflate(inflater) + + return viewBinding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/profile/ui/DiscussionsFragment.kt b/app/src/main/java/com/isolaatti/profile/ui/DiscussionsFragment.kt new file mode 100644 index 0000000..f73afce --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/ui/DiscussionsFragment.kt @@ -0,0 +1,22 @@ +package com.isolaatti.profile.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.isolaatti.databinding.FragmentDiscussionsBinding + +class DiscussionsFragment : Fragment() { + lateinit var viewBinding: FragmentDiscussionsBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewBinding = FragmentDiscussionsBinding.inflate(inflater) + + return viewBinding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/profile/ui/ImagesFragment.kt b/app/src/main/java/com/isolaatti/profile/ui/ImagesFragment.kt new file mode 100644 index 0000000..bef6a01 --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/ui/ImagesFragment.kt @@ -0,0 +1,22 @@ +package com.isolaatti.profile.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.isolaatti.databinding.FragmentImagesBinding + +class ImagesFragment : Fragment() { + lateinit var viewBinding: FragmentImagesBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewBinding = FragmentImagesBinding.inflate(inflater) + + return viewBinding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/profile/ui/ProfileActivity.kt b/app/src/main/java/com/isolaatti/profile/ui/ProfileActivity.kt new file mode 100644 index 0000000..1312a80 --- /dev/null +++ b/app/src/main/java/com/isolaatti/profile/ui/ProfileActivity.kt @@ -0,0 +1,70 @@ +package com.isolaatti.profile.ui + +import android.os.Bundle +import androidx.activity.addCallback +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager2.adapter.FragmentStateAdapter +import androidx.viewpager2.adapter.FragmentViewHolder +import com.google.android.material.tabs.TabLayoutMediator +import com.isolaatti.R +import com.isolaatti.databinding.ActivityProfileBinding +import com.squareup.picasso.Picasso +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class ProfileActivity : AppCompatActivity() { + class ViewPagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) { + override fun getItemCount(): Int = 3 + + override fun createFragment(position: Int): Fragment { + return when(position) { + 0 -> { + DiscussionsFragment() + } + 1 -> { + AudiosFragment() + } + 2 -> { + ImagesFragment() + } + else -> {Fragment()} + } + } + + } + + + lateinit var viewBinding: ActivityProfileBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + viewBinding = ActivityProfileBinding.inflate(layoutInflater) + + setContentView(viewBinding.root) + + Picasso.get().load("https://isolaatti.com/api/images/image/63a2a6c5270ecc2be2512799?mode=reduced").into(viewBinding.profileImageView) + viewBinding.textViewUsername.text = "Erik Everardo" + viewBinding.textViewDescription.text = "Hola" + viewBinding.profileViewPager2.adapter = ViewPagerAdapter(this) + viewBinding.topAppBar.setNavigationOnClickListener { + onBackPressed() + } + + TabLayoutMediator(viewBinding.profileTabLayout, viewBinding.profileViewPager2) {tab, position -> + when(position) { + 0 -> { + tab.text = getText(R.string.discussions) + } + 1 -> { + tab.text = getText(R.string.audios) + } + 2 -> { + tab.text = getText(R.string.images) + } + } + }.attach() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/settings/ui/ChangePasswordFragment.kt b/app/src/main/java/com/isolaatti/settings/ui/ChangePasswordFragment.kt new file mode 100644 index 0000000..cef955c --- /dev/null +++ b/app/src/main/java/com/isolaatti/settings/ui/ChangePasswordFragment.kt @@ -0,0 +1,21 @@ +package com.isolaatti.settings.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.isolaatti.databinding.FragmentSettingsChangePasswordBinding + +class ChangePasswordFragment : Fragment() { + lateinit var viewBinding: FragmentSettingsChangePasswordBinding + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewBinding = FragmentSettingsChangePasswordBinding.inflate(inflater) + + return viewBinding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/settings/ui/FeedSettingsFragment.kt b/app/src/main/java/com/isolaatti/settings/ui/FeedSettingsFragment.kt new file mode 100644 index 0000000..6857431 --- /dev/null +++ b/app/src/main/java/com/isolaatti/settings/ui/FeedSettingsFragment.kt @@ -0,0 +1,22 @@ +package com.isolaatti.settings.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.isolaatti.databinding.FragmentSettingsFeedSettingsBinding + +class FeedSettingsFragment : Fragment() { + lateinit var viewBinding: FragmentSettingsFeedSettingsBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewBinding = FragmentSettingsFeedSettingsBinding.inflate(inflater) + + return viewBinding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/settings/ui/SessionsFragment.kt b/app/src/main/java/com/isolaatti/settings/ui/SessionsFragment.kt new file mode 100644 index 0000000..13a0e90 --- /dev/null +++ b/app/src/main/java/com/isolaatti/settings/ui/SessionsFragment.kt @@ -0,0 +1,22 @@ +package com.isolaatti.settings.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.isolaatti.databinding.FragmentSettingsSessionsBinding + +class SessionsFragment : Fragment() { + lateinit var viewBinding: FragmentSettingsSessionsBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewBinding = FragmentSettingsSessionsBinding.inflate(inflater) + + return viewBinding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/settings/ui/SettingsActivity.kt b/app/src/main/java/com/isolaatti/settings/ui/SettingsActivity.kt new file mode 100644 index 0000000..cbb5832 --- /dev/null +++ b/app/src/main/java/com/isolaatti/settings/ui/SettingsActivity.kt @@ -0,0 +1,17 @@ +package com.isolaatti.settings.ui + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.isolaatti.databinding.ActivitySettingsBinding + +class SettingsActivity : AppCompatActivity() { + + lateinit var viewBinding: ActivitySettingsBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + viewBinding = ActivitySettingsBinding.inflate(layoutInflater) + + setContentView(viewBinding.root) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/settings/ui/SettingsFragment.kt b/app/src/main/java/com/isolaatti/settings/ui/SettingsFragment.kt new file mode 100644 index 0000000..b2b2378 --- /dev/null +++ b/app/src/main/java/com/isolaatti/settings/ui/SettingsFragment.kt @@ -0,0 +1,22 @@ +package com.isolaatti.settings.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.isolaatti.databinding.FragmentSettingsBinding + +class SettingsFragment : Fragment() { + lateinit var viewBinding: FragmentSettingsBinding + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewBinding = FragmentSettingsBinding.inflate(inflater) + + return viewBinding.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/utils/IntIdentificationWrapper.kt b/app/src/main/java/com/isolaatti/utils/IntIdentificationWrapper.kt new file mode 100644 index 0000000..aeea8f8 --- /dev/null +++ b/app/src/main/java/com/isolaatti/utils/IntIdentificationWrapper.kt @@ -0,0 +1,3 @@ +package com.isolaatti.utils + +data class IntIdentificationWrapper(val id: Int) diff --git a/app/src/main/java/com/isolaatti/utils/PicassoImagesPluginDef.kt b/app/src/main/java/com/isolaatti/utils/PicassoImagesPluginDef.kt new file mode 100644 index 0000000..74a1704 --- /dev/null +++ b/app/src/main/java/com/isolaatti/utils/PicassoImagesPluginDef.kt @@ -0,0 +1,19 @@ +package com.isolaatti.utils + +import com.squareup.picasso.Picasso +import com.squareup.picasso.RequestCreator +import io.noties.markwon.image.AsyncDrawable +import io.noties.markwon.image.picasso.PicassoImagesPlugin + +object PicassoImagesPluginDef { + val picassoImagePlugin = PicassoImagesPlugin.create(object: PicassoImagesPlugin.PicassoStore { + override fun load(drawable: AsyncDrawable): RequestCreator { + return Picasso.get().load(drawable.destination).tag(drawable) + } + + override fun cancel(drawable: AsyncDrawable) { + Picasso.get().cancelTag(drawable) + } + + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/isolaatti/utils/UrlGen.kt b/app/src/main/java/com/isolaatti/utils/UrlGen.kt new file mode 100644 index 0000000..f09162a --- /dev/null +++ b/app/src/main/java/com/isolaatti/utils/UrlGen.kt @@ -0,0 +1,7 @@ +package com.isolaatti.utils + +import com.isolaatti.connectivity.RetrofitClient.Companion.BASE_URL + +object UrlGen { + fun userProfileImage(userId: Int) = "${BASE_URL}images/profile_image/of_user/1?mode=small" +} \ No newline at end of file diff --git a/app/src/main/res/drawable/baseline_arrow_back_24.xml b/app/src/main/res/drawable/baseline_arrow_back_24.xml new file mode 100644 index 0000000..8452791 --- /dev/null +++ b/app/src/main/res/drawable/baseline_arrow_back_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/comments_solid.xml b/app/src/main/res/drawable/comments_solid.xml new file mode 100644 index 0000000..fc6fe9b --- /dev/null +++ b/app/src/main/res/drawable/comments_solid.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/hands_clapping_solid.xml b/app/src/main/res/drawable/hands_clapping_solid.xml new file mode 100644 index 0000000..9676fad --- /dev/null +++ b/app/src/main/res/drawable/hands_clapping_solid.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml new file mode 100644 index 0000000..6c71d75 --- /dev/null +++ b/app/src/main/res/layout/activity_profile.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml new file mode 100644 index 0000000..357f704 --- /dev/null +++ b/app/src/main/res/layout/activity_settings.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_audios.xml b/app/src/main/res/layout/fragment_audios.xml new file mode 100644 index 0000000..5a8b470 --- /dev/null +++ b/app/src/main/res/layout/fragment_audios.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_discussions.xml b/app/src/main/res/layout/fragment_discussions.xml new file mode 100644 index 0000000..e649140 --- /dev/null +++ b/app/src/main/res/layout/fragment_discussions.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_feed.xml b/app/src/main/res/layout/fragment_feed.xml index be59b6b..0439014 100644 --- a/app/src/main/res/layout/fragment_feed.xml +++ b/app/src/main/res/layout/fragment_feed.xml @@ -16,8 +16,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" - android:hint="@string/searchbar_hint" - app:navigationIcon="@drawable/baseline_menu_24" /> + android:hint="@string/searchbar_hint" /> + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml new file mode 100644 index 0000000..b021a9c --- /dev/null +++ b/app/src/main/res/layout/fragment_settings.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings_change_password.xml b/app/src/main/res/layout/fragment_settings_change_password.xml new file mode 100644 index 0000000..70e0397 --- /dev/null +++ b/app/src/main/res/layout/fragment_settings_change_password.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings_feed_settings.xml b/app/src/main/res/layout/fragment_settings_feed_settings.xml new file mode 100644 index 0000000..92814a8 --- /dev/null +++ b/app/src/main/res/layout/fragment_settings_feed_settings.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings_sessions.xml b/app/src/main/res/layout/fragment_settings_sessions.xml new file mode 100644 index 0000000..490e993 --- /dev/null +++ b/app/src/main/res/layout/fragment_settings_sessions.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/post_layout.xml b/app/src/main/res/layout/post_layout.xml new file mode 100644 index 0000000..26c4431 --- /dev/null +++ b/app/src/main/res/layout/post_layout.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + +