diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..06ea259 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# IntelliJ IDEA files +.idea/ +*.iml + +# Compiled/Output +out/ +*.class + +# Crash logs +hs_err_pid* + +# Windows +Thumbs.db \ No newline at end of file diff --git a/Algorithms/lib/junit-jupiter-5.4.2.jar b/Algorithms/lib/junit-jupiter-5.4.2.jar new file mode 100644 index 0000000..b3bf697 Binary files /dev/null and b/Algorithms/lib/junit-jupiter-5.4.2.jar differ diff --git a/Algorithms/lib/junit-jupiter-api-5.4.2.jar b/Algorithms/lib/junit-jupiter-api-5.4.2.jar new file mode 100644 index 0000000..40828b7 Binary files /dev/null and b/Algorithms/lib/junit-jupiter-api-5.4.2.jar differ diff --git a/Algorithms/lib/junit-jupiter-engine-5.4.2.jar b/Algorithms/lib/junit-jupiter-engine-5.4.2.jar new file mode 100644 index 0000000..3444a98 Binary files /dev/null and b/Algorithms/lib/junit-jupiter-engine-5.4.2.jar differ diff --git a/Algorithms/lib/junit-jupiter-params-5.4.2.jar b/Algorithms/lib/junit-jupiter-params-5.4.2.jar new file mode 100644 index 0000000..ee56504 Binary files /dev/null and b/Algorithms/lib/junit-jupiter-params-5.4.2.jar differ diff --git a/Algorithms/lib/junit-platform-commons-1.4.2.jar b/Algorithms/lib/junit-platform-commons-1.4.2.jar new file mode 100644 index 0000000..2705525 Binary files /dev/null and b/Algorithms/lib/junit-platform-commons-1.4.2.jar differ diff --git a/Algorithms/lib/junit-platform-engine-1.4.2.jar b/Algorithms/lib/junit-platform-engine-1.4.2.jar new file mode 100644 index 0000000..2c46ae9 Binary files /dev/null and b/Algorithms/lib/junit-platform-engine-1.4.2.jar differ diff --git a/Algorithms/lib/opentest4j-1.1.1.jar b/Algorithms/lib/opentest4j-1.1.1.jar new file mode 100644 index 0000000..3f35529 Binary files /dev/null and b/Algorithms/lib/opentest4j-1.1.1.jar differ diff --git a/Algorithms/src/main/xyz/jdtec/algorithms/Algorithms.java b/Algorithms/src/main/xyz/jdtec/algorithms/Algorithms.java new file mode 100644 index 0000000..de050e1 --- /dev/null +++ b/Algorithms/src/main/xyz/jdtec/algorithms/Algorithms.java @@ -0,0 +1,80 @@ +package xyz.jdtec.algorithms; + +import java.util.*; + +public class Algorithms { + /** + * Question 1: Find all pairs for a given sum + * Prints any pairs found with format: "(number, number)", separated by new lines. + * + * This implementation has an O(n) time complexity (linear time) as it only traverses the input array once (rather + * than nested loops). As far as I'm aware, this is the fastest possible implementation. For context, brute-force + * takes O(n^2) (polynomial time), which is horrible. Alternatively, the sort + pointers method is bit better, but + * it requires sorting, which I believe is O(n log n) best-case. + * + * @param testArray integer array to check for pairs + * @param targetSum integer sum to check against + */ + public static void findPairs(int[] testArray, int targetSum) { + // If array length < 2, we can't do anything + if (testArray.length < 2) { + return; + } + + Set> pairs = new HashSet<>(); // Store the found pairs in a Set to prevent duplicates + ArrayList workingList = new ArrayList<>(); // Working list, see below for usage + + // Loop through all the elements of input array + for (int num : testArray) { + // Instead of checking a + b = c, check c - a = b; ...where: a = num, b = checkNum, c = targetSum + int checkNum = targetSum - num; + + if (!workingList.contains(checkNum)) { + // Add current number (a) to "working list" if it doesn't contain complement of current number (b) + workingList.add(num); + } + else { + // Complement of current number (b) was found! Therefore, we must've found a pair; add to pairs Set + pairs.add(Arrays.asList(num, checkNum)); + } + } + + // Run through the Set of pairs and print to stdout according to requested format + for (List pair : pairs) { + // Note: I went through the trouble of storing the pairs as a List rather than as a pre-formatted String + // because later on, if we need to use the data in some other way, it's easy to do so. + System.out.println(String.format("(%d, %d)", pair.get(0), pair.get(1))); + } + } + + /** + * Question 2: Is Palindrome + * Tells you whether a given String is a palindrome! + * + * This implementation uses the existing (and well designed, I assume) StringBuilder.reverse() method provided by + * Java standard library. It has a time complexity of O(n), should be fastest possible. + * + * @param testString String to check for palindromic status + * @return whether String is a palindrome + */ + public static boolean isPalindrome(String testString) { + // Make sure string is lowercase as "Radar" != "radar"! + testString = testString.toLowerCase(); + + // Use the StringBuilder built-in class to reverse the string + StringBuilder str = new StringBuilder(testString); + String reverse = str.reverse().toString(); + + // By definition: string is palindrome if string reads the same way normally and in reverse! + return testString.equals(reverse); + } + + // Main method, for Question 1 example. + public static void main(String[] args) { + // --- Given Example for findPairs --- // + int[] testArray = {2, 4, 5, 1, 3, 5, 4}; + int targetSum = 6; + + findPairs(testArray, targetSum); + } +} diff --git a/Algorithms/src/test/xyz/jdtec/algorithms/AlgorithmsTest.java b/Algorithms/src/test/xyz/jdtec/algorithms/AlgorithmsTest.java new file mode 100644 index 0000000..fc09e69 --- /dev/null +++ b/Algorithms/src/test/xyz/jdtec/algorithms/AlgorithmsTest.java @@ -0,0 +1,83 @@ +package xyz.jdtec.algorithms; + +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + + +class AlgorithmsTest { + // Instantiate our own output stream so we can test methods that print to stdout + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + + // Different OSes have different "line separators" to check for: CRLF or LF + String lf = System.lineSeparator(); + + // --- Setup and Teardown --- // + + @BeforeEach + void setUp() { + // Reset our own output stream and redirect stdout into it + outStream.reset(); + System.setOut(new PrintStream(outStream)); + } + + @AfterEach + void tearDown() { + // Redirect stdout back to System stream + System.setOut(System.out); + } + + // --- findPairs() Tests --- // + + @Test + void findPairsTestInputTooShort() { + // Check for array length < 2 case + Algorithms.findPairs(new int[] {1}, 6); + assertEquals("", outStream.toString()); + } + + @Test + void findPairs() { + // Check for example case + Algorithms.findPairs(new int[] {2, 4, 5, 1, 3, 5, 4}, 6); + assertEquals("(1, 5)" + lf + "(4, 2)" + lf, outStream.toString()); + } + + @Test + void findPairsTestNegativesAndZeroes() { + // Check for negatives and zeroes + Algorithms.findPairs(new int[] {-2, 8, 5, 6, 0, -9, 15}, 6); + assertEquals("(8, -2)" + lf + "(0, 6)" + lf + "(15, -9)" + lf, outStream.toString()); + } + + @Test + void findPairsTestRepeats() { + // Check for repeats + Algorithms.findPairs(new int[] {3, 3, 3, 3, 3, 3}, 6); + assertEquals("(3, 3)" + lf, outStream.toString()); + } + + @Test + void findPairsTestNoPairs() { + // Check for none found + Algorithms.findPairs(new int[] {1, 0}, 6); + assertEquals("", outStream.toString()); + } + + // --- isPalindrome() Tests --- // + + @Test + void isPalindromeTestExamples() { + assertTrue(Algorithms.isPalindrome("radar")); // example case + assertTrue(Algorithms.isPalindrome("BOb")); // example case + random capitalization + assertTrue(Algorithms.isPalindrome("asdfdsa")); // example case + } + + @Test + void isPalindromeTestNonPalindromes() { + assertFalse(Algorithms.isPalindrome("awesome")); // non-palindrome case + assertFalse(Algorithms.isPalindrome("Game of Apps")); // non-palindrome case + random capitalization + } +} \ No newline at end of file diff --git a/Android App/.gitignore b/Android App/.gitignore new file mode 100644 index 0000000..603b140 --- /dev/null +++ b/Android App/.gitignore @@ -0,0 +1,14 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/Android App/app/.gitignore b/Android App/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/Android App/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Android App/app/build.gradle b/Android App/app/build.gradle new file mode 100644 index 0000000..6f7713c --- /dev/null +++ b/Android App/app/build.gradle @@ -0,0 +1,35 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 29 + buildToolsVersion "29.0.3" + + defaultConfig { + applicationId "xyz.jdtec.imageview" + minSdkVersion 28 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation 'androidx.recyclerview:recyclerview:1.0.0' +} diff --git a/Android App/app/proguard-rules.pro b/Android App/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/Android App/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/Android App/app/src/main/AndroidManifest.xml b/Android App/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7e6ce6e --- /dev/null +++ b/Android App/app/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Android App/app/src/main/java/xyz/jdtec/imageview/Image.java b/Android App/app/src/main/java/xyz/jdtec/imageview/Image.java new file mode 100644 index 0000000..5fde4be --- /dev/null +++ b/Android App/app/src/main/java/xyz/jdtec/imageview/Image.java @@ -0,0 +1,63 @@ +package xyz.jdtec.imageview; + +import java.util.ArrayList; + +public class Image { + private int id; + private String caption; + private String description; + private String infoUrl; + + /** + * Image class constructor + * + * @param id Android resource ID for the image + * @param caption caption text for the image + */ + Image(int id, String caption, String description, String infoUrl) { + this.id = id; + this.caption = caption; + this.description = description; + this.infoUrl = infoUrl; + } + + /** + * Method for creating "dummy" images + * + * @return ArrayList of Image objects containing some images and their captions + */ + public static ArrayList createDummyImages() { + ArrayList images = new ArrayList<>(); + + // Returns some images from drawable as well their respective captions + images.add(new Image(R.drawable.sun, "Sun", "The Sun is a main-sequence star in our solar system. As with other stars, the Sun is composed mainly from hydrogen and helium gas.", "https://solarsystem.nasa.gov/solar-system/sun/overview/")); + images.add(new Image(R.drawable.mercury, "Mercury", "Mercury is the 1st planet in our solar system, with an average orbital distance of 0.39 AU away from the Sun. Mercury is mainly composed of rock and metallic elements, and as such is one of the terrestrial planets.", "https://solarsystem.nasa.gov/planets/mercury/overview/")); + images.add(new Image(R.drawable.venus, "Venus", "Venus is the 2nd planet in our solar system, with an average orbital distance of 0.72 AU away from the Sun. Venus is mainly composed of rock and metallic elements, and as such is one of the terrestrial planets.", "https://solarsystem.nasa.gov/planets/venus/overview/")); + images.add(new Image(R.drawable.earth, "Earth", "Earth is the 3rd planet in our solar system, with an average orbital distance of 1 AU away from the Sun. Earth is mainly composed of rock and metallic elements, and as such is one of the terrestrial planets.", "https://solarsystem.nasa.gov/planets/earth/overview/")); + images.add(new Image(R.drawable.mars, "Mars", "Mars is the 4th planet in our solar system, with an average orbital distance of 1.5 AU away from the Sun. Mars is mainly composed of rock and metallic elements, and as such is one of the terrestrial planets.", "https://solarsystem.nasa.gov/planets/mars/overview/")); + images.add(new Image(R.drawable.jupiter, "Jupiter", "Jupiter is the 5th planet in our solar system, with an average orbital distance of 5.2 AU away from the Sun. Jupiter is mainly composed of gaseous elements, and as such is one of the gas giants.", "https://solarsystem.nasa.gov/planets/jupiter/overview/")); + images.add(new Image(R.drawable.saturn, "Saturn", "Saturn is the 6th planet in our solar system, with an average orbital distance of 9.5 AU away from the Sun. Saturn is mainly composed of gaseous elements, and as such is one of the gas giants.", "https://solarsystem.nasa.gov/planets/saturn/overview/")); + images.add(new Image(R.drawable.uranus, "Uranus", "Uranus is the 7th planet in our solar system, with an average orbital distance of 19.2 AU away from the Sun. Uranus is mainly composed of gaseous elements, and as such is one of the gas giants.", "https://solarsystem.nasa.gov/planets/uranus/overview/")); + images.add(new Image(R.drawable.neptune, "Neptune", "Neptune is the 8th planet in our solar system, with an average orbital distance of 30 AU away from the Sun. Neptune is mainly composed of gaseous elements, and as such is one of the gas giants.", "https://solarsystem.nasa.gov/planets/neptune/overview/")); + + return images; + } + + // --- Getters --- + + public int getId() { + return id; + } + + public String getCaption() { + return caption; + } + + public String getDescription() { + return description; + } + + public String getInfoUrl() { + return infoUrl; + } +} diff --git a/Android App/app/src/main/java/xyz/jdtec/imageview/ImageDetailActivity.java b/Android App/app/src/main/java/xyz/jdtec/imageview/ImageDetailActivity.java new file mode 100644 index 0000000..b12b8b3 --- /dev/null +++ b/Android App/app/src/main/java/xyz/jdtec/imageview/ImageDetailActivity.java @@ -0,0 +1,74 @@ +package xyz.jdtec.imageview; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; + +public class ImageDetailActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.image_expanded); + + // Enable "back" button in top toolbar + ActionBar bar = getSupportActionBar(); + bar.setDisplayHomeAsUpEnabled(true); + + // Retrieve the image resource ID, caption, description from intent (passed along by invoking onClick) + Intent intent = getIntent(); + int imageResId = intent.getIntExtra("image", 0); + String imageCaption = intent.getStringExtra("caption"); + String imageDescription = intent.getStringExtra("description"); + + // Set the image, caption text, description to the values obtained above + ((ImageView) findViewById(R.id.expandedImage)).setImageResource(imageResId); + ((TextView) findViewById(R.id.expandedCaption)).setText(imageCaption); + ((TextView) findViewById(R.id.expandedDescription)).setText(imageDescription); + + // If it's the page with my logo on it, must be about page: set title accordingly + if (imageResId == R.drawable.j_logo) { + setTitle(R.string.about_page_name); + } + } + + // --- Action Bar Menu --- // + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.image_detail_menu, menu); // display the menu + + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int itemId = item.getItemId(); // grab menu item ID + + // Change the animation for "back" button + if (itemId == android.R.id.home) { + finish(); + overridePendingTransition(0, android.R.anim.slide_out_right); + } + + // If the info button is the one that is clicked... + if (itemId == R.id.infoButton) { + // Get the info URL from the intent (passed along by invoking onClick) + Intent intent = getIntent(); + String infoUrl = intent.getStringExtra("infoUrl"); + + // Set the URL and start the built-in browser + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(infoUrl)); + startActivity(browserIntent); + } + + return super.onOptionsItemSelected(item); + } +} \ No newline at end of file diff --git a/Android App/app/src/main/java/xyz/jdtec/imageview/ImageViewerAdapter.java b/Android App/app/src/main/java/xyz/jdtec/imageview/ImageViewerAdapter.java new file mode 100644 index 0000000..1f99659 --- /dev/null +++ b/Android App/app/src/main/java/xyz/jdtec/imageview/ImageViewerAdapter.java @@ -0,0 +1,95 @@ +package xyz.jdtec.imageview; + +import android.content.Context; +import android.content.Intent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; + +public class ImageViewerAdapter extends RecyclerView.Adapter { + + // --- ViewHolder Definition --- // + + class ViewHolder extends RecyclerView.ViewHolder { + ImageView imageImageView; + TextView captionTextView; + + // Constructor + ViewHolder(View itemView) { + super(itemView); + + // Get the image and caption views + imageImageView = (ImageView) itemView.findViewById(R.id.image); + captionTextView = (TextView) itemView.findViewById(R.id.caption); + } + } + + // --- Member vars + constructor --- // + + private ArrayList images; + + public ImageViewerAdapter(ArrayList images) { + this.images = images; + } + + // --- Required methods // + + @NonNull + @Override + public ImageViewerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + // Define + Context context = parent.getContext(); + LayoutInflater inflater = LayoutInflater.from(context); + + // Inflate + return + View imageCell = inflater.inflate(R.layout.image_cell, parent, false); + return new ViewHolder(imageCell); + } + + @Override + public void onBindViewHolder(ImageViewerAdapter.ViewHolder holder, int position) { + // Get data + final Image image = images.get(position); + + // Set views + holder.imageImageView.setImageResource(image.getId()); + holder.captionTextView.setText(image.getCaption()); + + // Add some space between bottom of last item and the nav bar + if (position == images.size() - 1) { + holder.captionTextView.setPadding(0, 0, 0, 100); + } + + // Add an onClick listener to launch the expanded image activity + holder.imageImageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + // Grab a context and create an intent + Context context = view.getContext(); + Intent intent = new Intent(context, ImageDetailActivity.class); + + // Pass along the image resource ID, caption, description and info URL + intent.putExtra("image", image.getId()); + intent.putExtra("caption", image.getCaption()); + intent.putExtra("description", image.getDescription()); + intent.putExtra("infoUrl", image.getInfoUrl()); + + context.startActivity(intent); // start activity! + } + }); + + } + + @Override + public int getItemCount() { + return images.size(); + } +} + diff --git a/Android App/app/src/main/java/xyz/jdtec/imageview/MainActivity.java b/Android App/app/src/main/java/xyz/jdtec/imageview/MainActivity.java new file mode 100644 index 0000000..584c04a --- /dev/null +++ b/Android App/app/src/main/java/xyz/jdtec/imageview/MainActivity.java @@ -0,0 +1,60 @@ +package xyz.jdtec.imageview; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.content.Intent; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Define RecyclerView, LayoutManager, Adapter + RecyclerView imageViewerView = (RecyclerView) findViewById(R.id.imageViewer); + GridLayoutManager GLM = new GridLayoutManager(this, 2); + ImageViewerAdapter adapter = new ImageViewerAdapter(Image.createDummyImages()); + + // Setup adapter, layout manager, settings + imageViewerView.setHasFixedSize(true); + imageViewerView.setLayoutManager(GLM); + imageViewerView.setAdapter(adapter); + } + + // --- Action Bar Menu --- // + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.image_detail_menu, menu); // display the menu + + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int itemId = item.getItemId(); // grab menu item ID + + // If the info button is the one that is clicked... + if (itemId == R.id.infoButton) { + // Create an intent + // Note: this "about" page reuses the ImageDetail page, so extra layout is not needed! + Intent intent = new Intent(this, ImageDetailActivity.class); + + // Pass along the my info + intent.putExtra("image", R.drawable.j_logo); + intent.putExtra("caption", "ImageViewer: created with ❤️ by Joe Dai."); + intent.putExtra("description", "This app is published under the MIT license.\n\nThe solar system images contained within this app is obtained from NASA for non-commercial use. All image copyrights go to their respective owners."); + intent.putExtra("infoUrl", "https://jdtec.xyz/"); + + this.startActivity(intent); // start activity! + } + + return super.onOptionsItemSelected(item); + } +} diff --git a/Android App/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Android App/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/Android App/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Android App/app/src/main/res/drawable/earth.jpg b/Android App/app/src/main/res/drawable/earth.jpg new file mode 100644 index 0000000..0774fee Binary files /dev/null and b/Android App/app/src/main/res/drawable/earth.jpg differ diff --git a/Android App/app/src/main/res/drawable/ic_launcher_background.xml b/Android App/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/Android App/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Android App/app/src/main/res/drawable/ic_menu_info.xml b/Android App/app/src/main/res/drawable/ic_menu_info.xml new file mode 100644 index 0000000..ef049e5 --- /dev/null +++ b/Android App/app/src/main/res/drawable/ic_menu_info.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/Android App/app/src/main/res/drawable/j_logo.png b/Android App/app/src/main/res/drawable/j_logo.png new file mode 100644 index 0000000..91b98ae Binary files /dev/null and b/Android App/app/src/main/res/drawable/j_logo.png differ diff --git a/Android App/app/src/main/res/drawable/jupiter.jpg b/Android App/app/src/main/res/drawable/jupiter.jpg new file mode 100644 index 0000000..727f2ab Binary files /dev/null and b/Android App/app/src/main/res/drawable/jupiter.jpg differ diff --git a/Android App/app/src/main/res/drawable/mars.png b/Android App/app/src/main/res/drawable/mars.png new file mode 100644 index 0000000..1e888e4 Binary files /dev/null and b/Android App/app/src/main/res/drawable/mars.png differ diff --git a/Android App/app/src/main/res/drawable/mercury.jpg b/Android App/app/src/main/res/drawable/mercury.jpg new file mode 100644 index 0000000..2f91d16 Binary files /dev/null and b/Android App/app/src/main/res/drawable/mercury.jpg differ diff --git a/Android App/app/src/main/res/drawable/neptune.jpg b/Android App/app/src/main/res/drawable/neptune.jpg new file mode 100644 index 0000000..7315870 Binary files /dev/null and b/Android App/app/src/main/res/drawable/neptune.jpg differ diff --git a/Android App/app/src/main/res/drawable/saturn.png b/Android App/app/src/main/res/drawable/saturn.png new file mode 100644 index 0000000..a9bc5db Binary files /dev/null and b/Android App/app/src/main/res/drawable/saturn.png differ diff --git a/Android App/app/src/main/res/drawable/sun.jpg b/Android App/app/src/main/res/drawable/sun.jpg new file mode 100644 index 0000000..4de7069 Binary files /dev/null and b/Android App/app/src/main/res/drawable/sun.jpg differ diff --git a/Android App/app/src/main/res/drawable/uranus.jpg b/Android App/app/src/main/res/drawable/uranus.jpg new file mode 100644 index 0000000..5f6338f Binary files /dev/null and b/Android App/app/src/main/res/drawable/uranus.jpg differ diff --git a/Android App/app/src/main/res/drawable/venus.png b/Android App/app/src/main/res/drawable/venus.png new file mode 100644 index 0000000..a60db49 Binary files /dev/null and b/Android App/app/src/main/res/drawable/venus.png differ diff --git a/Android App/app/src/main/res/layout/activity_main.xml b/Android App/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..fa66a4e --- /dev/null +++ b/Android App/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/Android App/app/src/main/res/layout/image_cell.xml b/Android App/app/src/main/res/layout/image_cell.xml new file mode 100644 index 0000000..d89b3b6 --- /dev/null +++ b/Android App/app/src/main/res/layout/image_cell.xml @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Android App/app/src/main/res/layout/image_expanded.xml b/Android App/app/src/main/res/layout/image_expanded.xml new file mode 100644 index 0000000..06b2411 --- /dev/null +++ b/Android App/app/src/main/res/layout/image_expanded.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Android App/app/src/main/res/menu/image_detail_menu.xml b/Android App/app/src/main/res/menu/image_detail_menu.xml new file mode 100644 index 0000000..61508f4 --- /dev/null +++ b/Android App/app/src/main/res/menu/image_detail_menu.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/Android App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Android App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/Android App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Android App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Android App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/Android App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Android App/app/src/main/res/mipmap-hdpi/ic_launcher.png b/Android App/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..a571e60 Binary files /dev/null and b/Android App/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/Android App/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Android App/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..61da551 Binary files /dev/null and b/Android App/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/Android App/app/src/main/res/mipmap-mdpi/ic_launcher.png b/Android App/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c41dd28 Binary files /dev/null and b/Android App/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/Android App/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Android App/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..db5080a Binary files /dev/null and b/Android App/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/Android App/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/Android App/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..6dba46d Binary files /dev/null and b/Android App/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/Android App/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Android App/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..da31a87 Binary files /dev/null and b/Android App/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/Android App/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Android App/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..15ac681 Binary files /dev/null and b/Android App/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/Android App/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Android App/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..b216f2d Binary files /dev/null and b/Android App/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/Android App/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Android App/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..f25a419 Binary files /dev/null and b/Android App/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/Android App/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Android App/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..e96783c Binary files /dev/null and b/Android App/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/Android App/app/src/main/res/values/colors.xml b/Android App/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..cf2ebed --- /dev/null +++ b/Android App/app/src/main/res/values/colors.xml @@ -0,0 +1,9 @@ + + + + #BB86FC + #3700B3 + #03DAC6 + #121212 + #FFF + diff --git a/Android App/app/src/main/res/values/strings.xml b/Android App/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..561a41b --- /dev/null +++ b/Android App/app/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + ImageViewer + Image Details + About ImageViewer + More info + diff --git a/Android App/app/src/main/res/values/styles.xml b/Android App/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..9de70d6 --- /dev/null +++ b/Android App/app/src/main/res/values/styles.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/Android App/build.gradle b/Android App/build.gradle new file mode 100644 index 0000000..659b03c --- /dev/null +++ b/Android App/build.gradle @@ -0,0 +1,29 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + jcenter() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.6.2' + + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/Android App/gradle.properties b/Android App/gradle.properties new file mode 100644 index 0000000..199d16e --- /dev/null +++ b/Android App/gradle.properties @@ -0,0 +1,20 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true + diff --git a/Android App/gradle/wrapper/gradle-wrapper.jar b/Android App/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f6b961f Binary files /dev/null and b/Android App/gradle/wrapper/gradle-wrapper.jar differ diff --git a/Android App/gradle/wrapper/gradle-wrapper.properties b/Android App/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0af643a --- /dev/null +++ b/Android App/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Jun 16 19:11:23 PDT 2020 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip diff --git a/Android App/gradlew b/Android App/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/Android App/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/Android App/gradlew.bat b/Android App/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/Android App/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Android App/settings.gradle b/Android App/settings.gradle new file mode 100644 index 0000000..77e3759 --- /dev/null +++ b/Android App/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name='ImageView' +include ':app' diff --git a/README.md b/README.md index 562449d..98d8b01 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,82 @@ # Game of Apps Development Intern Interview +### Submission: Joe Dai -Thanks for your interest in the Game of Apps developer intern position! This repo contains a list of tasks for you to do, so we can get a gauge of your skill and passion for development. - -You're expected to know the basics of the Git development workflow. If you don't know or you want a review, check out this [tutorial](https://www.raywenderlich.com/179717/open-source-collaboration-using-git-and-github). +> Thanks for your interest in the Game of Apps developer intern position! This repo contains a list of tasks for you to do, so we can get a gauge of your skill and passion for development. +> +> You're expected to know the basics of the Git development workflow. If you don't know or you want a review, check out this [tutorial](https://www.raywenderlich.com/179717/open-source-collaboration-using-git-and-github). ## Instructions -The goal is to submit a pull request that accomplishes the following tasks. While the pull requests are public, don't blindly copy others. The follow up interview will involve questions on your submission. - -Fork this repository to begin. - -Commit your changes to your fork, then email the link of your fork to careers@gameofapps.org. +> The goal is to submit a pull request that accomplishes the following tasks. While the pull requests are public, don't blindly copy others. The follow up interview will involve questions on your submission. +> +> Fork this repository to begin. +> +> Commit your changes to your fork, then email the link of your fork to careers@gameofapps.org. ## Challenge 1: Algorithms -Your first challenge is to solve two algorithm questions. You'll be judged based on correctness, performance, and code readability. - -### Question 1: Find all pairs for a given sum - -Create a function that accepts an array of integers and a target sum. The function will print all pairs of integers in the array whose sum is equal to the target sum. Here's an example: - -```java -int[] testArray = {2, 4, 5, 1, 3, 5, 4}; -int targetSum = 6; -// Expected pairs are (to be printed on the console): -// (2, 4) -// (1, 5) - -findPairs(testArray, targetSum); -``` - -Here's a function signature to start you off: +> Your first challenge is to solve two algorithm questions. You'll be judged based on correctness, performance, and code readability. + +**See solution at: [Algorithms.java](./Algorithms/src/main/xyz/jdtec/algorithms/Algorithms.java)** + +**See JUnit tests at: [AlgorithmsTest.java](./Algorithms/src/test/xyz/jdtec/algorithms/AlgorithmsTest.java)** + +> ### Question 1: Find all pairs for a given sum +> +> Create a function that accepts an array of integers and a target sum. The function will print all pairs of integers in the array whose sum is equal to the target sum. Here's an example: +> +> ```java +> int[] testArray = {2, 4, 5, 1, 3, 5, 4}; +> int targetSum = 6; +> // Expected pairs are (to be printed on the console): +> // (2, 4) +> // (1, 5) +> +> findPairs(testArray, targetSum); +> ``` +> +> Here's a function signature to start you off: +> +> ```java +> void findPairs(int[] testArray, int targetSum) { +> // your code here +> } +> ``` +> +> ### Question 2: Is Palindrome? +> +> Create a function that checks if a string is a palindrome and returns `true` or `false`. A palindrome is a word that reads the same way even if you read it backwards. +> +> Example palindromes: +> +> - radar +> - bob +> - asdfdsa +> +> Here's a function signature to start you off: +> +> ```java +> boolean isPalindrome(String testString) { +> // your code here +> } +> ``` -```java -void findPairs(int[] testArray, int targetSum) { - // your code here -} -``` - -### Question 2: Is Palindrome? - -Create a function that checks if a string is a palindrome and returns `true` or `false`. A palindrome is a word that reads the same way even if you read it backwards. - -Example palindromes: - -- radar -- bob -- asdfdsa - -Here's a function signature to start you off: +## Challenge 2: Android -```java -boolean isPalindrome(String testString) { - // your code here -} -``` +> Your second challenge is to develop a small app from scratch. Here are the requirements: +> +> - It should show a list of images. +> - Tapping on an image should navigate to a new screen that shows the selected picture -## Challenge 2: Android +**See app solution at: [Android App](./Android%20App/app/src/main) — "ImageViewer"** -Your second challenge is to develop a small app from scratch. Here are the requirements: +--- -- It should show a list of images. -- Tapping on an image should navigate to a new screen that shows the selected picture +> ### Notes: +> +> - A good developer tries to write code that is easy to understand. The industry has a set of best practices that focus on writing easy to maintain code. Here's a set of guidelines on these best practices: [Java Style Guide](https://github.com/raywenderlich/java-style-guide). +> -### Notes: +--- -- A good developer tries to write code that is easy to understand. The industry has a set of best practices that focus on writing easy to maintain code. Here's a set of guidelines on these best practices: [Java Style Guide](https://github.com/raywenderlich/java-style-guide). +*All code within this repo is licensed under the [MIT license](https://opensource.org/licenses/MIT)*