Created
March 21, 2021 07:20
-
-
Save haerulmuttaqin/8c9738bc580f1f5761bb108aff5687f1 to your computer and use it in GitHub Desktop.
#5 — Job Finder App (https://youtu.be/YX_3TjKY-Vw)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<layout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto"> | |
<data> | |
<variable | |
name="item" | |
type="id.haerulmuttaqin.jobfinder.data.entity.GithubJob" /> | |
</data> | |
<androidx.coordinatorlayout.widget.CoordinatorLayout | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@color/blue_200"> | |
<com.google.android.material.appbar.AppBarLayout | |
android:id="@+id/appbar" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:background="@color/blue_200" | |
app:elevation="0dp"> | |
<androidx.appcompat.widget.Toolbar | |
android:id="@+id/toolbar" | |
android:layout_width="match_parent" | |
android:layout_height="?attr/actionBarSize" | |
android:theme="@style/Theme.JobFinder.Toolbar" | |
app:elevation="0dp" | |
app:layout_collapseMode="pin" | |
app:popupTheme="@style/Theme.JobFinder.PopupOverlay" | |
app:titleTextColor="@color/white" /> | |
</com.google.android.material.appbar.AppBarLayout> | |
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout | |
android:id="@+id/swipeRefresh" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@drawable/bg_rounded_top" | |
android:fillViewport="true" | |
android:fitsSystemWindows="true" | |
app:layout_anchor="@id/appbar" | |
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> | |
<RelativeLayout | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@drawable/bg_rounded_top" | |
android:fillViewport="true" | |
android:fitsSystemWindows="true" | |
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> | |
<ImageView | |
android:id="@+id/imgtop" | |
android:layout_width="40dp" | |
android:layout_height="5dp" | |
android:layout_centerHorizontal="true" | |
android:layout_marginTop="8dp" | |
android:background="@drawable/bg_strip_round" /> | |
<androidx.recyclerview.widget.RecyclerView | |
android:id="@+id/recyclerView" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:layout_marginStart="5dp" | |
android:layout_marginEnd="5dp" | |
android:layout_marginTop="15dp" | |
app:layout_behavior="@string/appbar_scrolling_view_behavior" | |
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> | |
<LinearLayout | |
android:id="@+id/emptyView" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:orientation="vertical" | |
android:fillViewport="true" | |
android:clickable="false" | |
android:focusable="false" | |
app:layout_behavior="@string/appbar_scrolling_view_behavior" | |
app:layout_constraintEnd_toEndOf="parent" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintTop_toTopOf="parent"> | |
<ImageView | |
android:layout_width="250dp" | |
android:layout_height="250dp" | |
android:layout_gravity="center" | |
android:layout_marginTop="100dp" | |
android:src="@drawable/ic_undraw_empty" /> | |
<TextView | |
android:id="@+id/textEmpty" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:gravity="center" | |
android:paddingStart="16dp" | |
android:paddingTop="16dp" | |
android:paddingEnd="16dp" | |
android:text="No Data Found" | |
android:fontFamily="@font/medium"/> | |
<TextView | |
android:id="@+id/textEmptyErr" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:gravity="center" | |
android:paddingStart="16dp" | |
android:paddingBottom="16dp" | |
android:paddingEnd="16dp" | |
android:fontFamily="@font/book"/> | |
</LinearLayout> | |
<com.facebook.shimmer.ShimmerFrameLayout | |
android:id="@+id/shimmer" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:orientation="vertical" | |
android:layout_marginTop="16dp" | |
app:layout_behavior="@string/appbar_scrolling_view_behavior" | |
app:shimmer_duration="800" | |
app:shimmer_auto_start="true"> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:orientation="vertical"> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
</LinearLayout> | |
</com.facebook.shimmer.ShimmerFrameLayout> | |
<ImageView | |
android:id="@+id/shadow" | |
android:layout_width="match_parent" | |
android:layout_height="36dp" | |
android:layout_marginStart="3dp" | |
android:layout_marginEnd="3dp" | |
android:layout_marginTop="15dp" | |
android:src="@drawable/bg_shadow_up_to_down" | |
app:layout_anchor="@+id/scroll" | |
app:layout_anchorGravity="top|center" /> | |
</RelativeLayout> | |
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> | |
</androidx.coordinatorlayout.widget.CoordinatorLayout> | |
</layout> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<layout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto"> | |
<data> | |
<variable | |
name="viewModel" | |
type="id.haerulmuttaqin.jobfinder.ui.MainViewModel" /> | |
</data> | |
<androidx.coordinatorlayout.widget.CoordinatorLayout | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@color/blue_200"> | |
<com.google.android.material.appbar.AppBarLayout | |
android:id="@+id/appbar" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
app:elevation="0dp"> | |
<com.google.android.material.appbar.CollapsingToolbarLayout | |
android:id="@+id/collapse" | |
android:layout_width="match_parent" | |
android:layout_height="280dp" | |
app:collapsedTitleTextAppearance="@style/collapsedTitleStyle" | |
app:contentScrim="?attr/colorPrimary" | |
app:expandedTitleMarginBottom="26dp" | |
app:expandedTitleMarginStart="26dp" | |
app:expandedTitleTextAppearance="@style/expandedTitleStyle" | |
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap" | |
app:title="@string/app_name" | |
app:titleEnabled="true"> | |
<RelativeLayout | |
app:layout_collapseMode="parallax" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content"> | |
<ImageView | |
android:id="@+id/banner" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:scaleType="centerCrop" | |
android:src="@drawable/banner_1" /> | |
<TextView | |
android:id="@+id/welcomeText" | |
android:text="Hi, Welcome back" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginStart="26dp" | |
android:layout_marginTop="40dp" | |
android:layout_marginEnd="10dp" | |
android:fontFamily="@font/book" | |
android:textSize="16sp" | |
android:textColor="@color/white" | |
android:layout_toStartOf="@id/notif"/> | |
<TextView | |
android:id="@+id/secondaryText" | |
android:text="Find your perfect job" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_below="@id/welcomeText" | |
android:layout_marginStart="26dp" | |
android:layout_marginTop="2dp" | |
android:layout_marginEnd="10dp" | |
android:layout_toStartOf="@id/notif" | |
android:textSize="26sp" | |
android:textColor="@color/white" | |
android:fontFamily="@font/bold" /> | |
<ImageView | |
android:id="@+id/notif" | |
android:layout_width="26dp" | |
android:layout_height="40dp" | |
android:layout_alignParentTop="true" | |
android:layout_alignParentEnd="true" | |
android:layout_marginTop="42dp" | |
android:layout_marginEnd="16dp" | |
android:contentDescription="@string/app_name" | |
android:src="@drawable/ic_baseline_more_vert_24" | |
android:paddingBottom="10dp" | |
app:tint="@color/white"/> | |
<LinearLayout | |
android:id="@+id/searchLayout" | |
android:orientation="vertical" | |
android:layout_alignParentBottom="true" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content"> | |
<com.google.android.material.card.MaterialCardView | |
android:id="@+id/card_search" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginLeft="20dp" | |
android:layout_marginRight="20dp" | |
android:layout_marginBottom="60dp" | |
android:clickable="true" | |
android:focusable="true" | |
android:background="?attr/selectableItemBackground" | |
app:strokeWidth="0.3dp" | |
app:cardCornerRadius="20dp" | |
app:cardElevation="0dp" | |
app:strokeColor="@color/blue_300" | |
app:cardBackgroundColor="@color/blue_250"> | |
<RelativeLayout | |
android:layout_width="match_parent" | |
android:layout_height="60dp"> | |
<TextView | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:text="What are you looking for?" | |
android:singleLine="true" | |
android:layout_centerVertical="true" | |
android:layout_marginStart="16dp" | |
android:layout_marginEnd="16dp" | |
android:textColor="@color/blue_050" | |
android:fontFamily="@font/book" | |
android:textSize="16dp"/> | |
<ImageView | |
android:src="@drawable/ic_round_search_24" | |
android:layout_width="25dp" | |
android:layout_height="60dp" | |
android:layout_alignParentEnd="true" | |
android:layout_marginEnd="16dp" | |
app:tint="@color/blue_050"/> | |
</RelativeLayout> | |
</com.google.android.material.card.MaterialCardView> | |
</LinearLayout> | |
</RelativeLayout> | |
<androidx.appcompat.widget.Toolbar | |
android:id="@+id/toolbar" | |
android:layout_width="match_parent" | |
android:layout_height="?attr/actionBarSize" | |
android:theme="@style/Theme.JobFinder.Toolbar" | |
android:fitsSystemWindows="true" | |
app:background="@android:color/transparent" | |
app:layout_collapseMode="pin" | |
app:popupTheme="@style/Theme.JobFinder.PopupOverlay" | |
app:titleTextColor="@color/white" /> | |
</com.google.android.material.appbar.CollapsingToolbarLayout> | |
</com.google.android.material.appbar.AppBarLayout> | |
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout | |
android:id="@+id/swipeRefresh" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@drawable/bg_rounded_top" | |
android:fillViewport="true" | |
android:fitsSystemWindows="true" | |
app:layout_anchor="@id/appbar" | |
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> | |
<RelativeLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content"> | |
<androidx.core.widget.NestedScrollView | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginTop="16dp" | |
android:fillViewport="true"> | |
<RelativeLayout | |
android:id="@+id/contentLayout" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content"> | |
<TextView | |
android:id="@+id/markedTitle" | |
android:text="Marked Job" | |
android:textSize="16dp" | |
android:textColor="@color/gray_600" | |
android:layout_marginStart="21dp" | |
android:layout_marginEnd="21dp" | |
android:layout_marginTop="25dp" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:fontFamily="@font/medium"/> | |
<androidx.recyclerview.widget.RecyclerView | |
android:id="@+id/recyclerViewMarked" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginTop="6dp" | |
android:layout_marginBottom="10dp" | |
android:layout_below="@id/markedTitle" | |
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" | |
android:nestedScrollingEnabled="true" | |
android:orientation="horizontal"/> | |
<TextView | |
android:id="@+id/recommendedTitle" | |
android:text="Recommended Job" | |
android:textSize="16dp" | |
android:textColor="@color/gray_600" | |
android:layout_marginStart="21dp" | |
android:layout_marginEnd="21dp" | |
android:layout_marginTop="25dp" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_below="@id/recyclerViewMarked" | |
android:fontFamily="@font/medium"/> | |
<androidx.recyclerview.widget.RecyclerView | |
android:id="@+id/recyclerView" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:layout_marginStart="5dp" | |
android:layout_marginEnd="5dp" | |
android:layout_marginBottom="10dp" | |
android:layout_below="@id/recommendedTitle" | |
app:layout_behavior="@string/appbar_scrolling_view_behavior" | |
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> | |
</RelativeLayout> | |
</androidx.core.widget.NestedScrollView> | |
<com.facebook.shimmer.ShimmerFrameLayout | |
android:id="@+id/shimmer" | |
android:visibility="gone" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:orientation="vertical" | |
android:layout_marginTop="16dp" | |
app:layout_behavior="@string/appbar_scrolling_view_behavior" | |
app:shimmer_duration="800" | |
app:shimmer_auto_start="true"> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:orientation="vertical"> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
<include layout="@layout/item_job_placeholder" /> | |
</LinearLayout> | |
</com.facebook.shimmer.ShimmerFrameLayout> | |
<LinearLayout | |
android:id="@+id/emptyView" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:orientation="vertical" | |
android:fillViewport="true" | |
android:clickable="false" | |
android:focusable="false" | |
app:layout_behavior="@string/appbar_scrolling_view_behavior" | |
app:layout_constraintEnd_toEndOf="parent" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintTop_toTopOf="parent"> | |
<ImageView | |
android:layout_width="250dp" | |
android:layout_height="250dp" | |
android:layout_gravity="center" | |
android:layout_marginTop="100dp" | |
android:src="@drawable/ic_undraw_empty" /> | |
<TextView | |
android:id="@+id/textEmpty" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:gravity="center" | |
android:paddingStart="16dp" | |
android:paddingTop="16dp" | |
android:paddingEnd="16dp" | |
android:text="No Data Found" | |
android:fontFamily="@font/medium"/> | |
<TextView | |
android:id="@+id/textEmptyErr" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:gravity="center" | |
android:paddingStart="16dp" | |
android:paddingBottom="16dp" | |
android:paddingEnd="16dp" | |
android:fontFamily="@font/book"/> | |
</LinearLayout> | |
<ImageView | |
android:id="@+id/shadow" | |
android:layout_width="match_parent" | |
android:layout_height="35dp" | |
android:layout_marginTop="16dp" | |
android:src="@drawable/bg_shadow_up_to_down" | |
android:visibility="visible" /> | |
<ImageView | |
android:background="@drawable/bg_strip_round" | |
android:layout_width="40dp" | |
android:layout_height="5dp" | |
android:layout_marginTop="8dp" | |
android:layout_centerHorizontal="true"/> | |
</RelativeLayout> | |
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> | |
</androidx.coordinatorlayout.widget.CoordinatorLayout> | |
</layout> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dagger.Module; | |
import dagger.android.ContributesAndroidInjector; | |
import id.haerulmuttaqin.jobfinder.ui.MainActivity; | |
import id.haerulmuttaqin.jobfinder.ui.detail.DetailActivity; | |
import id.haerulmuttaqin.jobfinder.ui.list.ListActivity; | |
@Module | |
public abstract class ActivityBuilder { | |
@ContributesAndroidInjector | |
abstract MainActivity mainActivity(); | |
@ContributesAndroidInjector | |
abstract DetailActivity detailActivity(); | |
@ContributesAndroidInjector | |
abstract ListActivity listActivity(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="id.haerulmuttaqin.jobfinder"> | |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | |
<uses-permission android:name="android.permission.INTERNET" /> | |
<application | |
android:name=".App" | |
android:allowBackup="true" | |
android:icon="@mipmap/ic_launcher" | |
android:label="@string/app_name" | |
android:roundIcon="@mipmap/ic_launcher_round" | |
android:supportsRtl="true" | |
android:theme="@style/Theme.JobFinder.NoActionBar"> | |
<activity android:name=".ui.MainActivity"> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
</activity> | |
<activity | |
android:name=".ui.detail.DetailActivity" | |
android:theme="@style/Theme.JobFinder.NoActionBar"/> | |
<activity | |
android:name=".ui.list.ListActivity" | |
android:theme="@style/Theme.JobFinder.NoActionBar"/> | |
</application> | |
</manifest> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.List; | |
import id.haerulmuttaqin.jobfinder.data.entity.GithubJob; | |
import retrofit2.Call; | |
import retrofit2.http.GET; | |
import retrofit2.http.Query; | |
public interface ApiInterface { | |
@GET("positions.json") | |
Call<List<GithubJob>> getJobList(); | |
@GET("positions.json") | |
Call<List<GithubJob>> searchJobList(@Query("search") String keyword); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dependencies { | |
implementation 'com.github.haerulmuttaqin:BottomFluxDialog:0.1.1' | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.List; | |
import javax.inject.Inject; | |
import id.haerulmuttaqin.jobfinder.data.entity.GithubJob; | |
import retrofit2.Call; | |
public class ConnectionServer { | |
@Inject | |
ApiInterface apiInterface; | |
public ConnectionServer(ApiInterface apiInterface) { | |
this.apiInterface = apiInterface; | |
} | |
public Call<List<GithubJob>> getJobList() { | |
return apiInterface.getJobList(); | |
} | |
public Call<List<GithubJob>> searchJobList(String keyword) { | |
return apiInterface.searchJobList(keyword); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.lifecycle.LiveData; | |
import androidx.room.Dao; | |
import androidx.room.Insert; | |
import androidx.room.OnConflictStrategy; | |
import androidx.room.Query; | |
import java.util.List; | |
import id.haerulmuttaqin.jobfinder.data.entity.GithubJob; | |
@Dao | |
public interface GithubJobDao { | |
@Insert(onConflict = OnConflictStrategy.REPLACE) | |
void insert(GithubJob githubJob); | |
@Query("SELECT * FROM githubjob ORDER BY createdAt DESC LIMIT 10") | |
LiveData<List<GithubJob>> getLiveData(); | |
@Query("SELECT * FROM githubjob WHERE LOWER(title) LIKE :keyword OR LOWER(description) LIKE :keyword ORDER BY createdAt DESC") | |
LiveData<List<GithubJob>> searchLiveData(String keyword); | |
@Query("SELECT * FROM githubjob where is_mark = 1 ORDER BY createdAt DESC") | |
LiveData<List<GithubJob>> getLiveDataMarked(); | |
@Query("SELECT * FROM githubjob where id = :id") | |
GithubJob getDataById(String id); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import androidx.lifecycle.LiveData; | |
import java.util.List; | |
import id.haerulmuttaqin.jobfinder.data.entity.GithubJob; | |
public class GithubJobRepository { | |
private static GithubJobDatabase database; | |
private static GithubJobRepository repository; | |
public GithubJobRepository(Context context) { | |
database = GithubJobDatabase.getDatabase(context); | |
} | |
public static GithubJobRepository getInstance(Context context) { | |
if (repository == null) { | |
repository = new GithubJobRepository(context); | |
} | |
return repository; | |
} | |
public void updateMarkJob(GithubJob githubJob) { | |
githubJob.is_mark = githubJob.is_mark == 1 ? 0 : 1; | |
database.githubJobDao().insert(githubJob); | |
} | |
public void insert(GithubJob githubJob) { | |
if (database.githubJobDao().getDataById(githubJob.id) == null) { | |
database.githubJobDao().insert(githubJob); | |
} | |
} | |
public GithubJob getById(String id) { | |
return database.githubJobDao().getDataById(id); | |
} | |
public LiveData<List<GithubJob>> getLiveData() { | |
return database.githubJobDao().getLiveData(); | |
} | |
public LiveData<List<GithubJob>> searchLiveData(String keyword) { | |
keyword = "%" + keyword + "%"; | |
return database.githubJobDao().searchLiveData(keyword); | |
} | |
public LiveData<List<GithubJob>> getLiveDataMarked() { | |
return database.githubJobDao().getLiveDataMarked(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Intent; | |
import android.os.Bundle; | |
import android.view.MenuItem; | |
import android.view.View; | |
import android.widget.Toast; | |
import androidx.annotation.NonNull; | |
import androidx.annotation.Nullable; | |
import androidx.lifecycle.ViewModelProvider; | |
import com.google.android.material.snackbar.Snackbar; | |
import javax.inject.Inject; | |
import id.haerulmuttaqin.jobfinder.R; | |
import id.haerulmuttaqin.jobfinder.Utils; | |
import id.haerulmuttaqin.jobfinder.base.BaseActivity; | |
import id.haerulmuttaqin.jobfinder.data.api.ConnectionServer; | |
import id.haerulmuttaqin.jobfinder.data.entity.GithubJob; | |
import id.haerulmuttaqin.jobfinder.data.storage.GithubJobRepository; | |
import id.haerulmuttaqin.jobfinder.databinding.ActivityListBinding; | |
import id.haerulmuttaqin.jobfinder.ui.MainAdapter; | |
import id.haerulmuttaqin.jobfinder.ui.MainViewModel; | |
import id.haerulmuttaqin.jobfinder.ui.detail.DetailActivity; | |
public class ListActivity extends BaseActivity<ActivityListBinding, MainViewModel> implements MainViewModel.Navigator { | |
@Inject | |
GithubJobRepository repository; | |
@Inject | |
ConnectionServer server; | |
private ActivityListBinding binding; | |
private MainViewModel viewModel; | |
@Override | |
public int getBindingVariable() { | |
return 0; | |
} | |
@Override | |
public int getLayoutId() { | |
return R.layout.activity_list; | |
} | |
@Override | |
public MainViewModel getViewModel() { | |
return viewModel; | |
} | |
@Override | |
protected void onCreate(@Nullable Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
binding = getViewDataBinding(); | |
viewModel = new ViewModelProvider( | |
this, | |
new MainViewModel.ModelFactory(this, server, repository) | |
).get(MainViewModel.class); | |
viewModel.setNavigator(this); | |
if (getIntent().getStringExtra("search") != null) { | |
String keyword = getIntent().getStringExtra("search"); | |
setupActionBar("Search Jobs (" + keyword + ")"); | |
viewModel.searchJobFromServer(keyword); | |
binding.swipeRefresh.setOnRefreshListener(()->viewModel.searchJobFromServer(keyword)); | |
viewModel.searchLiveData(keyword).observe(this, githubJobs -> { | |
binding.recyclerView.setAdapter(new MainAdapter(githubJobs, viewModel)); | |
}); | |
} else { | |
Toast.makeText(this, "Failed get list!", Toast.LENGTH_SHORT).show(); | |
finish(); | |
} | |
} | |
private void setupActionBar(String title) { | |
setSupportActionBar(binding.toolbar); | |
if (getSupportActionBar() != null) { | |
getSupportActionBar().setDisplayHomeAsUpEnabled(true); | |
getSupportActionBar().setTitle(title); | |
} | |
} | |
@Override | |
public boolean onOptionsItemSelected(@NonNull MenuItem item) { | |
if (item.getItemId() == android.R.id.home) { | |
onBackPressed(); | |
return true; | |
} | |
return super.onOptionsItemSelected(item); | |
} | |
@Override | |
public void showProgress() { | |
binding.swipeRefresh.setRefreshing(true); | |
binding.emptyView.setVisibility(View.GONE); | |
binding.shimmer.setVisibility(View.VISIBLE); | |
binding.shimmer.startShimmer(); | |
binding.recyclerView.setVisibility(View.GONE); | |
} | |
@Override | |
public void hideProgress() { | |
binding.swipeRefresh.setRefreshing(false); | |
binding.emptyView.setVisibility(View.GONE); | |
binding.shimmer.setVisibility(View.GONE); | |
binding.shimmer.stopShimmer(); | |
binding.recyclerView.setVisibility(View.VISIBLE); | |
} | |
@Override | |
public void onGetResult(boolean status, String message) { | |
if (!status) { //<-- status result is FALSE | |
binding.textEmptyErr.setText(message); | |
binding.emptyView.setVisibility(View.VISIBLE); | |
} else { | |
binding.emptyView.setVisibility(View.GONE); | |
} | |
} | |
@Override | |
public void onMark(int mark, String title) { | |
Snackbar.make(binding.getRoot(), mark == 0 ? "\uD83D\uDE13 Unmark " + title : "\uD83D\uDE0D Marked " + title, Snackbar.LENGTH_SHORT).show(); | |
} | |
@Override | |
public void onItemClick(GithubJob githubJob) { | |
Intent intent = new Intent(this, DetailActivity.class); | |
intent.putExtra("item", githubJob); | |
startActivity(intent); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Intent; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.widget.RelativeLayout; | |
import androidx.annotation.Nullable; | |
import androidx.lifecycle.ViewModelProvider; | |
import com.google.android.material.bottomsheet.BottomSheetDialog; | |
import com.google.android.material.snackbar.Snackbar; | |
import com.google.android.material.textfield.TextInputEditText; | |
import javax.inject.Inject; | |
import id.haerulmuttaqin.jobfinder.R; | |
import id.haerulmuttaqin.jobfinder.base.BaseActivity; | |
import id.haerulmuttaqin.jobfinder.data.api.ConnectionServer; | |
import id.haerulmuttaqin.jobfinder.data.entity.GithubJob; | |
import id.haerulmuttaqin.jobfinder.data.storage.GithubJobRepository; | |
import id.haerulmuttaqin.jobfinder.databinding.ActivityMainBinding; | |
import id.haerulmuttaqin.jobfinder.ui.detail.DetailActivity; | |
import id.haerulmuttaqin.jobfinder.ui.list.ListActivity; | |
public class MainActivity extends BaseActivity<ActivityMainBinding, MainViewModel> implements MainViewModel.Navigator { | |
@Inject ConnectionServer server; | |
@Inject GithubJobRepository repository; | |
private ActivityMainBinding binding; | |
private MainViewModel viewModel; | |
@Override | |
public int getBindingVariable() { | |
return 0; | |
} | |
@Override | |
public int getLayoutId() { | |
return R.layout.activity_main; | |
} | |
@Override | |
public MainViewModel getViewModel() { | |
return viewModel; | |
} | |
@Override | |
protected void onCreate(@Nullable Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
binding = getViewDataBinding(); | |
viewModel = new ViewModelProvider(this, new MainViewModel.ModelFactory(this, server, repository)).get(MainViewModel.class); | |
viewModel.setNavigator(this); | |
viewModel.getJobFromServer(); | |
viewModel.getLiveData().observe(this, githubJobs -> { | |
binding.recyclerView.setAdapter(new MainAdapter(githubJobs, viewModel)); | |
}); | |
viewModel.getLiveDataMarked().observe(this, githubJobs -> { | |
if (githubJobs.size() > 0) { | |
binding.markedTitle.setVisibility(View.VISIBLE); | |
binding.recyclerViewMarked.setVisibility(View.VISIBLE); | |
binding.recyclerViewMarked.setAdapter(new MainMarkedAdapter(githubJobs, viewModel)); | |
} else { | |
binding.markedTitle.setVisibility(View.GONE); | |
binding.recyclerViewMarked.setVisibility(View.GONE); | |
} | |
}); | |
binding.swipeRefresh.setOnRefreshListener(()->viewModel.getJobFromServer()); | |
binding.cardSearch.setOnClickListener(v->{ | |
showDialogSearch(); | |
}); | |
} | |
private void showDialogSearch() { | |
View view = getLayoutInflater().inflate(R.layout.dialog_search, null); | |
TextInputEditText m = view.findViewById(R.id.message); | |
RelativeLayout btnSearch = view.findViewById(R.id.search); | |
BottomSheetDialog dialog = new BottomSheetDialog(this, R.style.BottomSheetDialogStyle); | |
btnSearch.setOnClickListener(v -> { | |
Intent intent = new Intent(this, ListActivity.class); | |
intent.putExtra("search", m.getText().toString()); | |
startActivity(intent); | |
}); | |
m.requestFocus(); | |
dialog.setContentView(view); | |
dialog.show(); | |
} | |
@Override | |
public void showProgress() { | |
binding.swipeRefresh.setRefreshing(true); | |
binding.emptyView.setVisibility(View.GONE); | |
binding.shimmer.setVisibility(View.VISIBLE); | |
binding.shimmer.startShimmer(); | |
binding.contentLayout.setVisibility(View.GONE); | |
} | |
@Override | |
public void hideProgress() { | |
binding.swipeRefresh.setRefreshing(false); | |
binding.emptyView.setVisibility(View.GONE); | |
binding.shimmer.setVisibility(View.GONE); | |
binding.shimmer.stopShimmer(); | |
binding.contentLayout.setVisibility(View.VISIBLE); | |
} | |
@Override | |
public void onGetResult(boolean status, String message) { | |
if (!status) { //<-- status result is FALSE | |
binding.textEmptyErr.setText(message); | |
binding.emptyView.setVisibility(View.VISIBLE); | |
} else { | |
binding.emptyView.setVisibility(View.GONE); | |
} | |
} | |
@Override | |
public void onMark(int mark, String title) { | |
Snackbar.make(binding.getRoot(), mark == 0 ? "\uD83D\uDE13 Unmark " + title : "\uD83D\uDE0D Marked " + title, Snackbar.LENGTH_SHORT).show(); | |
} | |
@Override | |
public void onItemClick(GithubJob githubJob) { | |
Intent intent = new Intent(this, DetailActivity.class); | |
intent.putExtra("item", githubJob); | |
startActivity(intent); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import androidx.annotation.NonNull; | |
import androidx.lifecycle.LiveData; | |
import androidx.lifecycle.MutableLiveData; | |
import androidx.lifecycle.ViewModel; | |
import androidx.lifecycle.ViewModelProvider; | |
import java.util.List; | |
import id.haerulmuttaqin.jobfinder.Utils; | |
import id.haerulmuttaqin.jobfinder.base.BaseViewModel; | |
import id.haerulmuttaqin.jobfinder.data.api.ConnectionServer; | |
import id.haerulmuttaqin.jobfinder.data.entity.GithubJob; | |
import id.haerulmuttaqin.jobfinder.data.storage.GithubJobRepository; | |
import retrofit2.Call; | |
import retrofit2.Callback; | |
import retrofit2.Response; | |
public class MainViewModel extends BaseViewModel<MainViewModel.Navigator> { | |
MutableLiveData<List<GithubJob>> jobList = new MutableLiveData<>(); | |
public MainViewModel(Context context, ConnectionServer connectionServer, GithubJobRepository repository) { | |
super(context, connectionServer, repository); | |
} | |
public LiveData<List<GithubJob>> getLiveData() { | |
return getRepository().getLiveData(); | |
} | |
public LiveData<List<GithubJob>> searchLiveData(String keyword) { | |
return getRepository().searchLiveData(keyword.toLowerCase()); | |
} | |
public LiveData<List<GithubJob>> getLiveDataMarked() { | |
return getRepository().getLiveDataMarked(); | |
} | |
public String formatDate(String date){ | |
return Utils.dateToTimeFormat(date); | |
} | |
public void getJobFromServer() { | |
getNavigator().showProgress(); | |
getConnectionServer().getJobList().enqueue(new Callback<List<GithubJob>>() { | |
@Override | |
public void onResponse(Call<List<GithubJob>> call, Response<List<GithubJob>> response) { | |
if (response.isSuccessful() && response.body().size() > 0) { | |
for (GithubJob item : response.body()) { | |
item.createdAt = Utils.dateFormatter(item.createdAt); // format date | |
getRepository().insert(item); | |
} | |
getNavigator().onGetResult(true, "Success"); | |
} | |
getNavigator().hideProgress(); | |
} | |
@Override | |
public void onFailure(Call<List<GithubJob>> call, Throwable t) { | |
t.getLocalizedMessage(); | |
getNavigator().hideProgress(); | |
getNavigator().onGetResult(false, Utils.errorMessageHandler(call, t)); | |
} | |
}); | |
} | |
public void searchJobFromServer(String keyword) { | |
getNavigator().showProgress(); | |
getConnectionServer().searchJobList(keyword).enqueue(new Callback<List<GithubJob>>() { | |
@Override | |
public void onResponse(Call<List<GithubJob>> call, Response<List<GithubJob>> response) { | |
if (response.isSuccessful() && response.body().size() > 0) { | |
for (GithubJob item : response.body()) { | |
getRepository().insert(item); | |
} | |
getNavigator().onGetResult(true, "Success"); | |
} | |
getNavigator().hideProgress(); | |
} | |
@Override | |
public void onFailure(Call<List<GithubJob>> call, Throwable t) { | |
t.getLocalizedMessage(); | |
getNavigator().hideProgress(); | |
getNavigator().onGetResult(false, Utils.errorMessageHandler(call, t)); | |
} | |
}); | |
} | |
public void markJob(GithubJob githubJob) { | |
getRepository().updateMarkJob(githubJob); | |
getNavigator().onMark(githubJob.is_mark, githubJob.title); | |
} | |
public void itemClick(GithubJob githubJob) { | |
getNavigator().onItemClick(githubJob); | |
} | |
public static class ModelFactory implements ViewModelProvider.Factory { | |
private Context context; | |
private ConnectionServer server; | |
private GithubJobRepository repository; | |
public ModelFactory(Context context, ConnectionServer server, GithubJobRepository repository) { | |
this.context = context; | |
this.server = server; | |
this.repository = repository; | |
} | |
@NonNull | |
@Override | |
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { | |
return (T) new MainViewModel(context, server, repository); | |
} | |
} | |
public interface Navigator { | |
void showProgress(); | |
void hideProgress(); | |
void onGetResult(boolean status, String message); | |
void onMark(int mark, String title); | |
void onItemClick(GithubJob githubJob); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment