Skip to content

Commit ceb3c22

Browse files
authored
Merge pull request dubesar#519 from JCarlosR/dark_theme_and_icons_for_meme_app
Fixes dubesar#518: Add dark mode and icons
2 parents fb31ba2 + 8cdb2b5 commit ceb3c22

File tree

14 files changed

+167
-97
lines changed

14 files changed

+167
-97
lines changed

Android/Android Apps/MemeShareApp/.idea/misc.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Android/Android Apps/MemeShareApp/README.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ This app shows the memes that come from Reddit. We can share the meme through an
55
![one](app/src/main/res/mipmap-hdpi/one.png)
66

77
## Concepts Learned
8-
- Calling various API's
8+
- Call various APIs
99
- Networking
10-
- Image Processing
11-
- Adding Dependencies
12-
- Calling buttons via onClickListener
10+
- Image processing
11+
- Add dependencies
12+
- Call buttons via onClickListener
1313
- TextView, Layouts
14-
- Asynchronous Callback
14+
- Asynchronous callbacks
1515
- Use Volley and Glide
16+
- Dark theme (using night colors)
17+
- Set menu items
1618

1719
## Asynchronous Callback
1820
An Asynchronous call does not block the program from the code execution. When the call returns from the event, the call returns back to the callback function. So in the context of Java, we have to Create a new thread and invoke the callback method inside that thread. The callback function may be invoked from a thread but is not a requirement. A Callback may also start a new thread, thus making themselves asynchronous.
@@ -24,8 +26,9 @@ Glide Github : [Glide](https://github.com/bumptech/glide)
2426

2527
Meme API : [API](https://github.com/D3vd/Meme_Api)
2628

27-
# Improvement
29+
# Do you want to contribute?
2830
- make the app edit the meme
29-
- make improvement in the UI Of the app
30-
- add Dark Mode
31-
- add Orientation of the app
31+
- make improvements in the UI of the app
32+
- add support for both orientations
33+
- prevent loading a new meme when changing the dark mode status
34+
- add shared preferences to remember user dark mode status

Android/Android Apps/MemeShareApp/app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
android:label="@string/app_name"
1010
android:roundIcon="@mipmap/ic_launcher_round"
1111
android:supportsRtl="true"
12-
android:theme="@style/AppTheme">
13-
<activity android:name=".MainActivity">
12+
android:theme="@style/Theme.MemeApp">
13+
<activity
14+
android:name=".MainActivity">
1415
<intent-filter>
1516
<action android:name="android.intent.action.MAIN" />
16-
1717
<category android:name="android.intent.category.LAUNCHER" />
1818
</intent-filter>
1919
</activity>
Lines changed: 92 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
package com.example.memesharejava;
22

3-
import androidx.annotation.Nullable;
4-
import androidx.appcompat.app.AppCompatActivity;
5-
63
import android.content.Intent;
4+
import android.content.res.Configuration;
75
import android.graphics.drawable.Drawable;
86
import android.os.Bundle;
9-
import android.util.Log;
7+
import android.view.Menu;
8+
import android.view.MenuInflater;
9+
import android.view.MenuItem;
1010
import android.view.View;
1111
import android.widget.Button;
1212
import android.widget.ImageView;
1313
import android.widget.ProgressBar;
14-
import android.widget.Toast;
14+
15+
import androidx.annotation.Nullable;
16+
import androidx.appcompat.app.AppCompatActivity;
17+
import androidx.appcompat.app.AppCompatDelegate;
1518

1619
import com.android.volley.Request;
17-
import com.android.volley.RequestQueue;
1820
import com.android.volley.Response;
1921
import com.android.volley.VolleyError;
2022
import com.android.volley.toolbox.JsonObjectRequest;
21-
import com.android.volley.toolbox.StringRequest;
22-
import com.android.volley.toolbox.Volley;
2323
import com.bumptech.glide.Glide;
2424
import com.bumptech.glide.load.DataSource;
2525
import com.bumptech.glide.load.engine.GlideException;
@@ -29,14 +29,14 @@
2929
import org.json.JSONException;
3030
import org.json.JSONObject;
3131

32-
import java.net.URL;
33-
3432
public class MainActivity extends AppCompatActivity {
3533

36-
ImageView memeImageView;
37-
Button shareButton, nextButton;
38-
ProgressBar progressBar;
39-
String currentImageUrl;
34+
private ImageView memeImageView;
35+
private Button shareButton, nextButton;
36+
private ProgressBar progressBar;
37+
private String currentImageUrl;
38+
39+
private boolean isNightModeEnabled = false;
4040

4141
@Override
4242
protected void onCreate(Bundle savedInstanceState) {
@@ -46,14 +46,16 @@ protected void onCreate(Bundle savedInstanceState) {
4646
memeImageView = (ImageView) findViewById(R.id.memeImageView);
4747
shareButton = (Button) findViewById(R.id.shareButton);
4848
nextButton = (Button) findViewById(R.id.nextButton);
49-
progressBar = (ProgressBar)findViewById(R.id.progressBar);
49+
progressBar = (ProgressBar) findViewById(R.id.progressBar);
50+
51+
checkNightMode();
5052

5153
shareButton.setOnClickListener(new View.OnClickListener() {
5254
@Override
5355
public void onClick(View v) {
5456
Intent intent = new Intent(Intent.ACTION_SEND);
5557
intent.setType("text/plain");
56-
intent.putExtra(Intent.EXTRA_TEXT, "Hey, Checkout this cool meme I got from Reddit "+currentImageUrl);
58+
intent.putExtra(Intent.EXTRA_TEXT, "Hey, Checkout this cool meme I got from Reddit " + currentImageUrl);
5759
startActivity(Intent.createChooser(intent, "Share this meme using..."));
5860
}
5961
});
@@ -67,49 +69,84 @@ public void onClick(View v) {
6769

6870
loadMeme();
6971
}
70-
private void loadMeme() {
72+
73+
private void checkNightMode() {
74+
int nightModeFlag = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
75+
76+
if (nightModeFlag == Configuration.UI_MODE_NIGHT_YES) {
77+
isNightModeEnabled = true;
78+
}
79+
}
80+
81+
public boolean onCreateOptionsMenu(Menu menu) {
82+
MenuInflater inflater = getMenuInflater();
83+
inflater.inflate(R.menu.main_menu, menu);
84+
return true;
85+
}
86+
87+
public boolean onOptionsItemSelected(MenuItem item) {
88+
if (item.getItemId() == R.id.item_dark_mode) {
89+
toggleDarkMode();
90+
return true;
91+
}
92+
return super.onOptionsItemSelected(item);
93+
}
94+
95+
private void toggleDarkMode() {
96+
if (isNightModeEnabled) {
97+
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
98+
} else {
99+
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
100+
}
101+
102+
getDelegate().applyDayNight();
103+
isNightModeEnabled = !isNightModeEnabled;
104+
}
105+
106+
private void loadMeme() {
71107
progressBar.setVisibility(View.VISIBLE);
72108
shareButton.setEnabled(false);
73109
nextButton.setEnabled(false);
74-
// Instantiate the RequestQueue.
75-
String url ="https://meme-api.herokuapp.com/gimme";
76-
77-
// Request a string response from the provided URL.
78-
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null,
79-
new Response.Listener<JSONObject>() {
80-
@Override
81-
public void onResponse(JSONObject response) {
82-
try {
83-
currentImageUrl = response.getString("url");
84-
Glide.with(getApplicationContext()).load(currentImageUrl).listener(new RequestListener<Drawable>() {
85-
@Override
86-
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
87-
progressBar.setVisibility(View.GONE);
88-
nextButton.setEnabled(true);
89-
return false;
90-
}
91-
92-
@Override
93-
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
94-
progressBar.setVisibility(View.GONE);
95-
shareButton.setEnabled(true);
96-
nextButton.setEnabled(true);
97-
return false;
98-
}
99-
}).into(memeImageView);
100-
} catch (JSONException e) {
101-
e.printStackTrace();
102-
}
103-
}
104-
}, new Response.ErrorListener() {
105-
@Override
106-
public void onErrorResponse(VolleyError error){
107110

108-
}
109-
});
111+
// Instantiate the RequestQueue.
112+
String url = "https://meme-api.herokuapp.com/gimme";
113+
114+
// Request a string response from the provided URL.
115+
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null,
116+
new Response.Listener<JSONObject>() {
117+
@Override
118+
public void onResponse(JSONObject response) {
119+
try {
120+
currentImageUrl = response.getString("url");
121+
Glide.with(getApplicationContext()).load(currentImageUrl).listener(new RequestListener<Drawable>() {
122+
@Override
123+
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
124+
progressBar.setVisibility(View.GONE);
125+
nextButton.setEnabled(true);
126+
return false;
127+
}
128+
129+
@Override
130+
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
131+
progressBar.setVisibility(View.GONE);
132+
shareButton.setEnabled(true);
133+
nextButton.setEnabled(true);
134+
return false;
135+
}
136+
}).into(memeImageView);
137+
} catch (JSONException e) {
138+
e.printStackTrace();
139+
}
140+
}
141+
}, new Response.ErrorListener() {
142+
@Override
143+
public void onErrorResponse(VolleyError error) {
110144

111-
// Add the request to the RequestQueue.
112-
MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
113-
}
145+
}
146+
});
114147

148+
// Add the request to the RequestQueue.
149+
MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
115150
}
151+
152+
}

Android/Android Apps/MemeShareApp/app/src/main/java/com/example/memesharejava/MySingleton.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
package com.example.memesharejava;
22

33
import android.content.Context;
4+
45
import com.android.volley.Request;
56
import com.android.volley.RequestQueue;
67
import com.android.volley.toolbox.Volley;
78

8-
import static android.icu.lang.UCharacter.GraphemeClusterBreak.T;
9-
109
public class MySingleton {
1110
private static MySingleton instance;
1211
public RequestQueue requestQueue;
13-
private static Context ctx;
12+
private Context ctx;
1413

1514
private MySingleton(Context context) {
1615
ctx = context;
1716
requestQueue = getRequestQueue();
18-
1917
}
2018

2119
public static synchronized MySingleton getInstance(Context context) {
2220
if (instance == null) {
2321
instance = new MySingleton(context);
2422
}
23+
2524
return instance;
2625
}
2726

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector android:height="24dp" android:tint="#FFFFFF"
2+
android:viewportHeight="24" android:viewportWidth="24"
3+
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4+
<path android:fillColor="@android:color/white" android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
5+
</vector>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector android:height="24dp" android:tint="#FFFFFF"
2+
android:viewportHeight="24" android:viewportWidth="24"
3+
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4+
<path android:fillColor="@android:color/white" android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
5+
</vector>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector android:height="24dp" android:tint="#FFFFFF"
2+
android:viewportHeight="24" android:viewportWidth="24"
3+
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4+
<path android:fillColor="@android:color/white" android:pathData="M6.76,4.84l-1.8,-1.79 -1.41,1.41 1.79,1.79 1.42,-1.41zM4,10.5L1,10.5v2h3v-2zM13,0.55h-2L11,3.5h2L13,0.55zM20.45,4.46l-1.41,-1.41 -1.79,1.79 1.41,1.41 1.79,-1.79zM17.24,18.16l1.79,1.8 1.41,-1.41 -1.8,-1.79 -1.4,1.4zM20,10.5v2h3v-2h-3zM12,5.5c-3.31,0 -6,2.69 -6,6s2.69,6 6,6 6,-2.69 6,-6 -2.69,-6 -6,-6zM11,22.45h2L13,19.5h-2v2.95zM3.55,18.54l1.41,1.41 1.79,-1.8 -1.41,-1.41 -1.79,1.8z"/>
5+
</vector>

Android/Android Apps/MemeShareApp/app/src/main/res/layout/activity_main.xml

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,49 +10,48 @@
1010
android:id="@+id/memeImageView"
1111
android:layout_width="0dp"
1212
android:layout_height="0dp"
13+
android:background="@color/colorBackground"
14+
android:contentDescription="@string/image_view_meme_content_description"
1315
app:layout_constraintBottom_toTopOf="@id/shareButton"
1416
app:layout_constraintLeft_toLeftOf="parent"
1517
app:layout_constraintRight_toRightOf="parent"
1618
app:layout_constraintTop_toTopOf="parent"
17-
tools:srcCompat="@tools:sample/avatars"
18-
android:background="#000000"
19-
/>
19+
tools:srcCompat="@tools:sample/avatars" />
2020

2121
<ProgressBar
2222
android:id="@+id/progressBar"
2323
android:layout_width="wrap_content"
2424
android:layout_height="wrap_content"
25-
app:layout_constraintTop_toTopOf="@id/memeImageView"
2625
app:layout_constraintBottom_toBottomOf="@id/memeImageView"
2726
app:layout_constraintLeft_toLeftOf="@id/memeImageView"
2827
app:layout_constraintRight_toRightOf="@id/memeImageView"
29-
/>
28+
app:layout_constraintTop_toTopOf="@id/memeImageView" />
3029

3130
<Button
3231
android:id="@+id/shareButton"
32+
android:drawableStart="@drawable/ic_baseline_share"
3333
android:layout_width="0dp"
3434
android:layout_height="wrap_content"
35+
android:background="@color/colorPrimaryDark"
3536
android:padding="32dp"
3637
android:text="@string/share"
38+
android:textColor="@color/textColorPrimary"
3739
app:layout_constraintBottom_toBottomOf="parent"
3840
app:layout_constraintLeft_toLeftOf="parent"
39-
app:layout_constraintRight_toLeftOf="@id/guideline"
40-
android:background="@color/colorPrimaryDark"
41-
android:textColor="@color/white"
42-
/>
41+
app:layout_constraintRight_toLeftOf="@id/guideline" />
4342

4443
<Button
44+
android:drawableEnd="@drawable/ic_baseline_navigate_next"
4545
android:id="@+id/nextButton"
4646
android:layout_width="0dp"
4747
android:layout_height="wrap_content"
48+
android:background="@color/colorAccent"
4849
android:padding="32dp"
4950
android:text="@string/next"
51+
android:textColor="@color/textColorPrimary"
5052
app:layout_constraintBottom_toBottomOf="parent"
51-
app:layout_constraintRight_toRightOf="parent"
5253
app:layout_constraintLeft_toRightOf="@id/guideline"
53-
android:background="@color/nextButtonColor"
54-
android:textColor="@color/white"
55-
/>
54+
app:layout_constraintRight_toRightOf="parent" />
5655

5756
<androidx.constraintlayout.widget.Guideline
5857
android:id="@+id/guideline"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<menu xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto">
4+
<item android:id="@+id/item_dark_mode"
5+
app:showAsAction="always"
6+
android:icon="@drawable/ic_dark_mode"
7+
android:title="@string/dark_mode" />
8+
</menu>

0 commit comments

Comments
 (0)