diff --git a/app/build.gradle b/app/build.gradle index 77341663..ccc80bdb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,13 +8,13 @@ plugins { } def flavor android { - compileSdk 32 + compileSdk 33 defaultConfig { minSdk 21 - targetSdk 32 - versionCode 450 - versionName "3.12.0" + targetSdk 33 + versionCode 454 + versionName "3.13.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } flavorDimensions "default" @@ -106,7 +106,7 @@ dependencies { implementation 'com.burhanrashid52:photoeditor:1.5.1' - implementation project(path: ':cropper') + implementation("com.vanniktech:android-image-cropper:4.3.3") annotationProcessor "com.github.bumptech.glide:compiler:4.12.0" implementation 'jp.wasabeef:glide-transformations:4.3.0' implementation 'com.github.penfeizhou.android.animation:glide-plugin:2.24.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0a10c058..6543017c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + @@ -213,7 +214,7 @@ android:configChanges="keyboardHidden|orientation|screenSize" android:label="@string/scheduled" /> diff --git a/app/src/main/assets/quotes/famous.json b/app/src/main/assets/quotes/famous.json new file mode 100644 index 00000000..9de67faa --- /dev/null +++ b/app/src/main/assets/quotes/famous.json @@ -0,0 +1,8206 @@ +[ + { + "content": "In the depth of winter, I finally learned that there was within me an invincible summer.", + "author": "Albert Camus" + }, + { + "content": "To follow, without halt, one aim: There is the secret of success.", + "author": "Anna Pavlova" + }, + { + "content": "Focusing your life solely on making a buck shows a poverty of ambition. It asks too little of yourself. And it will leave you unfulfilled.", + "author": "Barack Obama" + }, + { + "content": "You cannot travel the path until you have become the path itself.", + "author": "Buddha" + }, + { + "content": "It is never too late to be what you might have been.", + "author": "George Eliot" + }, + { + "content": "Pick battles big enough to matter, small enough to win.", + "author": "Jonathan Kozol" + }, + { + "content": "Who sows virtue reaps honor.", + "author": "Leonardo da Vinci" + }, + { + "content": "Nobody will believe in you unless you believe in yourself.", + "author": "Liberace" + }, + { + "content": "Each day provides its own gifts.", + "author": "Marcus Aurelius" + }, + { + "content": "Don't wait. The time will never be just right.", + "author": "Napoleon Hill" + }, + { + "content": "If I am not for myself, who will be for me? If I am not for others, what am I? And if not now, when?", + "author": "Rabbi Hillel" + }, + { + "content": "Do not go where the path may lead, go instead where there is no path and leave a trail.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Nothing great was ever achieved without enthusiasm.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "If you love someone, set them free. If they come back, they're yours; if they don't, they never were.", + "author": "Richard Bach" + }, + { + "content": "There is no duty we so underrate as the duty of being happy. By being happy we sow anonymous benefits upon the world.", + "author": "Robert Louis Stevenson" + }, + { + "content": "These days people seek knowledge, not wisdom. Knowledge is of the past; wisdom is of the future.", + "author": "Vernon Cooper" + }, + { + "content": "This is the final test of a gentleman: his respect for those who can be of no possible value to him.", + "author": "William Lyon Phelps" + }, + { + "_id": "EBX5NXqc-R6-", + "content": "Six essential qualities that are the key to success: Sincerity, personal integrity, humility, courtesy, wisdom, charity.", + "author": "William C. Menninger" + }, + { + "content": "Short words are best and the old words when short are best of all.", + "author": "Winston Churchill" + }, + { + "content": "Applause is a receipt, not a bill.", + "author": "Dale Carnegie" + }, + { + "content": "Talent is God-given; be humble. Fame is man-given; be thankful. Conceit is self-given; be careful.", + "author": "Harvey Mackay" + }, + { + "content": "Never interrupt someone doing what you said couldn't be done.", + "author": "Amelia Earhart" + }, + { + "content": "Some of the best lessons we ever learn are learned from past mistakes. The error of the past is the wisdom and success of the future.", + "author": "Dale Turner" + }, + { + "content": "Many sophisticated, intelligent people lack wisdom and common sense.", + "author": "Joyce Meyer" + }, + { + "content": "Every friendship goes through ups and downs. Dysfunctional patterns set in; external situations cause internal friction; you grow apart and then bounce back together.", + "author": "Mariella Frostrup" + }, + { + "content": "Friendship, like love, is destroyed by long absence, though it may be increased by short intermissions.", + "author": "Samuel Johnson" + }, + { + "content": "Do something wonderful, people may imitate it.", + "author": "Albert Schweitzer" + }, + { + "content": "There surely is in human nature an inherent propensity to extract all the good out of all the evil.", + "author": "Benjamin Haydon" + }, + { + "content": "As you think, so shall you become.", + "author": "Bruce Lee" + }, + { + "content": "Genuine sincerity opens people's hearts, while manipulation causes them to close.", + "author": "Daisaku Ikeda" + }, + { + "content": "The universe is full of magical things, patiently waiting for our wits to grow sharper.", + "author": "Eden Phillpotts" + }, + { + "content": "Those who cannot learn from history are doomed to repeat it.", + "author": "George Santayana" + }, + { + "content": "Ability is what you're capable of doing. Motivation determines what you do. Attitude determines how well you do it.", + "author": "Lou Holtz" + }, + { + "content": "The thoughts we choose to think are the tools we use to paint the canvas of our lives.", + "author": "Louise Hay" + }, + { + "content": "Every adversity, every failure, every heartache carries with it the seed of an equal or greater benefit.", + "author": "Napoleon Hill" + }, + { + "content": "Strong beliefs win strong men, and then make them stronger.", + "author": "Richard Bach" + }, + { + "content": "Do you want to know who you are? Don't ask. Act! Action will delineate and define you.", + "author": "Thomas Jefferson" + }, + { + "content": "A wise man is superior to any insults which can be put upon him, and the best reply to unseemly behavior is patience and moderation.", + "author": "Molière" + }, + { + "content": "Well done is better than well said.", + "author": "Benjamin Franklin" + }, + { + "content": "We must not allow ourselves to become like the system we oppose.", + "author": "Desmond Tutu" + }, + { + "content": "You will not be punished for your anger; you will be punished by your anger.", + "author": "Buddha" + }, + { + "content": "The key to transforming our hearts and minds is to have an understanding of how our thoughts and emotions work.", + "author": "Dalai Lama" + }, + { + "content": "Do not give your attention to what others do or fail to do; give it to what you do or fail to do.", + "author": "Dhammapada" + }, + { + "content": "People grow through experience if they meet life honestly and courageously. This is how character is built.", + "author": "Eleanor Roosevelt" + }, + { + "content": "If you wish to be a writer, write.", + "author": "Epictetus" + }, + { + "content": "Not every difficult and dangerous thing is suitable for training, but only that which is conducive to success in achieving the object of our effort.", + "author": "Epictetus" + }, + { + "content": "But man is not made for defeat. A man can be destroyed but not defeated.", + "author": "Ernest Hemingway" + }, + { + "content": "Character cannot be developed in ease and quiet. Only through experience of trial and suffering can the soul be strengthened, vision cleared, ambition inspired, and success achieved.", + "author": "Helen Keller" + }, + { + "content": "You can't shake hands with a clenched fist.", + "author": "Indira Gandhi" + }, + { + "content": "There are things so deep and complex that only intuition can reach it in our stage of development as human beings.", + "author": "John Astin" + }, + { + "content": "You can't stop the waves, but you can learn to surf.", + "author": "Jon Kabat-Zinn" + }, + { + "content": "If you correct your mind, the rest of your life will fall into place.", + "author": "Laozi" + }, + { + "content": "Imagination is the highest kite one can fly.", + "author": "Lauren Bacall" + }, + { + "content": "I never see what has been done; I only see what remains to be done.", + "author": "Marie Curie" + }, + { + "content": "Those who are blessed with the most talent don't necessarily outperform everyone else. It's the people with follow-through who excel.", + "author": "Mary Kay Ash" + }, + { + "content": "No man can succeed in a line of endeavor which he does not like.", + "author": "Napoleon Hill" + }, + { + "content": "Here is one quality that one must possess to win, and that is definiteness of purpose, the knowledge of what one wants, and a burning desire to possess it.", + "author": "Napoleon Hill" + }, + { + "content": "By believing passionately in something that does not yet exist, we create it.", + "author": "Nikos Kazantzakis" + }, + { + "content": "The meaning I picked, the one that changed my life: Overcome fear, behold wonder.", + "author": "Richard Bach" + }, + { + "content": "It's so simple to be wise. Just think of something stupid to say and then don't say it.", + "author": "Sam Levenson" + }, + { + "content": "Leaders aren't born they are made. And they are made just like anything else, through hard work. And that's the price we'll have to pay to achieve that goal, or any goal.", + "author": "Vince Lombardi" + }, + { + "content": "Everything you are against weakens you. Everything you are for empowers you.", + "author": "Wayne Dyer" + }, + { + "content": "Do more than dream: work.", + "author": "William Arthur Ward" + }, + { + "content": "The function of wisdom is to discriminate between good and evil.", + "author": "Cicero" + }, + { + "content": "Genius unrefined resembles a flash of lightning, but wisdom is like the sun.", + "author": "Franz Grillparzer" + }, + { + "content": "The greatest healing therapy is friendship and love.", + "author": "Hubert Humphrey" + }, + { + "content": "Those that know, do. Those that understand, teach.", + "author": "Aristotle" + }, + { + "content": "We need to find the courage to say NO to the things and people that are not serving us if we want to rediscover ourselves and live our lives with authenticity.", + "author": "Barbara De Angelis" + }, + { + "content": "We must learn our limits. We are all something, but none of us are everything.", + "author": "Blaise Pascal" + }, + { + "content": "Choose a job you love, and you will never have to work a day in your life.", + "author": "Confucius" + }, + { + "content": "They must often change, who would be constant in happiness or wisdom.", + "author": "Confucius" + }, + { + "content": "Respect should be earned by actions, and not acquired by years.", + "author": "Frank Lloyd Wright" + }, + { + "content": "We are all inclined to judge ourselves by our ideals; others, by their acts.", + "author": "Harold Nicolson" + }, + { + "content": "Correction does much, but encouragement does more.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "All the great performers I have worked with are fueled by a personal dream.", + "author": "John Eliot" + }, + { + "content": "Beauty is not in the face; beauty is a light in the heart.", + "author": "Kahlil Gibran" + }, + { + "content": "You were not born a winner, and you were not born a loser. You are what you make yourself be.", + "author": "Lou Holtz" + }, + { + "content": "How wonderful that we have met with a paradox. Now we have some hope of making progress.", + "author": "Niels Bohr" + }, + { + "content": "What we achieve inwardly will change outer reality.", + "author": "Plutarch" + }, + { + "content": "Our strength grows out of our weaknesses.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Can miles truly separate you from friends... If you want to be with someone you love, aren't you already there?", + "author": "Richard Bach" + }, + { + "content": "Things that were hard to bear are sweet to remember.", + "author": "Seneca the Younger" + }, + { + "content": "The supreme art of war is to subdue the enemy without fighting.", + "author": "Sun Tzu" + }, + { + "content": "The most formidable weapon against errors of every kind is reason.", + "author": "Thomas Paine" + }, + { + "content": "When people are like each other they tend to like each other.", + "author": "Tony Robbins" + }, + { + "content": "You have enemies? Good. That means you've stood up for something, sometime in your life.", + "author": "Winston Churchill" + }, + { + "content": "The three great essentials to achieve anything worthwhile are: Hard work, Stick-to-itiveness, and Common sense.", + "author": "Thomas Edison" + }, + { + "content": "If you were to offer a thirsty man all wisdom, you would not please him more than if you gave him a drink.", + "author": "Sophocles" + }, + { + "_id": "y2-XO-7xRg", + "content": "Love is the attempt to form a friendship inspired by beauty.", + "author": "Cicero" + }, + { + "content": "To hell with circumstances, I create opportunities.", + "author": "Bruce Lee" + }, + { + "content": "True happiness means forging a strong spirit that is undefeated, no matter how trying our circumstances.", + "author": "Daisaku Ikeda" + }, + { + "content": "When fate hands us a lemon, let's try to make lemonade.", + "author": "Dale Carnegie" + }, + { + "content": "One must be fond of people and trust them if one is not to make a mess of life.", + "author": "E. M. Forster" + }, + { + "content": "Nobody made a greater mistake than he who did nothing because he could do only a little.", + "author": "Edmund Burke" + }, + { + "content": "All serious daring starts from within.", + "author": "Harriet Beecher Stowe" + }, + { + "content": "Trouble is only opportunity in work clothes.", + "author": "Henry J. Kaiser" + }, + { + "content": "Freedom is what you do with what's been done to you.", + "author": "Jean-Paul Sartre" + }, + { + "content": "Love is the flower you've got to let grow.", + "author": "John Lennon" + }, + { + "content": "Quality is never an accident; it is always the result of intelligent effort.", + "author": "John Ruskin" + }, + { + "content": "All that is necessary is to accept the impossible, do without the indispensable, and bear the intolerable.", + "author": "Kathleen Norris" + }, + { + "content": "Everything that exists is in a manner the seed of that which will be.", + "author": "Marcus Aurelius" + }, + { + "content": "Waste no more time arguing about what a good man should be. Be one.", + "author": "Marcus Aurelius" + }, + { + "content": "We shall never know all the good that a simple smile can do.", + "author": "Mother Teresa" + }, + { + "content": "Fear not for the future, weep not for the past.", + "author": "Percy Bysshe Shelley" + }, + { + "content": "The best way to pay for a lovely moment is to enjoy it.", + "author": "Richard Bach" + }, + { + "content": "The only Zen you find on the tops of mountains is the Zen you bring up there.", + "author": "Robert M. Pirsig" + }, + { + "content": "Everyone has been made for some particular work, and the desire for that work has been put in every heart.", + "author": "Rumi" + }, + { + "content": "Memory is the mother of all wisdom.", + "author": "Samuel Johnson" + }, + { + "content": "Can you imagine what I would do if I could do all I can?", + "author": "Sun Tzu" + }, + { + "content": "Life is the flower for which love is the honey.", + "author": "Victor Hugo" + }, + { + "content": "Courage is what it takes to stand up and speak; courage is also what it takes to sit down and listen.", + "author": "Winston Churchill" + }, + { + "content": "Never, never, never give up.", + "author": "Winston Churchill" + }, + { + "content": "Consult not your fears but your hopes and your dreams. Think not about your frustrations, but about your unfulfilled potential. Concern yourself not with what you tried and failed in, but with what it is still possible for you to do.", + "author": "Pope John XXIII" + }, + { + "content": "The key is to keep company only with people who uplift you, whose presence calls forth your best.", + "author": "Epictetus" + }, + { + "content": "It's the little details that are vital. Little things make big things happen.", + "author": "John Wooden" + }, + { + "content": "If you don't know where you are going, any road will get you there.", + "author": "Lewis Carroll" + }, + { + "content": "You can only learn so much from books. You can only learn so much from education. Ultimately, it is the wisdom of God that will carry you through in the toughest situations of life.", + "author": "Ravi Zacharias" + }, + { + "content": "Habit, if not resisted, soon becomes necessity.", + "author": "Augustine of Hippo" + }, + { + "content": "A youth, when at home, should be filial and, abroad, respectful to his elders. He should be earnest and truthful. He should overflow in love to all and cultivate the friendship of the good. When he has time and opportunity, after the performance of these things, he should employ them in polite studies.", + "author": "Confucius" + }, + { + "content": "However rare true love may be, it is less so than true friendship.", + "author": "François de La Rochefoucauld" + }, + { + "content": "True friendship is like sound health; the value of it is seldom known until it is lost.", + "author": "Charles Caleb Colton" + }, + { + "content": "Neatness begets order; but from order to taste there is the same difference as from taste to genius, or from love to friendship.", + "author": "Johann Kaspar Lavater" + }, + { + "content": "When I dare to be powerful, to use my strength in the service of my vision, then it becomes less and less important whether I am afraid.", + "author": "Audre Lorde" + }, + { + "content": "Take no thought of who is right or wrong or who is better than. Be not for or against.", + "author": "Bruce Lee" + }, + { + "content": "What you do not want done to yourself, do not do to others.", + "author": "Confucius" + }, + { + "content": "When you see a man of worth, think of how you may emulate him. When you see one who is unworthy, examine yourself.", + "author": "Confucius" + }, + { + "content": "Most of the important things in the world have been accomplished by people who have kept on trying when there seemed to be no hope at all.", + "author": "Dale Carnegie" + }, + { + "content": "A successful person is one who can lay a firm foundation with the bricks that others throw at him or her.", + "author": "David Brinkley" + }, + { + "content": "You must do the things you think you cannot do.", + "author": "Eleanor Roosevelt" + }, + { + "content": "Three things in human life are important. The first is to be kind. The second is to be kind. The third is to be kind.", + "author": "Henry James" + }, + { + "content": "Be less curious about people and more curious about ideas.", + "author": "Marie Curie" + }, + { + "content": "Happiness is as a butterfly which, when pursued, is always beyond our grasp, but which if you will sit down quietly, may alight upon you.", + "author": "Nathaniel Hawthorne" + }, + { + "content": "By nature, man hates change; seldom will he quit his old home till it has actually fallen around his ears.", + "author": "Thomas Carlyle" + }, + { + "content": "Minds are like parachutes. They only function when open.", + "author": "Thomas Dewar" + }, + { + "content": "Meditation is the dissolution of thoughts in eternal awareness or Pure consciousness without objectification, knowing without thinking, merging finitude in infinity.", + "author": "Voltaire" + }, + { + "content": "I can't imagine a person becoming a success who doesn't give this game of life everything he's got.", + "author": "Walter Cronkite" + }, + { + "content": "What you get by achieving your goals is not as important as what you become by achieving your goals.", + "author": "Zig Ziglar" + }, + { + "content": "Adopt the pace of nature: her secret is patience.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "The only true wisdom is in knowing you know nothing.", + "author": "Isocrates" + }, + { + "content": "Nature and books belong to the eyes that see them.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "When written in Chinese, the word 'crisis' is composed of two characters. One represents danger and the other represents opportunity.", + "author": "John F. Kennedy" + }, + { + "content": "Science investigates; religion interprets. Science gives man knowledge which is power; religion gives man wisdom which is control.", + "author": "Martin Luther King Jr." + }, + { + "content": "Be true to yourself, help others, make each day your masterpiece, make friendship a fine art, drink deeply from good books - especially the Bible, build a shelter against a rainy day, give thanks for your blessings and pray for guidance every day.", + "author": "John Wooden" + }, + { + "content": "A friend is someone who gives you total freedom to be yourself.", + "author": "Jim Morrison" + }, + { + "content": "I don't need a friend who changes when I change and who nods when I nod; my shadow does that much better.", + "author": "Plutarch" + }, + { + "content": "Appreciation is the highest form of prayer, for it acknowledges the presence of good wherever you shine the light of your thankful thoughts.", + "author": "Alan Cohen" + }, + { + "content": "Speak when you are angry, and you will make the best speech you will ever regret.", + "author": "Ambrose Bierce" + }, + { + "content": "It all depends on how we look at things, and not how they are in themselves.", + "author": "Carl Jung" + }, + { + "content": "Happiness does not come about only due to external circumstances; it mainly derives from inner attitudes.", + "author": "Dalai Lama" + }, + { + "content": "Be your own hero, it's cheaper than a movie ticket.", + "author": "Doug Horton" + }, + { + "content": "If a man does his best, what else is there?", + "author": "George S. Patton" + }, + { + "content": "It's not what you look at that matters, it's what you see.", + "author": "Henry David Thoreau" + }, + { + "content": "You won't skid if you stay in a rut.", + "author": "Kin Hubbard" + }, + { + "content": "Doing nothing is better than being busy doing nothing.", + "author": "Laozi" + }, + { + "content": "Great acts are made up of small deeds.", + "author": "Laozi" + }, + { + "content": "All achievements, all earned riches, have their beginning in an idea.", + "author": "Napoleon Hill" + }, + { + "content": "Anybody can make history. Only a great man can write it.", + "author": "Oscar Wilde" + }, + { + "content": "Knowledge has three degrees: opinion, science, illumination. The means or instrument of the first is sense; of the second, dialectic; of the third, intuition.", + "author": "Plotinus" + }, + { + "content": "What the caterpillar calls the end of the world, the master calls a butterfly.", + "author": "Richard Bach" + }, + { + "content": "It requires wisdom to understand wisdom: the music is nothing if the audience is deaf.", + "author": "Walter Lippmann" + }, + { + "content": "Knowledge is proud that it knows so much; wisdom is humble that it knows no more.", + "author": "William Cowper" + }, + { + "content": "So much technology, so little talent.", + "author": "Vernor Vinge" + }, + { + "content": "I define friendship as a bond that transcends all barriers. When you are ready to expect anything and everything from friends, good, bad or ugly... that's what I call true friendship.", + "author": "Harbhajan Singh" + }, + { + "content": "It is not a lack of love, but a lack of friendship that makes unhappy marriages.", + "author": "Friedrich Nietzsche" + }, + { + "content": "A man's growth is seen in the successive choirs of his friends", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Never make friends with people who are above or below you in status. Such friendships will never give you any happiness.", + "author": "Chanakya" + }, + { + "content": "Be slow in choosing a friend, slower in changing.", + "author": "Benjamin Franklin" + }, + { + "content": "Friendship is a strong and habitual inclination in two persons to promote the good and happiness of one another.", + "author": "Eustace Budgell" + }, + { + "content": "Marriage: A friendship recognized by the police.", + "author": "Robert Louis Stevenson" + }, + { + "content": "What is necessary to change a person is to change his awareness of himself.", + "author": "Abraham Maslow" + }, + { + "content": "Peace cannot be kept by force. It can only be achieved by understanding.", + "author": "Albert Einstein" + }, + { + "content": "If you can't explain it simply, you don't understand it well enough.", + "author": "Albert Einstein" + }, + { + "content": "The first step to getting the things you want out of life is this: decide what you want.", + "author": "Ben Stein" + }, + { + "content": "Happiness comes when your work and words are of benefit to yourself and others.", + "author": "Buddha" + }, + { + "content": "Thousands of candles can be lighted from a single candle, and the life of the candle will not be shortened. Happiness never decreases by being shared.", + "author": "Buddha" + }, + { + "content": "An idea that is developed and put into action is more important than an idea that exists only as an idea.", + "author": "Buddha" + }, + { + "content": "How many cares one loses when one decides not to be something but to be someone.", + "author": "Coco Chanel" + }, + { + "content": "Human beings, who are almost unique in having the ability to learn from the experience of others, are also remarkable for their apparent disinclination to do so.", + "author": "Douglas Adams" + }, + { + "content": "I cannot give you the formula for success, but I can give you the formula for failure: which is: Try to please everybody.", + "author": "Herbert Bayard Swope" + }, + { + "content": "Sadness flies away on the wings of time.", + "author": "Jean de La Fontaine" + }, + { + "content": "There are two kinds of failures: those who thought and never did, and those who did and never thought.", + "author": "Laurence J. Peter" + }, + { + "content": "Do not be too timid and squeamish about your reactions. All life is an experiment. The more experiments you make the better.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Only those who dare to fail greatly can ever achieve greatly.", + "author": "Robert F. Kennedy" + }, + { + "content": "Change your life today. Don't gamble on the future, act now, without delay.", + "author": "Simone de Beauvoir" + }, + { + "content": "Independence is happiness.", + "author": "Susan B. Anthony" + }, + { + "content": "There is nothing on this earth more to be prized than true friendship.", + "author": "Thomas Aquinas" + }, + { + "content": "What we think determines what happens to us, so if we want to change our lives, we need to stretch our minds.", + "author": "Wayne Dyer" + }, + { + "content": "Look up at the stars and not down at your feet. Try to make sense of what you see, and wonder about what makes the universe exist. Be curious.", + "author": "Stephen Hawking" + }, + { + "content": "People usually compare the computer to the head of the human being. I would say that hardware is the bone of the head, the skull. The semiconductor is the brain within the head. The software is the wisdom. And data is the knowledge.", + "author": "Masayoshi Son" + }, + { + "content": "The doors of wisdom are never shut.", + "author": "Benjamin Franklin" + }, + { + "content": "The strong bond of friendship is not always a balanced equation; friendship is not always about giving and taking in equal shares. Instead, friendship is grounded in a feeling that you know exactly who will be there for you when you need something, no matter what or when.", + "author": "Simon Sinek" + }, + { + "content": "Rare as is true love, true friendship is rarer.", + "author": "Jean de La Fontaine" + }, + { + "content": "When the solution is simple, God is answering.", + "author": "Albert Einstein" + }, + { + "content": "Blessed is the man who expects nothing, for he shall never be disappointed.", + "author": "Alexander Pope" + }, + { + "content": "The art of progress is to preserve order amid change, and to preserve change amid order.", + "author": "Alfred North Whitehead" + }, + { + "content": "Kind words do not cost much. Yet they accomplish much.", + "author": "Blaise Pascal" + }, + { + "content": "You can only grow if you're willing to feel awkward and uncomfortable when you try something new.", + "author": "Brian Tracy" + }, + { + "content": "Don't leave a stone unturned. It's always something, to know you have done the most you could.", + "author": "Charles Dickens" + }, + { + "content": "It does not matter how slowly you go as long as you do not stop.", + "author": "Confucius" + }, + { + "content": "Fine words and an insinuating appearance are seldom associated with true virtue", + "author": "Confucius" + }, + { + "content": "The superior man acts before he speaks, and afterwards speaks according to his action.", + "author": "Confucius" + }, + { + "content": "Reality does not conform to the ideal but confirms it.", + "author": "Gustave Flaubert" + }, + { + "content": "Things do not change; we change.", + "author": "Henry David Thoreau" + }, + { + "content": "A thing well said will be wit in all languages.", + "author": "John Dryden" + }, + { + "content": "I have an everyday religion that works for me. Love yourself first, and everything else falls into line.", + "author": "Lucille Ball" + }, + { + "content": "Decision is a risk rooted in the courage of being free.", + "author": "Paul Tillich" + }, + { + "content": "To make no mistakes is not in the power of man; but from their errors and mistakes the wise and good learn wisdom for the future.", + "author": "Plutarch" + }, + { + "_id": "z-hDjBf4spF-", + "content": "Make the most of yourself, for that is all there is of you.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Peace is not something you wish for. It's something you make, something you do, something you are, and something you give away.", + "author": "Robert Fulghum" + }, + { + "content": "We can change our lives. We can do, have, and be exactly what we wish.", + "author": "Tony Robbins" + }, + { + "content": "Your talent is God's gift to you. What you do with it is your gift back to God.", + "author": "Leo Buscaglia" + }, + { + "content": "True wisdom comes to each of us when we realize how little we understand about life, ourselves, and the world around us.", + "author": "Isocrates" + }, + { + "content": "Technological progress has merely provided us with more efficient means for going backwards.", + "author": "Aldous Huxley" + }, + { + "_id": "J-47k8g-i", + "content": "Love is a friendship set to music.", + "author": "Joseph Campbell" + }, + { + "author": "Woody Allen", + "content": "Interestingly, according to modern astronomers, space is finite. This is a very comforting thought-- particularly for people who can never remember where they have left things." + }, + { + "content": "All men have a sweetness in their life. That is what helps them go on. It is towards that they turn when they feel too worn out.", + "author": "Albert Camus" + }, + { + "content": "You will never be happy if you continue to search for what happiness consists of. You will never live if you are looking for the meaning of life.", + "author": "Albert Camus" + }, + { + "content": "Life is a gift, and it offers us the privilege, opportunity, and responsibility to give something back by becoming more", + "author": "Tony Robbins" + }, + { + "content": "Whatever we expect with confidence becomes our own self-fulfilling prophecy.", + "author": "Brian Tracy" + }, + { + "content": "The winds and waves are always on the side of the ablest navigators.", + "author": "Edward Gibbon" + }, + { + "content": "The wisest men follow their own direction.", + "author": "Euripides" + }, + { + "content": "When you reach the end of your rope, tie a knot in it and hang on.", + "author": "Franklin D. Roosevelt" + }, + { + "content": "He who talks more is sooner exhausted.", + "author": "Laozi" + }, + { + "content": "Very little is needed to make a happy life; it is all within yourself, in your way of thinking.", + "author": "Marcus Aurelius" + }, + { + "content": "If you want a thing done well, do it yourself.", + "author": "Napoleon" + }, + { + "content": "The only journey is the one within.", + "author": "Rainer Maria Rilke" + }, + { + "content": "Good thoughts are no better than good dreams, unless they be executed.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Time changes everything except something within us which is always surprised by change.", + "author": "Thomas Hardy" + }, + { + "content": "The way we communicate with others and with ourselves ultimately determines the quality of our lives.", + "author": "Tony Robbins" + }, + { + "content": "When you discover your mission, you will feel its demand. It will fill you with enthusiasm and a burning desire to get to work on it.", + "author": "W. Clement Stone" + }, + { + "content": "Be great in act, as you have been in thought.", + "author": "William Shakespeare" + }, + { + "content": "I know where I'm going and I know the truth, and I don't have to be what you want me to be. I'm free to be what I want.", + "author": "Muhammad Ali" + }, + { + "content": "The older I get the more wisdom I find in the ancient rule of taking first things first. A process which often reduces the most complex human problem to a manageable proportion.", + "author": "Dwight D. Eisenhower" + }, + { + "content": "Between saying and doing, many a pair of shoes is worn out.", + "author": "Iris Murdoch" + }, + { + "content": "The real problem is not whether machines think but whether men do.", + "author": "B. F. Skinner" + }, + { + "content": "True happiness arises, in the first place, from the enjoyment of oneself, and in the next, from the friendship and conversation of a few select companions.", + "author": "Joseph Addison" + }, + { + "content": "Our most intimate friend is not he to whom we show the worst, but the best of our nature.", + "author": "Nathaniel Hawthorne" + }, + { + "content": "There is no friendship, no love, like that of the parent for the child.", + "author": "Henry Ward Beecher" + }, + { + "content": "Always bear in mind that your own resolution to succeed is more important than any one thing.", + "author": "Abraham Lincoln" + }, + { + "content": "Once we accept our limits, we go beyond them.", + "author": "Albert Einstein" + }, + { + "content": "Feeling and longing are the motive forces behind all human endeavor and human creations.", + "author": "Albert Einstein" + }, + { + "content": "We all live with the objective of being happy; our lives are all different and yet the same.", + "author": "Anne Frank" + }, + { + "content": "There is only one success: to be able to spend your life in your own way.", + "author": "Christopher Morley" + }, + { + "content": "When deeds and words are in accord, the whole world is transformed.", + "author": "Zhuang Zhou" + }, + { + "content": "If you are going to achieve excellence in big things, you develop the habit in little matters. Excellence is not an exception; it is a prevailing attitude.", + "author": "Colin Powell" + }, + { + "content": "Until you make peace with who you are, you'll never be content with what you have.", + "author": "Doris Mortman" + }, + { + "content": "Do what you can. Want what you have. Be who you are.", + "author": "Forrest Church" + }, + { + "content": "If you think you can, you can. And if you think you can't, you're right.", + "author": "Henry Ford" + }, + { + "content": "Silence is a source of great strength.", + "author": "Laozi" + }, + { + "content": "All difficult things have their origin in that which is easy, and great things in that which is small.", + "author": "Laozi" + }, + { + "content": "Always be smarter than the people who hire you.", + "author": "Lena Horne" + }, + { + "content": "Although there may be tragedy in your life, there's always a possibility to triumph. It doesn't matter who you are, where you come from. The ability to triumph begins with you. Always.", + "author": "Oprah Winfrey" + }, + { + "content": "Most of the shadows of life are caused by standing in our own sunshine.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "The mark of your ignorance is the depth of your belief in injustice and tragedy. What the caterpillar calls the end of the world, the Master calls the butterfly.", + "author": "Richard Bach" + }, + { + "content": "All perceiving is also thinking, all reasoning is also intuition, all observation is also invention.", + "author": "Rudolf Arnheim" + }, + { + "content": "No one has a finer command of language than the person who keeps his mouth shut.", + "author": "Sam Rayburn" + }, + { + "content": "It is impossible to escape the impression that people commonly use false standards of measurement — that they seek power, success and wealth for themselves and admire them in others, and that they underestimate what is of true value in life.", + "author": "Sigmund Freud" + }, + { + "content": "It is time to remember that old wisdom our soldiers will never forget: that whether we are black or brown or white, we all bleed the same red blood of patriots, we all enjoy the same glorious freedoms, and we all salute the same great American Flag.", + "author": "Donald Trump" + }, + { + "content": "In dwelling, live close to the ground. In thinking, keep to the simple. In conflict, be fair and generous. In governing, don't try to control. In work, do what you enjoy. In family life, be completely present.", + "author": "Laozi" + }, + { + "content": "You've got to go out on a limb sometimes because that's where the fruit is.", + "author": "Will Rogers" + }, + { + "content": "Always be a first-rate version of yourself, instead of a second-rate version of somebody else.", + "author": "Judy Garland" + }, + { + "content": "Cleverness is not wisdom.", + "author": "Euripides" + }, + { + "content": "It is better to travel well than to arrive.", + "author": "Buddha" + }, + { + "content": "Nothing happens unless first we dream.", + "author": "Carl Sandburg" + }, + { + "content": "Every great advance in science has issued from a new audacity of the imagination.", + "author": "John Dewey" + }, + { + "content": "He who knows that enough is enough will always have enough.", + "author": "Laozi" + }, + { + "content": "Know that although in the eternal scheme of things you are small, you are also unique and irreplaceable, as are all your fellow humans everywhere in the world.", + "author": "Margaret Laurence" + }, + { + "content": "Change your thoughts and you change your world.", + "author": "Norman Vincent Peale" + }, + { + "content": "Always seek out the seed of triumph in every adversity.", + "author": "Og Mandino" + }, + { + "content": "Something opens our wings. Something makes boredom and hurt disappear. Someone fills the cup in front of us: We taste only sacredness.", + "author": "Rumi" + }, + { + "content": "We are Divine enough to ask and we are important enough to receive.", + "author": "Wayne Dyer" + }, + { + "content": "Just as treasures are uncovered from the earth, so virtue appears from good deeds, and wisdom appears from a pure and peaceful mind. To walk safely through the maze of human life, one needs the light of wisdom and the guidance of virtue.", + "author": "Buddha" + }, + { + "content": "Avoid having your ego so close to your position that when your position falls, your ego goes with it.", + "author": "Colin Powell" + }, + { + "content": "Wise men make more opportunities than they find.", + "author": "Francis Bacon" + }, + { + "content": "The key to wisdom is this - constant and frequent questioning, for by doubting we are led to question and by questioning we arrive at the truth.", + "author": "Peter Abelard" + }, + { + "content": "Vanity can easily overtake wisdom. It usually overtakes common sense.", + "author": "Julian Casablancas" + }, + { + "content": "Technology… the knack of so arranging the world that we don't have to experience it.", + "author": "Max Frisch" + }, + { + "content": "Be slow to fall into friendship; but when thou art in, continue firm and constant.", + "author": "Isocrates" + }, + { + "content": "One friend in a lifetime is much; two are many; three are hardly possible. Friendship needs a certain parallelism of life, a community of thought, a rivalry of aim.", + "author": "Brooks Adams" + }, + { + "content": "He has no enemies, but is intensely disliked by his friends.", + "author": "Oscar Wilde" + }, + { + "content": "If you live to be a hundred, I want to live to be a hundred minus one day, so I never have to live without you.", + "author": "A. A. Milne" + }, + { + "content": "A man should look for what is, and not for what he thinks should be.", + "author": "Albert Einstein" + }, + { + "content": "It is easier to live through someone else than to become complete yourself.", + "author": "Betty Friedan" + }, + { + "content": "To want to be what one can be is purpose in life.", + "author": "Cynthia Ozick" + }, + { + "content": "Compassion and happiness are not a sign of weakness but a sign of strength.", + "author": "Dalai Lama" + }, + { + "content": "Difficulties are things that show a person what they are.", + "author": "Epictetus" + }, + { + "content": "Practice yourself, for heaven's sake in little things, and then proceed to greater.", + "author": "Epictetus" + }, + { + "content": "A true friend is the most precious of all possessions and the one we take the least thought about acquiring.", + "author": "François de La Rochefoucauld" + }, + { + "content": "Think like a man of action; act like a man of thought.", + "author": "Henri Bergson" + }, + { + "content": "A leader or a man of action in a crisis almost always acts subconsciously and then thinks of the reasons for his action.", + "author": "Jawaharlal Nehru" + }, + { + "content": "Patience and perseverance have a magical effect before which difficulties disappear and obstacles vanish.", + "author": "John Adams" + }, + { + "content": "Yeah, we all shine on, like the moon, and the stars, and the sun.", + "author": "John Lennon" + }, + { + "content": "Intuition will tell the thinking mind where to look next.", + "author": "Jonas Salk" + }, + { + "content": "A little knowledge that acts is worth infinitely more than much knowledge that is idle.", + "author": "Kahlil Gibran" + }, + { + "content": "By letting it go it all gets done. The world is won by those who let it go. But when you try and try. The world is beyond the winning.", + "author": "Laozi" + }, + { + "content": "Bodily exercise, when compulsory, does no harm to the body; but knowledge which is acquired under compulsion obtains no hold on the mind.", + "author": "Plato" + }, + { + "_id": "tpmH-IxHDP-I", + "content": "Strong people make as many mistakes as weak people. Difference is that strong people admit their mistakes, laugh at them, learn from them. That is how they become strong.", + "author": "Richard Needham" + }, + { + "content": "The more light you allow within you, the brighter the world you live in will be.", + "author": "Shakti Gawain" + }, + { + "content": "Numberless are the worlds wonders, but none more wonderful than man.", + "author": "Sophocles" + }, + { + "content": "Opportunity is missed by most because it is dressed in overalls and looks like work.", + "author": "Thomas Edison" + }, + { + "content": "Fortune favors the brave.", + "author": "Virgil" + }, + { + "content": "Anything you really want, you can attain, if you really go after it.", + "author": "Wayne Dyer" + }, + { + "content": "Knowledge is of no value unless you put it into practice.", + "author": "Anton Chekhov" + }, + { + "content": "With pride, there are many curses. With humility, there come many blessings.", + "author": "Ezra Taft Benson" + }, + { + "content": "Never find fault with the absent.", + "author": "Alexander Pope" + }, + { + "content": "In action a great heart is the chief qualification. In work, a great head.", + "author": "Arthur Schopenhauer" + }, + { + "content": "Programs must be written for people to read, and only incidentally for machines to execute.", + "author": "Hal Abelson" + }, + { + "content": "Share your smile with the world. It's a symbol of friendship and peace.", + "author": "Christie Brinkley" + }, + { + "content": "I have learned that to be with those I like is enough.", + "author": "Walt Whitman" + }, + { + "content": "I think somehow, we learn who we really are and then live with that decision.", + "author": "Eleanor Roosevelt" + }, + { + "content": "Wherever a man may happen to turn, whatever a man may undertake, he will always end up by returning to the path which nature has marked out for him.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "Time you enjoyed wasting was not wasted.", + "author": "John Lennon" + }, + { + "content": "I believe in one thing only, the power of human will.", + "author": "Joseph Stalin" + }, + { + "content": "He who is contented is rich.", + "author": "Laozi" + }, + { + "content": "He who lives in harmony with himself lives in harmony with the universe.", + "author": "Marcus Aurelius" + }, + { + "content": "You really can change the world if you care enough.", + "author": "Marian Wright Edelman" + }, + { + "content": "The simplest things are often the truest.", + "author": "Richard Bach" + }, + { + "content": "Don't turn away from possible futures before you're certain you don't have anything to learn from them.", + "author": "Richard Bach" + }, + { + "content": "The pessimist complains about the wind; the optimist expects it to change; the realist adjusts the sails.", + "author": "William Arthur Ward" + }, + { + "content": "The price of greatness is responsibility.", + "author": "Winston Churchill" + }, + { + "content": "Neither a lofty degree of intelligence nor imagination nor both together go to the making of genius. Love, love, love, that is the soul of genius.", + "author": "Wolfgang Amadeus Mozart" + }, + { + "content": "He who learns must suffer. And even in our sleep pain that cannot forget falls drop by drop upon the heart, and in our own despair, against our will, comes wisdom to us by the awful grace of God.", + "author": "Aeschylus" + }, + { + "content": "The wisdom of the wise, and the experience of ages, may be preserved by quotation.", + "author": "Isaac D'Israeli" + }, + { + "content": "You always have two choices: your commitment versus your fear.", + "author": "Sammy Davis Jr." + }, + { + "content": "Friendship improves happiness and abates misery, by the doubling of our joy and the dividing of our grief.", + "author": "Cicero" + }, + { + "content": "Let there be no purpose in friendship save the deepening of the spirit.", + "author": "Kahlil Gibran" + }, + { + "content": "I believe that a simple and unassuming manner of life is best for everyone, best both for the body and the mind.", + "author": "Albert Einstein" + }, + { + "content": "If one way be better than another, that you may be sure is nature's way.", + "author": "Aristotle" + }, + { + "content": "Yesterday I dared to struggle. Today I dare to win.", + "author": "Bernadette Devlin" + }, + { + "content": "I will not be concerned at other men's not knowing me; I will be concerned at my own want of ability.", + "author": "Confucius" + }, + { + "content": "Real success is finding your lifework in the work that you love.", + "author": "David McCullough" + }, + { + "content": "Happiness cannot be travelled to, owned, earned, worn or consumed. Happiness is the spiritual experience of living every minute with love, grace and gratitude.", + "author": "Denis Waitley" + }, + { + "content": "It is not uncommon for people to spend their whole life waiting to start living.", + "author": "Eckhart Tolle" + }, + { + "content": "Nature gave us one tongue and two ears so we could hear twice as much as we speak.", + "author": "Epictetus" + }, + { + "content": "It is very easy to forgive others their mistakes; it takes more grit to forgive them for having witnessed your own.", + "author": "Jessamyn West" + }, + { + "content": "Love yourself first and everything else falls into line. You really have to love yourself to get anything done in this world.", + "author": "Lucille Ball" + }, + { + "content": "The weak can never forgive. Forgiveness is the attribute of the strong.", + "author": "Mahatma Gandhi" + }, + { + "content": "If you can't feed a hundred people, then feed just one.", + "author": "Mother Teresa" + }, + { + "content": "Love is the master key that opens the gates of happiness.", + "author": "Oliver Wendell Holmes Jr." + }, + { + "content": "Follow effective action with quiet reflection. From the quiet reflection will come even more effective action.", + "author": "Peter Drucker" + }, + { + "content": "You have to believe in yourself.", + "author": "Sun Tzu" + }, + { + "content": "The path to success is to take massive, determined action.", + "author": "Tony Robbins" + }, + { + "content": "We never live; we are always in the expectation of living.", + "author": "Voltaire" + }, + { + "content": "Hope arouses, as nothing else can arouse, a passion for the possible.", + "author": "William Sloane Coffin" + }, + { + "content": "Be Impeccable with Your Word. Speak with integrity. Say only what you mean. Avoid using the word to speak against yourself or to gossip about others. Use the power of your word in the direction of truth and love.", + "author": "Don Miguel Ruiz" + }, + { + "content": "The time to repair the roof is when the sun is shining.", + "author": "John F. Kennedy" + }, + { + "content": "Wise kings generally have wise counselors; and he must be a wise man himself who is capable of distinguishing one.", + "author": "Diogenes" + }, + { + "content": "I know that inner wisdom is more precious than wealth. The more you spend it, the more you gain.", + "author": "Oprah Winfrey" + }, + { + "content": "The extreme limit of wisdom, that's what the public calls madness.", + "author": "Jean Cocteau" + }, + { + "content": "Life has no blessing like a prudent friend.", + "author": "Euripides" + }, + { + "content": "Great ideas often receive violent opposition from mediocre minds.", + "author": "Albert Einstein" + }, + { + "content": "Your worst enemy cannot harm you as much as your own unguarded thoughts.", + "author": "Buddha" + }, + { + "content": "Your vision will become clear only when you look into your heart. Who looks outside, dreams. Who looks inside, awakens.", + "author": "Carl Jung" + }, + { + "content": "Happiness is not something ready-made. It comes from your own actions.", + "author": "Dalai Lama" + }, + { + "content": "Until you make peace with who you are, you will never be content with what you have.", + "author": "Doris Mortman" + }, + { + "content": "There is nothing permanent except change.", + "author": "Heraclitus" + }, + { + "content": "Believe deep down in your heart that you're destined to do great things.", + "author": "Joe Paterno" + }, + { + "content": "You're not obligated to win. You're obligated to keep trying to do the best you can every day.", + "author": "Marian Wright Edelman" + }, + { + "content": "To fly, we have to have resistance.", + "author": "Maya Lin" + }, + { + "content": "A man may fulfil the object of his existence by asking a question he cannot answer and attempting a task he cannot achieve.", + "author": "Oliver Wendell Holmes Jr." + }, + { + "content": "Write your plans in pencil and give God the eraser.", + "author": "Paulo Coelho" + }, + { + "_id": "hv83OL-O-fTP", + "content": "It is only when the mind and character slumber that the dress can be seen.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "The first requisite for success is the ability to apply your physical and mental energies to one problem incessantly without growing weary.", + "author": "Thomas Edison" + }, + { + "content": "We can only be said to be alive in those moments when our hearts are conscious of our treasures.", + "author": "Thornton Wilder" + }, + { + "content": "Your mind will answer most questions if you learn to relax and wait for the answer.", + "author": "William Burroughs" + }, + { + "content": "To climb steep hills requires a slow pace at first.", + "author": "William Shakespeare" + }, + { + "content": "And I love that even in the toughest moments, when we're all sweating it - when we're worried that the bill won't pass, and it seems like all is lost - Barack never lets himself get distracted by the chatter and the noise. Just like his grandmother, he just keeps getting up and moving forward... with patience and wisdom, and courage and grace.", + "author": "Michelle Obama" + }, + { + "content": "Always keep an open mind and a compassionate heart.", + "author": "Phil Jackson" + }, + { + "content": "There are three classes of men; lovers of wisdom, lovers of honor, and lovers of gain.", + "author": "Plato" + }, + { + "content": "Each friend represents a world in us, a world not born until they arrive, and it is only by this meeting that a new world is born.", + "author": "Anaïs Nin" + }, + { + "content": "Acquaintances we meet, enjoy, and can easily leave behind; but friendship grows deep roots.", + "author": "H. Jackson Brown Jr." + }, + { + "content": "I want my friend to miss me as long as I miss him.", + "author": "Augustine of Hippo" + }, + { + "content": "You have to do your own growing no matter how tall your grandfather was.", + "author": "Abraham Lincoln" + }, + { + "content": "Learn from yesterday, live for today, hope for tomorrow.", + "author": "Albert Einstein" + }, + { + "content": "To accomplish great things, we must not only act, but also dream; not only plan, but also believe.", + "author": "Anatole France" + }, + { + "content": "We know the truth, not only by the reason, but by the heart.", + "author": "Blaise Pascal" + }, + { + "content": "Do not dwell in the past, do not dream of the future, concentrate the mind on the present moment.", + "author": "Buddha" + }, + { + "content": "I endeavor to be wise when I cannot be merry, easy when I cannot be glad, content with what cannot be mended and patient when there is no redress.", + "author": "Elizabeth Montagu" + }, + { + "content": "Our kindness may be the most persuasive argument for that which we believe.", + "author": "Gordon Hinckley" + }, + { + "content": "The smallest flower is a thought, a life answering to some feature of the Great Whole, of whom they have a persistent intuition.", + "author": "Honoré de Balzac" + }, + { + "content": "We never understand how little we need in this world until we know the loss of it.", + "author": "J. M. Barrie" + }, + { + "content": "If you have knowledge, let others light their candles in it.", + "author": "Margaret Fuller" + }, + { + "content": "If you don't like something, change it. If you can't change it, change your attitude.", + "author": "Maya Angelou" + }, + { + "content": "Always do your best. What you plant now, you will harvest later.", + "author": "Og Mandino" + }, + { + "content": "Meaning is not what you start with but what you end up with.", + "author": "Peter Elbow" + }, + { + "content": "To fly as fast as thought, you must begin by knowing that you have already arrived.", + "author": "Richard Bach" + }, + { + "_id": "lcNcja--RmXG", + "content": "There is no scarcity of opportunity to make a living at what you love; there's only scarcity of resolve to make it happen.", + "author": "Wayne Dyer" + }, + { + "content": "When in doubt, don't.", + "author": "Benjamin Franklin" + }, + { + "content": "As you walk in God's divine wisdom, you will surely begin to see a greater measure of victory and good success in your life.", + "author": "Joseph Prince" + }, + { + "content": "Wisdom is the power to put our time and our knowledge to the proper use.", + "author": "Thomas J. Watson" + }, + { + "content": "Even youngish men can acquire wisdom as time goes by.", + "author": "John Bercow" + }, + { + "content": "A friend is one who knows you and loves you just the same.", + "author": "Elbert Hubbard" + }, + { + "content": "No distance of place or lapse of time can lessen the friendship of those who are thoroughly persuaded of each other's worth.", + "author": "Robert Southey" + }, + { + "content": "Give me six hours to chop down a tree and I will spend the first four sharpening the axe.", + "author": "Abraham Lincoln" + }, + { + "content": "All our talents increase in the using, and every faculty, both good and bad, strengthen by exercise.", + "author": "Anne Brontë" + }, + { + "content": "The grand essentials of happiness are: something to do, something to love, and something to hope for.", + "author": "Alexander Chalmers" + }, + { + "content": "Do not mind anything that anyone tells you about anyone else. Judge everyone and everything for yourself.", + "author": "Henry James" + }, + { + "content": "Begin, be bold, and venture to be wise.", + "author": "Horace" + }, + { + "content": "To listen well is as powerful a means of communication and influence as to talk well.", + "author": "John Marshall" + }, + { + "content": "At the center of your being, you have the answer; you know who you are, and you know what you want.", + "author": "Laozi" + }, + { + "content": "Love isn't something you find. Love is something that finds you.", + "author": "Loretta Young" + }, + { + "content": "Our greatness lies not so much in being able to remake the world as being able to remake ourselves.", + "author": "Mahatma Gandhi" + }, + { + "content": "There are basically two types of people. People who accomplish things, and people who claim to have accomplished things. The first group is less crowded.", + "author": "Mark Twain" + }, + { + "content": "I don't believe in failure. It's not failure if you enjoyed the process.", + "author": "Oprah Winfrey" + }, + { + "content": "The pain passes, but the beauty remains.", + "author": "Pierre-Auguste Renoir" + }, + { + "content": "You are always free to change your mind and choose a different future, or a different past.", + "author": "Richard Bach" + }, + { + "content": "Sooner or later, those who win are those who think they can.", + "author": "Richard Bach" + }, + { + "content": "What is new in the world? Nothing. What is old in the world? Nothing. Everything has always been and will always be.", + "author": "Sai Baba" + }, + { + "content": "Never tell people how to do things. Tell them what to do and they will surprise you with their ingenuity.", + "author": "George S. Patton" + }, + { + "content": "People don't notice whether it's winter or summer when they're happy.", + "author": "Anton Chekhov" + }, + { + "content": "I am not the first Buddha who came upon Earth, nor shall I be the last. In due time, another Buddha will arise in the world - a Holy One, a supremely enlightened One, endowed with wisdom in conduct, auspicious, knowing the universe, an incomparable leader of men, a master of angels and mortals.", + "author": "Buddha" + }, + { + "content": "I had three chairs in my house; one for solitude, two for friendship, three for society.", + "author": "Henry David Thoreau" + }, + { + "content": "Friendship is also about liking a person for their failings, their weakness. It's also about mutual help, not about exploitation.", + "author": "Paul Theroux" + }, + { + "content": "It may happen sometimes that a long debate becomes the cause of a longer friendship. Commonly, those who dispute with one another at last agree.", + "author": "Elbert Hubbard" + }, + { + "content": "An optimist is a person who sees a green light everywhere, while the pessimist sees only the red spotlight... The truly wise person is color-blind.", + "author": "Albert Schweitzer" + }, + { + "content": "There are only two mistakes one can make along the road to truth; not going all the way, and not starting.", + "author": "Buddha" + }, + { + "content": "Every man is a volume if you know how to read him.", + "author": "William Ellery Channing" + }, + { + "content": "To be wrong is nothing unless you continue to remember it.", + "author": "Confucius" + }, + { + "content": "Love and compassion open our own inner life, reducing stress, distrust and loneliness.", + "author": "Dalai Lama" + }, + { + "content": "By going beyond your own problems and taking care of others, you gain inner strength, self-confidence, courage, and a greater sense of calm.", + "author": "Dalai Lama" + }, + { + "content": "The universe is transformation; our life is what our thoughts make it.", + "author": "Marcus Aurelius" + }, + { + "content": "If you accept the expectations of others, especially negative ones, then you never will change the outcome.", + "author": "Michael Jordan" + }, + { + "content": "If you want things to be different, perhaps the answer is to become different yourself.", + "author": "Norman Vincent Peale" + }, + { + "content": "Nothing is at last sacred but the integrity of your own mind.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Belief consists in accepting the affirmations of the soul; Unbelief, in denying them.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "It is not in the stars to hold our destiny but in ourselves.", + "author": "William Shakespeare" + }, + { + "content": "In every walk with nature, one receives far more than he seeks.", + "author": "John Muir" + }, + { + "content": "We should not judge people by their peak of excellence; but by the distance they have traveled from the point where they started.", + "author": "Henry Ward Beecher" + }, + { + "_id": "B76--SMLkD", + "content": "Excellence, then, is a state concerned with choice, lying in a mean, relative to us, this being determined by reason and in the way in which the man of practical wisdom would determine it.", + "author": "Aristotle" + }, + { + "content": "Technology made large populations possible; large populations now make technology indispensable.", + "author": "Joseph Wood Krutch" + }, + { + "content": "It is more shameful to distrust our friends than to be deceived by them.", + "author": "Confucius" + }, + { + "content": "Reality is merely an illusion, albeit a very persistent one.", + "author": "Albert Einstein" + }, + { + "content": "The greatest good you can do for another is not just share your riches but reveal to them their own.", + "author": "Benjamin Disraeli" + }, + { + "content": "Our passion is our strength.", + "author": "Billie Armstrong" + }, + { + "content": "No day in which you learn something is a complete loss.", + "author": "David Eddings" + }, + { + "content": "He that respects himself is safe from others; he wears a coat of mail that none can pierce.", + "author": "Henry Wadsworth Longfellow" + }, + { + "content": "Make it a rule of life never to regret and never to look back. Regret is an appalling waste of energy; you can't build on it; it's only for wallowing in.", + "author": "Katherine Mansfield" + }, + { + "content": "He who conquers others is strong; He who conquers himself is mighty.", + "author": "Laozi" + }, + { + "content": "Nothing in life is to be feared. It is only to be understood.", + "author": "Marie Curie" + }, + { + "content": "To do all that one is able to do, is to be a man; to do all that one would like to do, is to be a god.", + "author": "Napoleon" + }, + { + "content": "I will love the light for it shows me the way, yet I will endure the darkness because it shows me the stars.", + "author": "Og Mandino" + }, + { + "content": "Take rest; a field that has rested gives a bountiful crop.", + "author": "Ovid" + }, + { + "content": "Know how to listen, and you will profit even from those who talk badly.", + "author": "Plutarch" + }, + { + "content": "Life is not a problem to be solved, but a reality to be experienced.", + "author": "Søren Kierkegaard" + }, + { + "content": "To go against the dominant thinking of your friends, of most of the people you see every day, is perhaps the most difficult act of heroism you can perform.", + "author": "Theodore H. White" + }, + { + "content": "I have not failed. I've just found 10,000 ways that won't work.", + "author": "Thomas Edison" + }, + { + "content": "Just as much as we see in others, we have in ourselves.", + "author": "William Hazlitt" + }, + { + "content": "We know what we are but know not what we may be.", + "author": "William Shakespeare" + }, + { + "content": "As a technology, the book is like a hammer. That is to say, it is perfect: a tool ideally suited to its task. Hammers can be tweaked and varied but will never go obsolete. Even when builders pound nails by the thousand with pneumatic nail guns, every household needs a hammer.", + "author": "James Gleick" + }, + { + "content": "Friendship is almost always the union of a part of one mind with the part of another; people are friends in spots.", + "author": "George Santayana" + }, + { + "content": "The only real valuable thing is intuition.", + "author": "Albert Einstein" + }, + { + "content": "They say that time changes things, but you actually have to change them yourself.", + "author": "Andy Warhol" + }, + { + "content": "Remember that sometimes not getting what you want is a wonderful stroke of luck.", + "author": "Dalai Lama" + }, + { + "content": "Fear grows in darkness; if you think there's a bogeyman around, turn on the light.", + "author": "Dorothy Thompson" + }, + { + "content": "Freedom is the right to live as we wish.", + "author": "Epictetus" + }, + { + "content": "The only limit to our realization of tomorrow will be our doubts of today.", + "author": "Franklin D. Roosevelt" + }, + { + "content": "Let us resolve to be masters, not the victims, of our history, controlling our own destiny without giving way to blind suspicions and emotions.", + "author": "John F. Kennedy" + }, + { + "content": "If it is not right do not do it; if it is not true do not say it.", + "author": "Marcus Aurelius" + }, + { + "content": "The purpose of learning is growth, and our minds, unlike our bodies, can continue growing as we continue to live.", + "author": "Mortimer J. Adler" + }, + { + "content": "A goal is a dream with a deadline.", + "author": "Napoleon Hill" + }, + { + "content": "Do not waste yourself in rejection, nor bark against the bad, but chant the beauty of the good.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "When we feel love and kindness toward others, it not only makes others feel loved and cared for, but it helps us also to develop inner happiness and peace.", + "author": "Dalai Lama" + }, + { + "content": "Do not be embarrassed by your mistakes. Nothing can teach us better than our understanding of them. This is one of the best ways of self-education.", + "author": "Thomas Carlyle" + }, + { + "content": "We've got to have a dream if we are going to make a dream come true.", + "author": "Walt Disney" + }, + { + "content": "Discipline is the bridge between goals and accomplishment.", + "author": "Jim Rohn" + }, + { + "content": "Talent is God given. Be humble. Fame is man-given. Be grateful. Conceit is self-given. Be careful.", + "author": "John Wooden" + }, + { + "content": "Pain and foolishness lead to great bliss and complete knowledge, for Eternal Wisdom created nothing under the sun in vain.", + "author": "Kahlil Gibran" + }, + { + "content": "Everyone in the world ought to do the things for which he is specially adapted. It is the part of wisdom to recognize what each one of us is best fitted for, and it is the part of education to perfect and utilize such predispositions. Because education can direct and aid nature but can never transform her.", + "author": "Maria Montessori" + }, + { + "content": "Wisdom is nothing but a preparation of the soul, a capacity, a secret art of thinking, feeling and breathing thoughts of unity at every moment of life.", + "author": "Hermann Hesse" + }, + { + "content": "Wisdom alone is the science of other sciences.", + "author": "Plato" + }, + { + "content": "It is good even for old men to learn wisdom.", + "author": "Aeschylus" + }, + { + "content": "It has become appallingly obvious that our technology has exceeded our humanity.", + "author": "Albert Einstein" + }, + { + "content": "True friendship ought never to conceal what it thinks.", + "author": "Jerome" + }, + { + "content": "One's friends are that part of the human race with which one can be human.", + "author": "George Santayana" + }, + { + "content": "You learn to speak by speaking, to study by studying, to run by running, to work by working; in just the same way, you learn to love by loving.", + "author": "Anatole France" + }, + { + "content": "The energy of the mind is the essence of life.", + "author": "Aristotle" + }, + { + "content": "Chaos is inherent in all compounded things. Strive on with diligence.", + "author": "Buddha" + }, + { + "content": "I love my past. I love my present. I'm not ashamed of what I've had, and I'm not sad because I have it no longer.", + "author": "Colette" + }, + { + "content": "The person who lives life fully, glowing with life's energy, is the person who lives a successful life.", + "author": "Daisaku Ikeda" + }, + { + "content": "A dream is your creative vision for your life in the future. You must break out of your current comfort zone and become comfortable with the unfamiliar and the unknown.", + "author": "Denis Waitley" + }, + { + "content": "Sometimes the most important thing in a whole day is the rest we take between two deep breaths.", + "author": "Etty Hillesum" + }, + { + "content": "An ounce of emotion is equal to a ton of facts.", + "author": "John Junor" + }, + { + "content": "Appreciation can make a day, even change a life. Your willingness to put it into words is all that is necessary.", + "author": "Margaret Cousins" + }, + { + "content": "Chance is always powerful. Let your hook be always cast; in the pool where you least expect it, there will be a fish.", + "author": "Ovid" + }, + { + "content": "In skating over thin ice our safety is in our speed.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Let go of your attachment to being right, and suddenly your mind is more open. You're able to benefit from the unique viewpoints of others, without being crippled by your own judgement.", + "author": "Ralph Marston" + }, + { + "content": "Let the beauty of what you love be what you do.", + "author": "Rumi" + }, + { + "content": "Democracy's premise rests on the notion that the collective wisdom of the majority will prove right more often than it's wrong; that given sufficient opportunity in the pursuit of happiness, your population will develop its talents, its intellect, its better judgment; that over time its capacity for discernment and self-correction will be enlarged.", + "author": "Ben Fountain" + }, + { + "content": "Life is a travelling to the edge of knowledge, then a leap taken.", + "author": "Laurence J. Peter" + }, + { + "content": "Tragedy is a tool for the living to gain wisdom, not a guide by which to live.", + "author": "Robert F. Kennedy" + }, + { + "content": "The virtue of justice consists in moderation, as regulated by wisdom.", + "author": "Aristotle" + }, + { + "content": "Remember that the most valuable antiques are dear old friends.", + "author": "H. Jackson Brown Jr." + }, + { + "content": "Remember that a gesture of friendship, no matter how small, is always appreciated.", + "author": "H. Jackson Brown Jr." + }, + { + "content": "Joy is the best makeup.", + "author": "Anne Lamott" + }, + { + "content": "If one is estranged from oneself, then one is estranged from others too. If one is out of touch with oneself, then one cannot touch others.", + "author": "Anne Lindbergh" + }, + { + "content": "We are what we repeatedly do. Excellence, then, is not an act, but a habit.", + "author": "Aristotle" + }, + { + "content": "The least movement is of importance to all nature. The entire ocean is affected by a pebble.", + "author": "Blaise Pascal" + }, + { + "content": "Goals are the fuel in the furnace of achievement.", + "author": "Brian Tracy" + }, + { + "content": "Mistakes are always forgivable, if one has the courage to admit them.", + "author": "Bruce Lee" + }, + { + "content": "The highest stage in moral culture at which we can arrive is when we recognize that we ought to control our thoughts.", + "author": "Charles Darwin" + }, + { + "content": "Life is really simple, but we insist on making it complicated.", + "author": "Confucius" + }, + { + "content": "People take different roads seeking fulfilment and happiness. Just because they're not on your road doesn't mean they've gotten lost.", + "author": "Dalai Lama" + }, + { + "content": "Great minds discuss ideas; average minds discuss events; small minds discuss people.", + "author": "Eleanor Roosevelt" + }, + { + "_id": "pOAcy5-yW-3", + "content": "A prudent question is one half of wisdom.", + "author": "Francis Bacon" + }, + { + "content": "The possibilities are numerous once we decide to act and not react.", + "author": "George Bernard Shaw" + }, + { + "content": "Myths which are believed in tend to become true.", + "author": "George Orwell" + }, + { + "content": "It is far better to be alone, than to be in bad company.", + "author": "George Washington" + }, + { + "content": "Don't compromise yourself. You are all you've got.", + "author": "Janis Joplin" + }, + { + "content": "Give a man a fish and you feed him for a day. Teach him how to fish and you feed him for a lifetime.", + "author": "Laozi" + }, + { + "content": "Happiness is found in doing, not merely possessing.", + "author": "Napoleon Hill" + }, + { + "content": "The biggest adventure you can ever take is to live the life of your dreams.", + "author": "Oprah Winfrey" + }, + { + "content": "It isn't what happens to us that causes us to suffer; it's what we say to ourselves about what happens.", + "author": "Pema Chödrön" + }, + { + "content": "There is nothing so useless as doing efficiently that which should not be done at all.", + "author": "Peter Drucker" + }, + { + "content": "Go put your creed into the deed. Nor speak with double tongue.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "To be what we are, and to become what we are capable of becoming, is the only end of life.", + "author": "Robert Louis Stevenson" + }, + { + "content": "Setting goals is the first step in turning the invisible into the visible.", + "author": "Tony Robbins" + }, + { + "content": "The deepest craving of human nature is the need to be appreciated.", + "author": "William James" + }, + { + "content": "Positive thinking will let you do everything better than negative thinking will.", + "author": "Zig Ziglar" + }, + { + "content": "Quick decisions are unsafe decisions.", + "author": "Sophocles" + }, + { + "content": "Always keep your mind as bright and clear as the vast sky, the great ocean, and the highest peak, empty of all thoughts. Always keep your body filled with light and heat. Fill yourself with the power of wisdom and enlightenment.", + "author": "Morihei Ueshiba" + }, + { + "content": "Commitment is an act, not a word.", + "author": "Jean-Paul Sartre" + }, + { + "content": "I look forward to a great future for America - a future in which our country will match its military strength with our moral restraint, its wealth with our wisdom, its power with our purpose.", + "author": "John F. Kennedy" + }, + { + "content": "A heart well prepared for adversity in bad times hopes, and in good times fears for a change in fortune.", + "author": "Horace" + }, + { + "content": "Friendship is essentially a partnership.", + "author": "Aristotle" + }, + { + "author": "Woody Allen", + "content": "It seemed the world was divided into good and bad people. The good ones slept better... while the bad ones seemed to enjoy the waking hours much more." + }, + { + "_id": "w3Rpf-oD-QF", + "content": "I never think of the future. It comes soon enough.", + "author": "Albert Einstein" + }, + { + "content": "Moral excellence comes about as a result of habit. We become just by doing just acts, temperate by doing temperate acts, brave by doing brave acts.", + "author": "Aristotle" + }, + { + "content": "All I can say about life is, Oh God, enjoy it!", + "author": "Bob Newhart" + }, + { + "content": "He is able who thinks he is able.", + "author": "Buddha" + }, + { + "content": "If you light a lamp for somebody, it will also brighten your path.", + "author": "Buddha" + }, + { + "_id": "lEjcF-a2-Z5w", + "content": "Sincerity is the way of Heaven. The attainment of sincerity is the way of men.", + "author": "Confucius" + }, + { + "content": "There is only one way to happiness and that is to cease worrying about things which are beyond the power of our will.", + "author": "Epictetus" + }, + { + "content": "Adversity has the effect of eliciting talents, which in prosperous circumstances would have lain dormant.", + "author": "Horace" + }, + { + "content": "All our knowledge begins with the senses, proceeds then to the understanding, and ends with reason. There is nothing higher than reason.", + "author": "Immanuel Kant" + }, + { + "content": "Good timber does not grow with ease; the stronger the wind, the stronger the trees.", + "author": "J. Willard Marriott" + }, + { + "content": "Nothing could be worse than the fear that one had given up too soon and left one unexpended effort that might have saved the world.", + "author": "Jane Addams" + }, + { + "content": "Never mistake activity for achievement.", + "author": "John Wooden" + }, + { + "content": "Nothing is softer or more flexible than water, yet nothing can resist it.", + "author": "Laozi" + }, + { + "content": "The power of intuitive understanding will protect you from harm until the end of your days.", + "author": "Laozi" + }, + { + "content": "Always remember that you are absolutely unique. Just like everyone else.", + "author": "Margaret Mead" + }, + { + "content": "When you learn, teach. When you get, give.", + "author": "Maya Angelou" + }, + { + "content": "The beginning of wisdom is found in doubting; by doubting we come to the question, and by seeking we may come upon the truth.", + "author": "Peter Abelard" + }, + { + "content": "Lose an hour in the morning, and you will spend all day looking for it.", + "author": "Richard Whately" + }, + { + "content": "Let yourself be silently drawn by the stronger pull of what you really love.", + "author": "Rumi" + }, + { + "content": "Work for something because it is good, not just because it stands a chance to succeed.", + "author": "Václav Havel" + }, + { + "content": "Nothing diminishes anxiety faster than action.", + "author": "Walter Inglis Anderson" + }, + { + "content": "Remember that failure is an event, not a person.", + "author": "Zig Ziglar" + }, + { + "content": "Start where you are. Use what you have. Do what you can.", + "author": "Arthur Ashe" + }, + { + "content": "To profit from good advice requires more wisdom than to give it.", + "author": "Wilson Mizner" + }, + { + "content": "The most technologically efficient machine that man has ever invented is the book.", + "author": "Northrop Frye" + }, + { + "content": "The language of friendship is not words but meanings.", + "author": "Henry David Thoreau" + }, + { + "content": "A true friend is one who overlooks your failures and tolerates your success!", + "author": "Doug Larson" + }, + { + "content": "A passion for politics stems usually from an insatiable need, either for power, or for friendship and adulation, or a combination of both.", + "author": "Fawn M. Brodie" + }, + { + "author": "Woody Allen", + "content": "Eternal nothingness is fine if you happen to be dressed for it." + }, + { + "author": "Abraham Lincoln", + "content": "I will prepare and someday my chance will come." + }, + { + "content": "All great men are gifted with intuition. They know without reasoning or analysis, what they need to know.", + "author": "Alexis Carrel" + }, + { + "content": "The foot feels the foot when it feels the ground.", + "author": "Buddha" + }, + { + "content": "Knowledge rests not upon truth alone, but upon error also.", + "author": "Carl Jung" + }, + { + "content": "Wisdom is the reward you get for a lifetime of listening when you'd have preferred to talk.", + "author": "Doug Larson" + }, + { + "_id": "WLJJ_y-H-sH0", + "content": "He is a wise man who does not grieve for the things which he has not but rejoices for those which he has.", + "author": "Epictetus" + }, + { + "content": "All is flux; nothing stays still.", + "author": "Heraclitus" + }, + { + "content": "Time you enjoy wasting, was not wasted.", + "author": "John Lennon" + }, + { + "content": "The world has the habit of making room for the man whose actions show that he knows where he is going.", + "author": "Napoleon Hill" + }, + { + "content": "Life is a succession of lessons, which must be lived to be understood.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Creativity comes from trust. Trust your instincts. And never hope more than you work.", + "author": "Rita Mae Brown" + }, + { + "content": "Instead of saying that man is the creature of circumstance, it would be nearer the mark to say that man is the architect of circumstance.", + "author": "Thomas Carlyle" + }, + { + "content": "Yesterday is history, tomorrow is a mystery, today is God's gift, that's why we call it the present.", + "author": "Joan Rivers" + }, + { + "content": "A monarchy conducted with infinite wisdom and infinite benevolence is the most perfect of all possible governments.", + "author": "Ezra Stiles" + }, + { + "content": "Wisdom often times consists of knowing what to do next.", + "author": "Herbert Hoover" + }, + { + "content": "It's supposed to be automatic, but actually you have to push this button.", + "author": "John Brunner" + }, + { + "content": "Experts on romance say for a happy marriage there has to be more than a passionate love. For a lasting union, they insist, there must be a genuine liking for each other. Which, in my book, is a good definition for friendship.", + "author": "Marilyn Monroe" + }, + { + "author": "William Shakespeare", + "content": "Action is eloquence." + }, + { + "content": "Never apologize for showing feeling. When you do so, you apologize for truth.", + "author": "Benjamin Disraeli" + }, + { + "content": "One fails forward toward success.", + "author": "Charles F. Kettering" + }, + { + "content": "If only wed stop trying to be happy wed have a pretty good time.", + "author": "Edith Wharton" + }, + { + "content": "When you are offended at any man's fault, turn to yourself and study your own failings. Then you will forget your anger.", + "author": "Epictetus" + }, + { + "content": "All truths are easy to understand once they are discovered; the point is to discover them.", + "author": "Galileo Galilei" + }, + { + "content": "There is only one happiness in life, to love and be loved.", + "author": "George Sand" + }, + { + "content": "Without some goals and some efforts to reach it, no man can live.", + "author": "John Dewey" + }, + { + "content": "A day of worry is more exhausting than a day of work.", + "author": "John Lubbock" + }, + { + "content": "I have been impressed with the urgency of doing. Knowing is not enough; we must apply. Being willing is not enough; we must do.", + "author": "Leonardo da Vinci" + }, + { + "content": "I'm not afraid of storms, for I'm learning how to sail my ship.", + "author": "Louisa May Alcott" + }, + { + "_id": "OG9-EbvEi-v", + "content": "We must become the change we want to see.", + "author": "Mahatma Gandhi" + }, + { + "content": "The best thing in every noble dream is the dreamer...", + "author": "Moncure D. Conway" + }, + { + "content": "The ladder of success is never crowded at the top.", + "author": "Napoleon Hill" + }, + { + "content": "Experience is simply the name we give our mistakes.", + "author": "Oscar Wilde" + }, + { + "content": "The best way to predict your future is to create it.", + "author": "Peter Drucker" + }, + { + "content": "The greatest remedy for anger is delay.", + "author": "Seneca the Younger" + }, + { + "content": "Ignorant men don't know what good they hold in their hands until they've flung it away.", + "author": "Sophocles" + }, + { + "content": "We must overcome the notion that we must be regular. It robs you of the chance to be extraordinary and leads you to the mediocre.", + "author": "Uta Hagen" + }, + { + "content": "The greatest discovery of our generation is that human beings can alter their lives by altering their attitudes of mind. As you think, so shall you be.", + "author": "William James" + }, + { + "content": "Think as a wise man but communicate in the language of the people.", + "author": "William Butler Yeats" + }, + { + "content": "We are what our thoughts have made us; so take care about what you think. Words are secondary. Thoughts live; they travel far.", + "author": "Swami Vivekananda" + }, + { + "content": "Without freedom of thought, there can be no such thing as wisdom - and no such thing as public liberty without freedom of speech.", + "author": "Benjamin Franklin" + }, + { + "content": "Friendship may, and often does, grow into love, but love never subsides into friendship.", + "author": "Lord Byron" + }, + { + "author": "Woody Allen", + "content": "I took a speed-reading course and read 'War and Peace' in twenty minutes. It involves Russia." + }, + { + "_id": "Dg-s-e2zAXKs", + "content": "One who gains strength by overcoming obstacles possesses the only strength which can overcome adversity.", + "author": "Albert Schweitzer" + }, + { + "content": "Wherever a man turns he can find someone who needs him.", + "author": "Albert Schweitzer" + }, + { + "content": "It is only with the heart that one can see rightly, what is essential is invisible to the eye.", + "author": "Antoine de Saint-Exupéry" + }, + { + "content": "Excellence is to do a common thing in an uncommon way.", + "author": "Booker T. Washington" + }, + { + "content": "There is never enough time to do everything, but there is always enough time to do the most important thing.", + "author": "Brian Tracy" + }, + { + "content": "Let us revere, let us worship, but erect and open-eyed, the highest, not the lowest; the future, not the past!", + "author": "Charlotte Perkins Gilman" + }, + { + "content": "If we look at the world with a love of life, the world will reveal its beauty to us.", + "author": "Daisaku Ikeda" + }, + { + "content": "Knowing is not enough; we must apply!", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "You may say I'm a dreamer, but I'm not the only one, I hope someday you will join us, and the world will live as one.", + "author": "John Lennon" + }, + { + "content": "I believe that every person is born with talent.", + "author": "Maya Angelou" + }, + { + "content": "Wise men talk because they have something to say; fools, because they have to say something.", + "author": "Plato" + }, + { + "content": "Don't judge each day by the harvest you reap but by the seeds that you plant.", + "author": "Robert Louis Stevenson" + }, + { + "content": "The most precious gift we can offer anyone is our attention. When mindfulness embraces those we love, they will bloom like flowers.", + "author": "Thích Nhất Hạnh" + }, + { + "content": "The longer we dwell on our misfortunes, the greater is their power to harm us.", + "author": "Voltaire" + }, + { + "content": "Keep your face always toward the sunshine - and shadows will fall behind you.", + "author": "Walt Whitman" + }, + { + "content": "You are not here merely to make a living. You are here in order to enable the world to live more amply, with greater vision, with a finer spirit of hope and achievement. You are here to enrich the world, and you impoverish yourself if you forget the errand.", + "author": "Woodrow Wilson" + }, + { + "content": "Before we acquire great power, we must acquire wisdom to use it well.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Be courteous to all, but intimate with few, and let those few be well tried before you give them your confidence.", + "author": "George Washington" + }, + { + "content": "True friends stab you in the front.", + "author": "Oscar Wilde" + }, + { + "content": "Whenever you have eliminated the impossible, whatever remains, however improbable, must be the truth.", + "author": "Arthur Conan Doyle" + }, + { + "content": "To give oneself earnestly to the duties due to men, and, while respecting spiritual beings, to keep aloof from them, may be called wisdom.", + "author": "Confucius" + }, + { + "content": "There are two primary choices in life: to accept conditions as they exist or accept responsibility for changing them.", + "author": "Denis Waitley" + }, + { + "content": "Don't ruin the present with the ruined past.", + "author": "Ellen Gilchrist" + }, + { + "content": "When we quit thinking primarily about ourselves and our own self-preservation, we undergo a truly heroic transformation of consciousness.", + "author": "Joseph Campbell" + }, + { + "content": "For it was not into my ear you whispered, but into my heart. It was not my lips you kissed, but my soul.", + "author": "Judy Garland" + }, + { + "content": "Look back over the past, with its changing empires that rose and fell, and you can foresee the future, too.", + "author": "Marcus Aurelius" + }, + { + "content": "Let the future tell the truth and evaluate each one according to his work and accomplishments. The present is theirs; the future, for which I have really worked, is mine.", + "author": "Nikola Tesla" + }, + { + "content": "Do all things with love.", + "author": "Og Mandino" + }, + { + "content": "Divide each difficulty into as many parts as is feasible and necessary to resolve it.", + "author": "René Descartes" + }, + { + "content": "There is no great genius without some touch of madness.", + "author": "Seneca the Younger" + }, + { + "content": "From error to error one discovers the entire truth.", + "author": "Sigmund Freud" + }, + { + "content": "He that never changes his opinions, never corrects his mistakes, and will never be wiser on the morrow than he is today.", + "author": "Tryon Edwards" + }, + { + "content": "To choose what is difficult all one's days, as if it were easy, that is faith.", + "author": "W. H. Auden" + }, + { + "content": "The road of excess leads to the palace of wisdom.", + "author": "William Blake" + }, + { + "content": "Friendship is one mind in two bodies.", + "author": "Mencius" + }, + { + "content": "A friendship founded on business is better than a business founded on friendship.", + "author": "John Locke" + }, + { + "content": "My friends are my estate.", + "author": "Emily Dickinson" + }, + { + "content": "When a friend is in trouble, don't annoy him by asking if there is anything you can do. Think up something appropriate and do it.", + "author": "A. Powell Davies" + }, + { + "content": "Life is just a chance to grow a soul.", + "author": "A. Powell Davies" + }, + { + "content": "In separateness lies the world's great misery, in compassion lies the world's true strength.", + "author": "Buddha" + }, + { + "content": "Every human being is the author of his own health or disease.", + "author": "Buddha" + }, + { + "content": "Our greatest glory is not in never falling, but in rising every time we fall.", + "author": "Confucius" + }, + { + "content": "The only real mistake is the one from which we learn nothing.", + "author": "John Powell" + }, + { + "content": "I can't believe that God put us on this earth to be ordinary.", + "author": "Lou Holtz" + }, + { + "content": "It is not the possession of truth, but the success which attends the seeking after it, that enriches the seeker and brings happiness to him.", + "author": "Max Planck" + }, + { + "content": "To succeed, we must first believe that we can.", + "author": "Michael Korda" + }, + { + "content": "The difference between what we do and what we are capable of doing would suffice to solve most of the world's problems.", + "author": "Mahatma Gandhi" + }, + { + "content": "We come to love not by finding a perfect person, but by learning to see an imperfect person perfectly.", + "author": "Sam Keen" + }, + { + "content": "Leave no stone unturned.", + "author": "Euripides" + }, + { + "content": "There is more wisdom in your body than in your deepest philosophy.", + "author": "Friedrich Nietzsche" + }, + { + "content": "Does wisdom perhaps appear on the earth as a raven which is inspired by the smell of carrion?", + "author": "Friedrich Nietzsche" + }, + { + "content": "Science gives us knowledge, but only philosophy can give us wisdom.", + "author": "Will Durant" + }, + { + "content": "Once a new technology rolls over you, if you're not part of the steamroller, you're part of the road.", + "author": "Stewart Brand" + }, + { + "content": "A true friend is someone who is there for you when he'd rather be anywhere else.", + "author": "Len Wein" + }, + { + "content": "Autumn is a second spring when every leaf is a flower.", + "author": "Albert Camus" + }, + { + "content": "The happiness that is genuinely satisfying is accompanied by the fullest exercise of our faculties and the fullest realization of the world in which we live.", + "author": "Bertrand Russell" + }, + { + "content": "See the positive side, the potential, and make an effort.", + "author": "Dalai Lama" + }, + { + "content": "When one door of happiness closes, another opens; but often we look so long at the closed door that we do not see the one which has been opened for us.", + "author": "Helen Keller" + }, + { + "content": "Forgiveness is choosing to love. It is the first skill of self-giving love.", + "author": "Mahatma Gandhi" + }, + { + "content": "Mind is everything: muscle, pieces of rubber. All that I am, I am because of my mind.", + "author": "Paavo Nurmi" + }, + { + "content": "I am always doing that which I cannot do, in order that I may learn how to do it.", + "author": "Pablo Picasso" + }, + { + "content": "Chaos and Order are not enemies, only opposites.", + "author": "Richard Garriott" + }, + { + "content": "The amount of happiness that you have depends on the amount of freedom you have in your heart.", + "author": "Thích Nhất Hạnh" + }, + { + "content": "Four steps to achievement: Plan purposefully. Prepare prayerfully. Proceed positively. Pursue persistently.", + "author": "William Arthur Ward" + }, + { + "content": "The fall of dropping water wears away the Stone.", + "author": "Lucretius" + }, + { + "content": "The art of storytelling is reaching its end because the epic side of truth, wisdom, is dying out.", + "author": "Walter Benjamin" + }, + { + "content": "Knowledge is going to make you stronger. Knowledge is going to let you control your life. Knowledge is going to give you the wisdom to teach their children. Knowledge is the thing that makes you smile in the face of disaster.", + "author": "Avery Brooks" + }, + { + "content": "This is the whole point of technology. It creates an appetite for immortality on the one hand. It threatens universal extinction on the other. Technology is lust removed from nature.", + "author": "Don DeLillo" + }, + { + "content": "I have friends in overalls whose friendship I would not swap for the favor of the kings of the world.", + "author": "Thomas Edison" + }, + { + "content": "Rock n' roll as a genre is different from pop and hip hop: it is about bands, and that for me suggests brotherhood, family, friendship and community.", + "author": "Steven Van Zandt" + }, + { + "author": "Woody Allen", + "content": "I'm astounded by people who want to 'know' the universe when it's hard enough to find your way around Chinatown." + }, + { + "content": "Setting an example is not the main means of influencing another, it is the only means.", + "author": "Albert Einstein" + }, + { + "content": "Life is so constructed that an event does not, cannot, will not, match the expectation.", + "author": "Charlotte Brontë" + }, + { + "content": "Life is a succession of moments. To live each one is to succeed.", + "author": "Corita Kent" + }, + { + "content": "If we have a positive mental attitude, then even when surrounded by hostility, we shall not lack inner peace.", + "author": "Dalai Lama" + }, + { + "content": "Light tomorrow with today!", + "author": "Elizabeth Browning" + }, + { + "content": "When you come to the end of your rope, tie a knot and hang on.", + "author": "Franklin D. Roosevelt" + }, + { + "content": "Face your deficiencies and acknowledge them; but do not let them master you. Let them teach you patience, sweetness, insight.", + "author": "Helen Keller" + }, + { + "content": "The foolish man seeks happiness in the distance, the wise grows it under his feet.", + "author": "James Oppenheim" + }, + { + "content": "The more you care, the stronger you can be.", + "author": "Jim Rohn" + }, + { + "content": "Victory belongs to the most persevering.", + "author": "Napoleon" + }, + { + "content": "With every experience, you alone are painting your own canvas, thought by thought, choice by choice.", + "author": "Oprah Winfrey" + }, + { + "content": "The smallest act of kindness is worth more than the grandest intention.", + "author": "Oscar Wilde" + }, + { + "content": "Every gift from a friend is a wish for your happiness.", + "author": "Richard Bach" + }, + { + "content": "Miracles come in moments. Be ready and willing.", + "author": "Wayne Dyer" + }, + { + "content": "Courage is going from failure to failure without losing enthusiasm.", + "author": "Winston Churchill" + }, + { + "content": "What wisdom can you find that is greater than kindness?", + "author": "Jean-Jacques Rousseau" + }, + { + "content": "To acquire knowledge, one must study; but to acquire wisdom, one must observe.", + "author": "Marilyn vos Savant" + }, + { + "content": "Communications tools don't get socially interesting until they get technologically boring.", + "author": "Clay Shirky" + }, + { + "content": "Technology is anything that wasn't around when you were born.", + "author": "Man Ray" + }, + { + "content": "False friendship, like the ivy, decays and ruins the walls it embraces; but true friendship gives new life and animation to the object it supports.", + "author": "Richard Burton" + }, + { + "content": "The sincere friends of this world are as ship lights in the stormiest of nights.", + "author": "Giotto" + }, + { + "content": "Love does not consist of gazing at each other, but in looking together in the same direction.", + "author": "Antoine de Saint-Exupéry" + }, + { + "content": "Love is composed of a single soul inhabiting two bodies.", + "author": "Aristotle" + }, + { + "content": "To live a pure unselfish life, one must count nothing as one's own in the midst of abundance.", + "author": "Buddha" + }, + { + "content": "The Superior Man is aware of Righteousness, the inferior man is aware of advantage.", + "author": "Confucius" + }, + { + "content": "Just as a flower, which seems beautiful has color but no perfume, so are the fruitless words of a man who speaks them but does them not.", + "author": "Dhammapada" + }, + { + "content": "What do we live for, if it is not to make life less difficult for each other?", + "author": "George Eliot" + }, + { + "content": "Keep yourself to the sunshine and you cannot see the shadow.", + "author": "Helen Keller" + }, + { + "content": "Not all those who wander are lost.", + "author": "J. R. R. Tolkien" + }, + { + "content": "If we could learn to like ourselves, even a little, maybe our cruelties and angers might melt away.", + "author": "John Steinbeck" + }, + { + "content": "You can't let praise or criticism get to you. It's a weakness to get caught up in either one.", + "author": "John Wooden" + }, + { + "content": "Let us be grateful to people who make us happy; they are the charming gardeners who make our souls blossom.", + "author": "Marcel Proust" + }, + { + "content": "Nothing in life is to be feared, it is only to be understood. Now is the time to understand more, so that we may fear less.", + "author": "Marie Curie" + }, + { + "content": "The universe is made of stories, not atoms.", + "author": "Muriel Rukeyser" + }, + { + "content": "Wise men speak because they have something to say; Fools because they have to say something.", + "author": "Plato" + }, + { + "content": "We must be as courteous to a man as we are to a picture, which we are willing to give the advantage of a good light.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Intuition is the supra-logic that cuts out all the routine processes of thought and leaps straight from the problem to the answer.", + "author": "Robert Graves" + }, + { + "content": "Liberty, taking the word in its concrete sense, consists in the ability to choose.", + "author": "Simone Weil" + }, + { + "content": "Reason and free inquiry are the only effectual agents against error.", + "author": "Thomas Jefferson" + }, + { + "content": "Go to your bosom: Knock there and ask your heart what it doth know.", + "author": "William Shakespeare" + }, + { + "content": "True knowledge exists in knowing that you know nothing.", + "author": "Isocrates" + }, + { + "content": "And when the world is created, it is created in such a way that those eternal objects of God's loving wisdom become actualities - interacting with one another, relating to God in the finite realm.", + "author": "Rowan Williams" + }, + { + "content": "Ethics change with technology.", + "author": "Larry Niven" + }, + { + "content": "One loyal friend is worth ten thousand relatives.", + "author": "Euripides" + }, + { + "content": "Sweet is the memory of distant friends! Like the mellow rays of the departing sun, it falls tenderly, yet sadly, on the heart.", + "author": "Washington Irving" + }, + { + "author": "Woody Allen", + "content": "His lack of education is more than compensated for by his keenly developed moral bankruptcy." + }, + { + "content": "Without courage, wisdom bears no fruit.", + "author": "Baltasar Gracián" + }, + { + "content": "To know oneself is to study oneself in action with another person.", + "author": "Bruce Lee" + }, + { + "content": "In all chaos there is a cosmos, in all disorder a secret order.", + "author": "Carl Jung" + }, + { + "content": "There are people who have money and people who are rich.", + "author": "Coco Chanel" + }, + { + "content": "You don't choose your family. They are God's gift to you, as you are to them.", + "author": "Desmond Tutu" + }, + { + "content": "There are two ways of spreading light: to be the candle or the mirror that reflects it.", + "author": "Edith Wharton" + }, + { + "content": "Problems are only opportunities with thorns on them.", + "author": "Hugh Miller" + }, + { + "content": "By accepting yourself and being fully what you are, your presence can make others happy.", + "author": "Jane Roberts" + }, + { + "content": "When one tugs at a single thing in nature, he finds it attached to the rest of the world.", + "author": "John Muir" + }, + { + "content": "The two most powerful warriors are patience and time.", + "author": "Leo Tolstoy" + }, + { + "content": "Time stays long enough for anyone who will use it.", + "author": "Leonardo da Vinci" + }, + { + "content": "Let me tell you the secret that has led me to my goal: my strength lies solely in my tenacity.", + "author": "Louis Pasteur" + }, + { + "_id": "l-mD-YbIuRvk", + "content": "The exercise of an extraordinary gift is the supremist pleasure in life.", + "author": "Mark Twain" + }, + { + "content": "Peace begins with a smile.", + "author": "Mother Teresa" + }, + { + "content": "Do not turn back when you are just at the goal.", + "author": "Publilius Syrus" + }, + { + "content": "By living deeply in the present moment we can understand the past better and we can prepare for a better future.", + "author": "Thích Nhất Hạnh" + }, + { + "content": "There are no failures. Just experiences and your reactions to them.", + "author": "Tom Krause" + }, + { + "content": "Be miserable. Or motivate yourself. Whatever has to be done, it's always your choice.", + "author": "Wayne Dyer" + }, + { + "content": "Life is a learning experience, only if you learn.", + "author": "Yogi Berra" + }, + { + "content": "The man of knowledge must be able not only to love his enemies but also to hate his friends.", + "author": "Friedrich Nietzsche" + }, + { + "content": "The most certain sign of wisdom is cheerfulness.", + "author": "Michel de Montaigne" + }, + { + "content": "Nine-tenths of wisdom is being wise in time.", + "author": "Theodore Roosevelt" + }, + { + "content": "Love is the wisdom of the fool and the folly of the wise.", + "author": "Samuel Johnson" + }, + { + "content": "It is a characteristic of wisdom not to do desperate things.", + "author": "Henry David Thoreau" + }, + { + "content": "But friendship is precious, not only in the shade, but in the sunshine of life, and thanks to a benevolent arrangement the greater part of life is sunshine.", + "author": "Thomas Jefferson" + }, + { + "author": "Woody Allen", + "content": "Life is divided into the horrible and the miserable." + }, + { + "content": "There is only one corner of the universe you can be certain of improving, and that's your own self.", + "author": "Aldous Huxley" + }, + { + "content": "Through perseverance many people win success out of what seemed destined to be certain failure.", + "author": "Benjamin Disraeli" + }, + { + "content": "We cannot do everything at once, but we can do something at once.", + "author": "Calvin Coolidge" + }, + { + "content": "Flow with whatever is happening and let your mind be free. Stay centered by accepting whatever you are doing. This is the ultimate.", + "author": "Zhuang Zhou" + }, + { + "content": "Silence is the true friend that never betrays.", + "author": "Confucius" + }, + { + "content": "Everything has beauty, but not everyone sees it.", + "author": "Confucius" + }, + { + "content": "More often than not, anger is actually an indication of weakness rather than of strength.", + "author": "Dalai Lama" + }, + { + "content": "The best preparation for tomorrow is doing your best today.", + "author": "H. Jackson Brown Jr." + }, + { + "content": "No pessimist ever discovered the secrets of the stars, or sailed to an uncharted land, or opened a new heaven to the human spirit.", + "author": "Helen Keller" + }, + { + "content": "Life is movement-we breathe, we eat, we walk, we move!", + "author": "John Pierrakos" + }, + { + "content": "The free man is he who does not fear to go to the end of his thought.", + "author": "Léon Blum" + }, + { + "content": "When in doubt, tell the truth.", + "author": "Mark Twain" + }, + { + "content": "Be faithful in small things because it is in them that your strength lies.", + "author": "Mother Teresa" + }, + { + "content": "Most great people have attained their greatest success just one step beyond their greatest failure.", + "author": "Napoleon Hill" + }, + { + "content": "If you don't go after what you want, you'll never have it. If you don't ask, the answer is always no. If you don't step forward, you're always in the same place.", + "author": "Nora Roberts" + }, + { + "content": "Inspiration exists, but it has to find us working.", + "author": "Pablo Picasso" + }, + { + "content": "If the single man plant himself indomitably on his instincts, and there abide, the huge world will come round to him.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Imagination is not a talent of some men but is the health of every man.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "This world, after all our science and sciences, is still a miracle; wonderful, inscrutable, magical and more, to whosoever will think of it.", + "author": "Thomas Carlyle" + }, + { + "content": "There is no way to prosperity, prosperity is the way.", + "author": "Wayne Dyer" + }, + { + "content": "You can't choose up sides on a round world.", + "author": "Wayne Dyer" + }, + { + "content": "Continuous effort - not strength or intelligence - is the key to unlocking our potential.", + "author": "Winston Churchill" + }, + { + "content": "The greater danger for most of us lies not in setting our aim too high and falling short; but in setting our aim too low and achieving our mark.", + "author": "Michelangelo" + }, + { + "content": "I decided that it was not wisdom that enabled poets to write their poetry, but a kind of instinct or inspiration, such as you find in seers and prophets who deliver all their sublime messages without knowing in the least what they mean.", + "author": "Isocrates" + }, + { + "content": "Sorrow is knowledge, those that know the most must mourn the deepest, the tree of knowledge is not the tree of life.", + "author": "Lord Byron" + }, + { + "content": "Much wisdom often goes with fewest words.", + "author": "Sophocles" + }, + { + "content": "Wisdom begins at the end.", + "author": "Daniel Webster" + }, + { + "content": "Friendship is always a sweet responsibility, never an opportunity.", + "author": "Kahlil Gibran" + }, + { + "content": "A friend is a gift you give yourself.", + "author": "Robert Louis Stevenson" + }, + { + "content": "The differences between friends cannot but reinforce their friendship.", + "author": "Mao Zedong" + }, + { + "content": "Friendship at first sight, like love at first sight, is said to be the only truth.", + "author": "Herman Melville" + }, + { + "content": "Love is rarer than genius itself. And friendship is rarer than love.", + "author": "Charles Péguy" + }, + { + "content": "Friendship is like money, easier made than kept.", + "author": "Samuel Butler" + }, + { + "content": "We cannot solve our problems with the same thinking we used when we created them.", + "author": "Albert Einstein" + }, + { + "content": "Ignorance never settles a question.", + "author": "Benjamin Disraeli" + }, + { + "content": "Set your goals high, and don't stop till you get there.", + "author": "Bo Jackson" + }, + { + "content": "Those who will play with cats must expect to be scratched.", + "author": "Miguel de Cervantes" + }, + { + "content": "We are all faced with a series of great opportunities brilliantly disguised as impossible situations.", + "author": "Chuck Swindoll" + }, + { + "content": "Ability will never catch up with the demand for it.", + "author": "Confucius" + }, + { + "content": "Only when we are no longer afraid do we begin to live.", + "author": "Dorothy Thompson" + }, + { + "content": "Only through our connectedness to others can we really know and enhance the self. And only through working on the self can we begin to enhance our connectedness to others.", + "author": "Harriet Lerner" + }, + { + "content": "The world is but a canvas to the imagination.", + "author": "Henry David Thoreau" + }, + { + "content": "We can only learn to love by loving.", + "author": "Iris Murdoch" + }, + { + "content": "Great indeed is the sublimity of the Creative, to which all beings owe their beginning, and which permeates all heaven.", + "author": "Laozi" + }, + { + "content": "He who knows, does not speak. He who speaks, does not know.", + "author": "Laozi" + }, + { + "content": "Spread love everywhere you go. Let no one ever come to you without leaving happier.", + "author": "Mother Teresa" + }, + { + "content": "If you cannot do great things, do small things in a great way.", + "author": "Napoleon Hill" + }, + { + "content": "Let your hook always be cast; in the pool where you least expect it, there will be a fish.", + "author": "Ovid" + }, + { + "content": "Either I will find a way, or I will make one.", + "author": "Philip Sidney" + }, + { + "content": "The greatest way to live with honor in this world is to be what we pretend to be.", + "author": "Socrates" + }, + { + "content": "Judge nothing, you will be happy. Forgive everything, you will be happier. Love everything, you will be happiest.", + "author": "Sri Chinmoy" + }, + { + "content": "The only limit to your impact is your imagination and commitment.", + "author": "Tony Robbins" + }, + { + "content": "No snowflake in an avalanche ever feels responsible.", + "author": "Voltaire" + }, + { + "content": "Our intention creates our reality.", + "author": "Wayne Dyer" + }, + { + "content": "Act as if what you do makes a difference. It does.", + "author": "William James" + }, + { + "content": "Do the one thing you think you cannot do. Fail at it. Try again. Do better the second time. The only people who never tumble are those who never mount the high wire. This is your moment. Own it.", + "author": "Oprah Winfrey" + }, + { + "content": "To enjoy good health, to bring true happiness to one's family, to bring peace to all, one must first discipline and control one's own mind. If a man can control his mind, he can find the way to Enlightenment, and all wisdom and virtue will naturally come to him.", + "author": "Buddha" + }, + { + "content": "There are three methods to gaining wisdom. The first is reflection, which is the highest. The second is limitation, which is the easiest. The third is experience, which is the bitterest.", + "author": "Confucius" + }, + { + "content": "To conquer fear is the beginning of wisdom.", + "author": "Bertrand Russell" + }, + { + "content": "There are three faithful friends - an old wife, an old dog, and ready money.", + "author": "Benjamin Franklin" + }, + { + "content": "Any sufficiently advanced technology is equivalent to magic.", + "author": "Arthur C. Clarke" + }, + { + "content": "Friendship is but another name for an alliance with the follies and the misfortunes of others. Our own share of miseries is sufficient: why enter then as volunteers into those of another?", + "author": "Thomas Jefferson" + }, + { + "content": "I am like a falling star who has finally found her place next to another in a lovely constellation, where we will sparkle in the heavens forever.", + "author": "Amy Tan" + }, + { + "content": "Three things cannot be long hidden: the sun, the moon, and the truth.", + "author": "Buddha" + }, + { + "content": "There is only one success - to be able to spend your life in your own way.", + "author": "Christopher Morley" + }, + { + "content": "You know you're in love when you can't fall asleep because reality is finally better than your dreams.", + "author": "Dr. Seuss" + }, + { + "content": "No man is free who is not master of himself.", + "author": "Epictetus" + }, + { + "content": "If I know what love is, it is because of you.", + "author": "Hermann Hesse" + }, + { + "content": "The bird of paradise alights only upon the hand that does not grasp.", + "author": "John Berry" + }, + { + "content": "What we see depends mainly on what we look for.", + "author": "John Lubbock" + }, + { + "content": "I have done my best: that is about all the philosophy of living one needs.", + "author": "Lin Yutang" + }, + { + "content": "To be fully alive, fully human, and completely awake is to be continually thrown out of the nest.", + "author": "Pema Chödrön" + }, + { + "content": "Every problem has a gift for you in its hands.", + "author": "Richard Bach" + }, + { + "content": "Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.", + "author": "Samuel Beckett" + }, + { + "content": "Where there is charity and wisdom, there is neither fear nor ignorance.", + "author": "Francis of Assisi" + }, + { + "content": "It is a common experience that a problem difficult at night is resolved in the morning after the committee of sleep has worked on it.", + "author": "John Steinbeck" + }, + { + "content": "It is impossible to love and to be wise.", + "author": "Francis Bacon" + }, + { + "content": "Wisdom is a kind of knowledge. It is knowledge of the nature, career, and consequences of human values.", + "author": "Sidney Hook" + }, + { + "content": "The real danger is not that computers will begin to think like men, but that men will begin to think like computers.", + "author": "Sydney J. Harris" + }, + { + "content": "When the world is so complicated, the simple gift of friendship is within all of our hands.", + "author": "Maria Shriver" + }, + { + "content": "Friendship marks a life even more deeply than love. Love risks degenerating into obsession, friendship is never anything but sharing.", + "author": "Elie Wiesel" + }, + { + "content": "Never apologize for showing feelings. When you do so, you apologize for the truth.", + "author": "Benjamin Disraeli" + }, + { + "content": "The person who makes a success of living is the one who see his goal steadily and aims for it unswervingly. That is dedication.", + "author": "Cecil B. DeMille" + }, + { + "content": "Be slow of tongue and quick of eye.", + "author": "Miguel de Cervantes" + }, + { + "content": "The first duty of a human being is to assume the right functional relationship to society - more briefly, to find your real job, and do it.", + "author": "Charlotte Perkins Gilman" + }, + { + "content": "It takes courage to grow up and become who you really are.", + "author": "E. E. Cummings" + }, + { + "content": "All that we see or seem is but a dream within a dream.", + "author": "Edgar Allan Poe" + }, + { + "content": "We love life, not because we are used to living but because we are used to loving.", + "author": "Friedrich Nietzsche" + }, + { + "content": "It has never been my object to record my dreams, just to realize them.", + "author": "Man Ray" + }, + { + "content": "Time is the wisest counsellor of all.", + "author": "Pericles" + }, + { + "content": "We are not animals. We are not a product of what has happened to us in our past. We have the power of choice.", + "author": "Stephen Covey" + }, + { + "content": "History will be kind to me for I intend to write it.", + "author": "Winston Churchill" + }, + { + "content": "Believe in yourself! Have faith in your abilities! Without a humble but reasonable confidence in your own powers you cannot be successful or happy.", + "author": "Norman Vincent Peale" + }, + { + "content": "Do not wait; the time will never be 'just right.' Start where you stand, and work with whatever tools you may have at your command, and better tools will be found as you go along.", + "author": "George Herbert" + }, + { + "content": "Silence at the proper season is wisdom, and better than any speech.", + "author": "Plutarch" + }, + { + "content": "Wisdom is always an overmatch for strength.", + "author": "Phil Jackson" + }, + { + "content": "Being entirely honest with oneself is a good exercise.", + "author": "Sigmund Freud" + }, + { + "content": "I will give you a definition of a proud man: he is a man who has neither vanity nor wisdom one filled with hatreds cannot be vain, neither can he be wise.", + "author": "John Keats" + }, + { + "content": "Wisdom consists of the anticipation of consequences.", + "author": "Norman Cousins" + }, + { + "content": "Value your friendship. Value your relationships.", + "author": "Barbara Bush" + }, + { + "content": "I have no special talent. I am only passionately curious.", + "author": "Albert Einstein" + }, + { + "content": "Life shrinks or expands in proportion to one's courage.", + "author": "Anaïs Nin" + }, + { + "content": "Experience keeps a dear school, but fools will learn in no other.", + "author": "Benjamin Franklin" + }, + { + "content": "Holding on to anger is like grasping a hot coal with the intent of throwing it at someone else; you are the one who gets burned.", + "author": "Buddha" + }, + { + "content": "Imagination will often carry us to worlds that never were. But without it we go nowhere.", + "author": "Carl Sagan" + }, + { + "content": "A lot of people give up just before theyre about to make it. You know you never know when that next obstacle is going to be the last one.", + "author": "Chuck Norris" + }, + { + "content": "The greater part of human pain is unnecessary. It is self-created as long as the unobserved mind runs your life.", + "author": "Eckhart Tolle" + }, + { + "content": "Those who dream by day are cognizant of many things which escape those who dream only by night.", + "author": "Edgar Allan Poe" + }, + { + "content": "If you focus on results, you will never change. If you focus on change, you will get results.", + "author": "Jack Dixon" + }, + { + "content": "In rivers, the water that you touch is the last of what has passed and the first of that which comes; so with present time.", + "author": "Leonardo da Vinci" + }, + { + "content": "Accept the things to which fate binds you and love the people with whom fate brings you together but do so with all your heart.", + "author": "Marcus Aurelius" + }, + { + "content": "The secret of getting ahead is getting started.", + "author": "Mark Twain" + }, + { + "content": "The truest wisdom is a resolute determination.", + "author": "Napoleon" + }, + { + "content": "Imagination rules the world.", + "author": "Napoleon" + }, + { + "content": "Take time to deliberate, but when the time for action has arrived, stop thinking and go in.", + "author": "Napoleon" + }, + { + "content": "Never deny a diagnosis but do deny the negative verdict that may go with it.", + "author": "Norman Cousins" + }, + { + "content": "People are not lazy. They simply have impotent goals - that is, goals that do not inspire them.", + "author": "Tony Robbins" + }, + { + "content": "When you judge another, you do not define them, you define yourself.", + "author": "Wayne Dyer" + }, + { + "content": "Motivation is the art of getting people to do what you want them to do because they want to do it.", + "author": "Dwight D. Eisenhower" + }, + { + "content": "I know not age, nor weariness nor defeat.", + "author": "Rose Kennedy" + }, + { + "content": "There is no passion to be found playing small - in settling for a life that is less than the one you are capable of living.", + "author": "Nelson Mandela" + }, + { + "content": "We are wiser than we know.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Start with what is right rather than what is acceptable.", + "author": "Franz Kafka" + }, + { + "content": "We're born alone, we live alone, we die alone. Only through our love and friendship can we create the illusion for the moment that we're not alone.", + "author": "Orson Welles" + }, + { + "content": "Love is like a friendship caught on fire. In the beginning a flame, very pretty, often hot and fierce, but still only light and flickering. As love grows older, our hearts mature and our love becomes as coals, deep-burning and unquenchable.", + "author": "Bruce Lee" + }, + { + "content": "The essence of true friendship is to make allowance for another's little lapses.", + "author": "Ovid" + }, + { + "content": "A friend in power is a friend lost.", + "author": "Henry Adams" + }, + { + "author": "Woody Allen", + "content": "I can't listen to that much Wagner. I start getting the urge to conquer Poland." + }, + { + "content": "Anyone who doesn't take truth seriously in small matters cannot be trusted in large ones either.", + "author": "Albert Einstein" + }, + { + "content": "It is better to understand a little than to misunderstand a lot.", + "author": "Anatole France" + }, + { + "content": "All know the way; few actually walk it.", + "author": "Bodhidharma" + }, + { + "content": "To keep the body in good health is a duty... otherwise we shall not be able to keep our mind strong and clear.", + "author": "Buddha" + }, + { + "content": "I am not bothered by the fact that I am unknown. I am bothered when I do not know others.", + "author": "Confucius" + }, + { + "content": "It is common sense to take a method and try it. If it fails, admit it frankly and try another. But above all, try something.", + "author": "Franklin D. Roosevelt" + }, + { + "content": "If the shoe doesn't fit, must we change the foot?", + "author": "Gloria Steinem" + }, + { + "content": "The moment one gives close attention to anything, it becomes a mysterious, awesome, indescribably magnificent world in itself.", + "author": "Henry Miller" + }, + { + "content": "To free us from the expectations of others, to give us back to ourselves... there lies the great, singular power of self-respect.", + "author": "Joan Didion" + }, + { + "content": "If you have made mistakes, there is always another chance for you. You may have a fresh start any moment you choose.", + "author": "Mary Pickford" + }, + { + "content": "Freedom is not worth having if it does not connote freedom to err.", + "author": "Mahatma Gandhi" + }, + { + "content": "Think how hard physics would be if particles could think.", + "author": "Murray Gell-Mann" + }, + { + "content": "I seek constantly to improve my manners and graces, for they are the sugar to which all are attracted.", + "author": "Og Mandino" + }, + { + "content": "Failure will never overtake me if my determination to succeed is strong enough.", + "author": "Og Mandino" + }, + { + "content": "All action results from thought, so it is thoughts that matter.", + "author": "Sai Baba" + }, + { + "content": "Wisdom begins in wonder.", + "author": "Socrates" + }, + { + "_id": "sXDz-2N4-nnJ", + "content": "An invasion of armies can be resisted, but not an idea whose time has come.", + "author": "Victor Hugo" + }, + { + "content": "When you dance, your purpose is not to get to a certain place on the floor. It's to enjoy each step along the way.", + "author": "Wayne Dyer" + }, + { + "content": "Maxim for life: You get treated in life the way you teach people to treat you.", + "author": "Wayne Dyer" + }, + { + "content": "Speak low, if you speak love.", + "author": "William Shakespeare" + }, + { + "content": "Sometimes I am happy and sometimes not. I am, after all, a human being, you know. And I am glad that we are sometimes happy and sometimes not. You get your wisdom working by having different emotions.", + "author": "Yoko Ono" + }, + { + "content": "Even if you're on the right track, you'll get run over if you just sit there.", + "author": "Will Rogers" + }, + { + "content": "The higher we are placed, the more humbly we should walk.", + "author": "Cicero" + }, + { + "content": "It's easier to resist at the beginning than at the end.", + "author": "Leonardo da Vinci" + }, + { + "content": "It is not so much our friends' help that helps us, as the confidence of their help.", + "author": "Epicurus" + }, + { + "content": "If there is such a thing as a good marriage, it is because it resembles friendship rather than love.", + "author": "Michel de Montaigne" + }, + { + "content": "The industrial landscape is already littered with remains of once successful companies that could not adapt their strategic vision to altered conditions of competition.", + "author": "Ralph Abernathy" + }, + { + "content": "Parents can only give good advice or put them on the right paths, but the final forming of a person's character lies in their own hands.", + "author": "Anne Frank" + }, + { + "content": "Every man takes the limits of his own field of vision for the limits of the world.", + "author": "Arthur Schopenhauer" + }, + { + "content": "Thousands of candles can be lit from a single, and the life of the candle will not be shortened. Happiness never decreases by being shared.", + "author": "Buddha" + }, + { + "content": "If you lose today, win tomorrow. In this never-ending spirit of challenge is the heart of a victor.", + "author": "Daisaku Ikeda" + }, + { + "content": "I can't change the direction of the wind, but I can adjust my sails to always reach my destination.", + "author": "Jimmy Dean" + }, + { + "content": "Your sacred space is where you can find yourself again and again.", + "author": "Joseph Campbell" + }, + { + "content": "Where there is love there is life.", + "author": "Mahatma Gandhi" + }, + { + "content": "Kindness is the language which the deaf can hear and the blind can see.", + "author": "Mark Twain" + }, + { + "content": "To get the full value of joy you must have someone to divide it with.", + "author": "Mark Twain" + }, + { + "content": "For every failure, there's an alternative course of action. You just have to find it. When you come to a roadblock, take a detour.", + "author": "Mary Kay Ash" + }, + { + "content": "Action is the foundational key to all success.", + "author": "Pablo Picasso" + }, + { + "content": "All children are artists. The problem is how to remain an artist once he grows up.", + "author": "Pablo Picasso" + }, + { + "content": "Truth, and goodness, and beauty are but different faces of the same all.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Bad things are not the worst things that can happen to us. Nothing is the worst thing that can happen to us!", + "author": "Richard Bach" + }, + { + "content": "When we are no longer able to change a situation - we are challenged to change ourselves.", + "author": "Viktor Frankl" + }, + { + "content": "You can't cross the sea merely by standing and staring at the water.", + "author": "Rabindranath Tagore" + }, + { + "content": "The sum of wisdom is that time is never lost that is devoted to work.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "If you only have a hammer, you tend to see every problem as a nail.", + "author": "Abraham Maslow" + }, + { + "content": "Friends... they cherish one another's hopes. They are kind to one another's dreams.", + "author": "Henry David Thoreau" + }, + { + "content": "Love is flower like; Friendship is like a sheltering tree.", + "author": "Samuel Taylor Coleridge" + }, + { + "content": "Forgiveness is that subtle thread that binds both love and friendship. Without forgiveness, you may not even have a child one day.", + "author": "George Foreman" + }, + { + "content": "Friendship is the marriage of the soul, and this marriage is liable to divorce.", + "author": "Voltaire" + }, + { + "content": "Fear makes strangers of people who would be friends.", + "author": "Shirley MacLaine" + }, + { + "content": "Friendship is an arrangement by which we undertake to exchange small favors for big ones.", + "author": "Montesquieu" + }, + { + "content": "If A is success in life, then A equals x plus y plus z. Work is x; y is play; and z is keeping your mouth shut.", + "author": "Albert Einstein" + }, + { + "content": "Love at first sight is easy to understand; it's when two people have been looking at each other for a lifetime that it becomes a miracle.", + "author": "Amy Bloom" + }, + { + "content": "I know but one freedom and that is the freedom of the mind.", + "author": "Antoine de Saint-Exupéry" + }, + { + "content": "The shoe that fits one person pinches another; there is no recipe for living that suits all cases.", + "author": "Carl Jung" + }, + { + "content": "The man who trusts men will make fewer mistakes than he who distrusts them.", + "author": "Camillo Benso, Count of Cavour" + }, + { + "content": "Beware of missing chances; otherwise it may be altogether too late someday.", + "author": "Franz Liszt" + }, + { + "content": "Be the chief but never the lord.", + "author": "Laozi" + }, + { + "content": "To see things in the seed, that is genius.", + "author": "Laozi" + }, + { + "content": "There is nothing happens to any person but what was in his power to go through with.", + "author": "Marcus Aurelius" + }, + { + "content": "You can do it if you believe you can!", + "author": "Napoleon Hill" + }, + { + "content": "Ask yourself the secret of your success. Listen to your answer and practice it.", + "author": "Richard Bach" + }, + { + "content": "Be as you wish to seem.", + "author": "Socrates" + }, + { + "content": "Smile, breathe and go slowly.", + "author": "Thích Nhất Hạnh" + }, + { + "content": "Successful people ask better questions, and as a result, they get better answers.", + "author": "Tony Robbins" + }, + { + "content": "Doing what you love is the cornerstone of having abundance in your life.", + "author": "Wayne Dyer" + }, + { + "content": "Step with care and great tact and remember that Life's a Great Balancing Act.", + "author": "Dr. Seuss" + }, + { + "content": "Our shared values define us more than our differences. And acknowledging those shared values can see us through our challenges today if we have the wisdom to trust in them again.", + "author": "John McCain" + }, + { + "content": "But what is liberty without wisdom, and without virtue? It is the greatest of all possible evils; for it is folly, vice, and madness, without tuition or restraint.", + "author": "Edmund Burke" + }, + { + "content": "The lure of the distant and the difficult is deceptive. The great opportunity is where you are.", + "author": "John Burroughs" + }, + { + "content": "All wisdom does not reside in Delhi.", + "author": "P. Chidambaram" + }, + { + "content": "Technology is teaching us to be human again.", + "author": "Simon Mainwaring" + }, + { + "content": "Two of man's basic needs are to love and to share. Both of these needs are satisfied in greater or lesser degree by friendship.", + "author": "Mother Angelica" + }, + { + "content": "Important principles may, and must, be inflexible.", + "author": "Abraham Lincoln" + }, + { + "content": "Criticism is something you can easily avoid by saying nothing, doing nothing, and being nothing.", + "author": "Aristotle" + }, + { + "content": "One secret of success in life is for a man to be ready for his opportunity when it comes.", + "author": "Benjamin Disraeli" + }, + { + "content": "If you love life, don't waste time, for time is what life is made up of.", + "author": "Bruce Lee" + }, + { + "content": "Those who are free of resentful thoughts surely find peace.", + "author": "Buddha" + }, + { + "content": "No matter how hard the past, you can always begin again.", + "author": "Buddha" + }, + { + "content": "Meditation brings wisdom, lack of meditation leaves ignorance. Know well what leads you forward and what holds you back and choose the path that leads to wisdom.", + "author": "Buddha" + }, + { + "content": "Error is discipline through which we advance.", + "author": "William Ellery Channing" + }, + { + "content": "It's not what happens to you, but how you react to it that matters.", + "author": "Epictetus" + }, + { + "content": "There is no retirement for an artist, it's your way of living so there is no end to it.", + "author": "Henry Moore" + }, + { + "content": "Fortune befriends the bold.", + "author": "John Dryden" + }, + { + "content": "The minute you settle for less than you deserve, you get even less than you settled for.", + "author": "Maureen Dowd" + }, + { + "content": "Opportunity often comes disguised in the form of misfortune, or temporary defeat.", + "author": "Napoleon Hill" + }, + { + "content": "Education is the most powerful weapon which you can use to change the world.", + "author": "Nelson Mandela" + }, + { + "content": "He can who thinks he can, and he can't who thinks he can't. This is an inexorable, indisputable law.", + "author": "Pablo Picasso" + }, + { + "content": "Self-trust is the first secret of success.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Argue for your limitations, and sure enough they're yours.", + "author": "Richard Bach" + }, + { + "content": "In order to win, you must expect to win.", + "author": "Richard Bach" + }, + { + "content": "Listen to what you know instead of what you fear.", + "author": "Richard Bach" + }, + { + "content": "Work like you don't need the money. Love like you've never been hurt. Dance like nobody's watching.", + "author": "Satchel Paige" + }, + { + "content": "There is no way to happiness, happiness is the way.", + "author": "Thích Nhất Hạnh" + }, + { + "content": "Success is not final; failure is not fatal: it is the courage to continue that counts.", + "author": "Winston Churchill" + }, + { + "content": "Most of our pocket wisdom is conceived for the use of mediocre people, to discourage them from ambitious attempts, and generally console them in their mediocrity.", + "author": "Robert Louis Stevenson" + }, + { + "content": "It is one of the severest tests of friendship to tell your friend his faults. So to love a man that you cannot bear to see a stain upon him, and to speak painful truth through loving words, that is friendship.", + "author": "Henry Ward Beecher" + }, + { + "content": "I destroy my enemies when I make them my friends.", + "author": "Abraham Lincoln" + }, + { + "content": "If we had no winter, the spring would not be so pleasant; if we did not sometimes taste of adversity, prosperity would not be so welcome.", + "author": "Anne Bradstreet" + }, + { + "content": "The mind is everything. What you think you become.", + "author": "Buddha" + }, + { + "content": "If you propose to speak, always ask yourself, is it true, is it necessary, is it kind.", + "author": "Buddha" + }, + { + "content": "Your vision will become clear only when you can look into your own heart. Who looks outside, dreams, who looks inside, awakes.", + "author": "Carl Jung" + }, + { + "content": "The more you know yourself, the more you forgive yourself.", + "author": "Confucius" + }, + { + "content": "The superior man is modest in his speech but exceeds in his actions.", + "author": "Confucius" + }, + { + "content": "When you meet someone better than yourself, turn your thoughts to becoming his equal. When you meet someone not as good as you are, look within and examine your own self.", + "author": "Confucius" + }, + { + "content": "Gratitude is the fairest blossom which springs from the soul.", + "author": "Henry K. Beecher" + }, + { + "content": "The moment one gives close attention to anything, even a blade of grass, it becomes a mysterious, awesome, indescribably magnificent world in itself.", + "author": "Henry Miller" + }, + { + "content": "People may doubt what you say, but they will believe what you do.", + "author": "Lewis Cass" + }, + { + "content": "Stay away from what might have been and look at what will be.", + "author": "Marsha Petrie Sue" + }, + { + "content": "If we learn to open our hearts, anyone, including the people who drive us crazy, can be our teacher.", + "author": "Pema Chödrön" + }, + { + "content": "The world makes way for the man who knows where he is going.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Learning is finding out what you already know.", + "author": "Richard Bach" + }, + { + "content": "Much wisdom often goes with fewer words.", + "author": "Sophocles" + }, + { + "content": "Simply put, you believer that things or people make you unhappy, but this is not accurate. You make yourself unhappy.", + "author": "Wayne Dyer" + }, + { + "content": "If you find yourself in a hole, the first thing to do is stop digging.", + "author": "Will Rogers" + }, + { + "content": "You can observe a lot just by watching.", + "author": "Yogi Berra" + }, + { + "content": "I can, therefore I am.", + "author": "Simone Weil" + }, + { + "content": "Pure, holy simplicity confounds all the wisdom of this world and the wisdom of the flesh.", + "author": "Francis of Assisi" + }, + { + "content": "The ultimate promise of technology is to make us master of a world that we command by the push of a button.", + "author": "Volker Grassmuck" + }, + { + "content": "A real friend is one who walks in when the rest of the world walks out.", + "author": "Walter Winchell" + }, + { + "content": "Love is blind; friendship closes its eyes.", + "author": "Friedrich Nietzsche" + }, + { + "content": "Friendship with oneself is all important, because without it one cannot be friends with anyone else in the world.", + "author": "Eleanor Roosevelt" + }, + { + "content": "Friendship always benefits; love sometimes injures.", + "author": "Seneca the Younger" + }, + { + "author": "Woody Allen", + "content": "How is it possible to find meaning in a finite world, given my waist and shirt size?" + }, + { + "content": "Truth is generally the best vindication against slander.", + "author": "Abraham Lincoln" + }, + { + "content": "To accomplish great things, we must dream as well as act.", + "author": "Anatole France" + }, + { + "content": "No one has ever become poor by giving.", + "author": "Anne Frank" + }, + { + "content": "Without this playing with fantasy no creative work has ever yet come to birth. The debt we owe to the play of the imagination is incalculable.", + "author": "Carl Jung" + }, + { + "content": "The important thing is this: to be able at any moment to sacrifice what we are for what we could become.", + "author": "Charles Du Bos" + }, + { + "content": "Reviewing what you have learned and learning anew, you are fit to be a teacher.", + "author": "Confucius" + }, + { + "content": "The past has no power to stop you from being present now. Only your grievance about the past can do that.", + "author": "Eckhart Tolle" + }, + { + "content": "Without leaps of imagination, or dreaming, we lose the excitement of possibilities. Dreaming, after all, is a form of planning.", + "author": "Gloria Steinem" + }, + { + "content": "Never bend your head. Always hold it high. Look the world right in the eye.", + "author": "Helen Keller" + }, + { + "content": "You cannot step twice into the same river, for other waters are continually flowing in.", + "author": "Heraclitus" + }, + { + "content": "Things turn out best for those who make the best of the way things turn out.", + "author": "Jack Buck" + }, + { + "content": "Man is not sum of what he has already, but rather the sum of what he does not yet have, of what he could have.", + "author": "Jean-Paul Sartre" + }, + { + "content": "Everything that happens as it should, and if you observe carefully, you will find this to be so.", + "author": "Marcus Aurelius" + }, + { + "content": "Everything we hear is an opinion, not a fact. Everything we see is a perspective, not the truth.", + "author": "Marcus Aurelius" + }, + { + "content": "A thing long expected takes the form of the unexpected when at last it comes.", + "author": "Mark Twain" + }, + { + "content": "Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do.", + "author": "Mark Twain" + }, + { + "content": "Better be ignorant of a matter than half know it.", + "author": "Publilius Syrus" + }, + { + "content": "Our lives are a sum total of the choices we have made.", + "author": "Wayne Dyer" + }, + { + "content": "Were here for a reason. I believe a bit of the reason is to throw little torches out to lead people through the dark.", + "author": "Whoopi Goldberg" + }, + { + "content": "True silence is the rest of the mind; it is to the spirit what sleep is to the body, nourishment and refreshment.", + "author": "William Penn" + }, + { + "content": "Spectacular achievement is always preceded by unspectacular preparation.", + "author": "Robert Schuller" + }, + { + "content": "The saddest aspect of life right now is that science gathers knowledge faster than society gathers wisdom.", + "author": "Isaac Asimov" + }, + { + "content": "The attempt to combine wisdom and power has only rarely been successful and then only for a short while.", + "author": "Albert Einstein" + }, + { + "content": "True friendship multiplies the good in life and divides its evils. Strive to have friends, for life without friends is like life on a desert island... to find one real friend in a lifetime is good fortune; to keep him is a blessing.", + "author": "Baltasar Gracián" + }, + { + "content": "Read as you taste fruit or savor wine, or enjoy friendship, love or life.", + "author": "George Herbert" + }, + { + "content": "Constant kindness can accomplish much. As the sun makes ice melt, kindness causes misunderstanding, mistrust, and hostility to evaporate.", + "author": "Albert Schweitzer" + }, + { + "content": "How wonderful it is that nobody need wait a single moment before starting to improve the world.", + "author": "Anne Frank" + }, + { + "content": "What we think, we become.", + "author": "Buddha" + }, + { + "content": "Just as a candle cannot burn without fire, men cannot live without a spiritual life.", + "author": "Buddha" + }, + { + "content": "To study and not think is a waste. To think and not study is dangerous.", + "author": "Confucius" + }, + { + "content": "The only person who never makes mistakes is the person who never does anything.", + "author": "Denis Waitley" + }, + { + "content": "The greatest mistake you can make in life is to be continually fearing you will make one.", + "author": "Elbert Hubbard" + }, + { + "content": "The future belongs to those who believe in the beauty of their dreams.", + "author": "Eleanor Roosevelt" + }, + { + "content": "Life is what you make of it. Always has been, always will be.", + "author": "Grandma Moses" + }, + { + "content": "I have just three things to teach: simplicity, patience, compassion. These three are your greatest treasures.", + "author": "Laozi" + }, + { + "content": "Our virtues and our failings are inseparable, like force and matter. When they separate, man is no more.", + "author": "Nikola Tesla" + }, + { + "content": "I am always doing that which I cannot do, in order that I may learn how to do it.", + "author": "Pablo Picasso" + }, + { + "content": "It is one of the blessings of old friends that you can afford to be stupid with them.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Happiness is a perfume you cannot pour on others without getting a few drops on yourself.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "The most complicated achievements of thought are possible without the assistance of consciousness.", + "author": "Sigmund Freud" + }, + { + "content": "If you can dream it, you can do it.", + "author": "Walt Disney" + }, + { + "content": "To be happy is to be able to become aware of oneself without fright.", + "author": "Walter Benjamin" + }, + { + "content": "Ideals are an imaginative understanding of that which is desirable in that which is possible.", + "author": "Walter Lippmann" + }, + { + "content": "You are important enough to ask and you are blessed enough to receive back.", + "author": "Wayne Dyer" + }, + { + "content": "We make a living by what we get, but we make a life by what we give.", + "author": "Winston Churchill" + }, + { + "content": "We are made wise not by the recollection of our past, but by the responsibility for our future.", + "author": "Bernard Shaw" + }, + { + "content": "In the sweetness of friendship let there be laughter and sharing of pleasures. For in the dew of little things the heart finds its morning and is refreshed.", + "author": "Kahlil Gibran" + }, + { + "content": "Friendship... is not something you learn in school. But if you haven't learned the meaning of friendship, you really haven't learned anything.", + "author": "Muhammad Ali" + }, + { + "content": "Love, friendship and respect do not unite people as much as a common hatred for something.", + "author": "Anton Chekhov" + }, + { + "content": "Some people go to priests; others to poetry; I to my friends.", + "author": "Virginia Woolf" + }, + { + "content": "Good advice is always certain to be ignored, but that's no reason not to give it.", + "author": "Agatha Christie" + }, + { + "content": "There is not one big cosmic meaning for all, there is only the meaning we each give to our life.", + "author": "Anaïs Nin" + }, + { + "content": "Tell me and I forget. Teach me and I remember. Involve me and I learn.", + "author": "Benjamin Franklin" + }, + { + "content": "Man is equally incapable of seeing the nothingness from which he emerges and the infinity in which he is engulfed.", + "author": "Blaise Pascal" + }, + { + "content": "There is nothing in a caterpillar that tells you it's going to be a butterfly.", + "author": "Buckminster Fuller" + }, + { + "content": "Peace comes from within. Do not seek it without.", + "author": "Buddha" + }, + { + "content": "The most beautiful things in the world cannot be seen or even touched. They must be felt with the heart.", + "author": "Helen Keller" + }, + { + "content": "If you don't design your own life plan, chances are you'll fall into someone else's plan. And guess what they have planned for you? Not much.", + "author": "Jim Rohn" + }, + { + "content": "Those who dare to fail miserably can achieve greatly.", + "author": "John F. Kennedy" + }, + { + "content": "The key to growth is the introduction of higher dimensions of consciousness into our awareness.", + "author": "Laozi" + }, + { + "content": "Aerodynamically the bumblebee shouldn't be able to fly, but the bumblebee doesn't know that, so it goes on flying anyway.", + "author": "Mary Kay Ash" + }, + { + "content": "The greatest danger for most of us is not that our aim is too high, and we miss it, but that it is too low, and we reach it.", + "author": "Michelangelo" + }, + { + "content": "Lots of people want to ride with you in the limo, but what you want is someone who will take the bus with you when the limo breaks down.", + "author": "Oprah Winfrey" + }, + { + "content": "I begin with an idea and then it becomes something else.", + "author": "Pablo Picasso" + }, + { + "content": "Happiness is the reward we get for living to the highest right we know.", + "author": "Richard Bach" + }, + { + "content": "Wisdom is the supreme part of happiness.", + "author": "Sophocles" + }, + { + "content": "Think for yourselves and let others enjoy the privilege to do so too.", + "author": "Voltaire" + }, + { + "content": "I cannot always control what goes on outside. But I can always control what goes on inside.", + "author": "Wayne Dyer" + }, + { + "content": "I'd rather attempt to do something great and fail than to attempt to do nothing and succeed.", + "author": "Robert Schuller" + }, + { + "content": "The greatest obstacle to discovery is not ignorance - it is the illusion of knowledge.", + "author": "Daniel J. Boorstin" + }, + { + "content": "Wisdom cannot come by railroad or automobile or airplane or be hurried up by telegraph or telephone.", + "author": "John Burroughs" + }, + { + "content": "Know what's important and what isn't. Have the wisdom to know the right thing to do, the integrity to do it, the character to stand up to those who don't, and the courage to stop those who won't.", + "author": "Mark Goulston" + }, + { + "content": "Logic is the beginning of wisdom, not the end.", + "author": "Leonard Nimoy" + }, + { + "content": "One's life has value so long as one attributes value to the life of others, by means of love, friendship, indignation and compassion.", + "author": "Simone de Beauvoir" + }, + { + "content": "I walk slowly, but I never walk backward.", + "author": "Abraham Lincoln" + }, + { + "content": "The happiness of a man in this life does not consist in the absence but in the mastery of his passions.", + "author": "Alfred Tennyson" + }, + { + "content": "The secret of success is constancy to purpose.", + "author": "Benjamin Disraeli" + }, + { + "content": "When you realize how perfect everything is you will tilt your head back and laugh at the sky.", + "author": "Buddha" + }, + { + "content": "I do not believe in a fate that falls on men however they act; but I do believe in a fate that falls on them unless they act.", + "author": "G. K. Chesterton" + }, + { + "content": "Everything that irritates us about others can lead us to an understanding of ourselves.", + "author": "Carl Jung" + }, + { + "content": "Genuine love should first be directed at oneself; if we do not love ourselves, how can we love others?", + "author": "Dalai Lama" + }, + { + "content": "Happiness mainly comes from our own attitude, rather than from external factors.", + "author": "Dalai Lama" + }, + { + "content": "I believe that we are solely responsible for our choices, and we have to accept the consequences of every deed, word, and thought throughout our lifetime.", + "author": "Elisabeth Kübler-Ross" + }, + { + "content": "Make the best use of what is in your power and take the rest as it happens.", + "author": "Epictetus" + }, + { + "content": "I am a man of fixed and unbending principles, the first of which is to be flexible at all times.", + "author": "Everett Dirksen" + }, + { + "content": "The best and most beautiful things in the world cannot be seen, nor touched... but are felt in the heart.", + "author": "Helen Keller" + }, + { + "content": "If you must tell me your opinions, tell me what you believe in. I have plenty of doubts of my own.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "Gratitude makes sense of our past, brings peace for today, and creates a vision for tomorrow.", + "author": "Melody Beattie" + }, + { + "content": "The cause is hidden. The effect is visible to all.", + "author": "Ovid" + }, + { + "content": "The greatest obstacle to connecting with our joy is resentment.", + "author": "Pema Chödrön" + }, + { + "content": "We read the world wrong and say that it deceives us.", + "author": "Rabindranath Tagore" + }, + { + "content": "Each man has his own vocation; his talent is his call. There is one direction in which all space is open to him.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "The place to improve the world is first in one's own heart and head and hands.", + "author": "Robert M. Pirsig" + }, + { + "content": "It is in your moments of decision that your destiny is shaped.", + "author": "Tony Robbins" + }, + { + "content": "I never worry about action, but only inaction.", + "author": "Winston Churchill" + }, + { + "content": "You are the only person on earth who can use your ability.", + "author": "Zig Ziglar" + }, + { + "content": "By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest.", + "author": "Confucius" + }, + { + "content": "Music is a higher revelation than all wisdom and philosophy.", + "author": "Ludwig van Beethoven" + }, + { + "content": "Along with success comes a reputation for wisdom.", + "author": "Euripides" + }, + { + "content": "If you have one true friend, you have more than your share.", + "author": "Thomas Fuller" + }, + { + "content": "There are no strangers here; Only friends you haven't yet met.", + "author": "William Butler Yeats" + }, + { + "content": "Marriage is the highest state of friendship. If happy, it lessens our cares by dividing them, at the same time that it doubles our pleasures by mutual participation.", + "author": "Samuel Richardson" + }, + { + "content": "A friend may well be reckoned the masterpiece of nature.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "It is important to our friends to believe that we are unreservedly frank with them, and important to friendship that we are not.", + "author": "Mignon McLaughlin" + }, + { + "author": "Woody Allen", + "content": "I don't want to achieve immortality through my work... I want to achieve it through not dying." + }, + { + "author": "Woody Allen", + "content": "I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me." + }, + { + "content": "No valid plans for the future can be made by those who have no capacity for living now.", + "author": "Alan Watts" + }, + { + "content": "He who angers you conquers you.", + "author": "Elizabeth Kenny" + }, + { + "content": "One needs something to believe in, something for which one can have whole-hearted enthusiasm. One needs to feel that one's life has meaning, that one is needed in this world.", + "author": "Hannah Szenes" + }, + { + "content": "We could never learn to be brave and patient if there were only joy in the world.", + "author": "Helen Keller" + }, + { + "content": "Almost everything comes from nothing.", + "author": "Henri-Frédéric Amiel" + }, + { + "content": "In the end we retain from our studies only that which we practically apply.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "Happiness often sneaks in through a door you didn't know you left open.", + "author": "John Barrymore" + }, + { + "content": "The journey of a thousand miles begins with one step.", + "author": "Laozi" + }, + { + "content": "Always tell the truth. That way, you don't have to remember what you said.", + "author": "Mark Twain" + }, + { + "content": "Whoever is happy will make others happy, too.", + "author": "Mark Twain" + }, + { + "content": "Life's most persistent and urgent question is, 'What are you doing for others?'", + "author": "Martin Luther King Jr." + }, + { + "content": "Do not wait for leaders; do it alone, person to person.", + "author": "Mother Teresa" + }, + { + "content": "The best cure for the body is a quiet mind.", + "author": "Napoleon" + }, + { + "content": "When your desires are strong enough you will appear to possess superhuman powers to achieve.", + "author": "Napoleon Hill" + }, + { + "content": "Men of perverse opinion do not know the excellence of what is in their hands, till someone dash it from them.", + "author": "Sophocles" + }, + { + "content": "Grief can be the garden of compassion. If you keep your heart open through everything, your pain can become your greatest ally in your life's search for love and wisdom.", + "author": "Rumi" + }, + { + "content": "Knowledge speaks, but wisdom listens.", + "author": "Jimi Hendrix" + }, + { + "content": "Knowing others is wisdom, knowing yourself is Enlightenment.", + "author": "Laozi" + }, + { + "content": "Wisdom comes alone through suffering.", + "author": "Aeschylus" + }, + { + "content": "Wisdom is oftentimes nearer when we stoop than when we soar.", + "author": "William Wordsworth" + }, + { + "content": "All this worldly wisdom was once the unamiable heresy of some wise man.", + "author": "Henry David Thoreau" + }, + { + "content": "One machine can do the work of fifty ordinary men. No machine can do the work of one extraordinary man.", + "author": "Elbert Hubbard" + }, + { + "content": "Loyalty and friendship, which is to me the same, created all the wealth that I've ever thought I'd have.", + "author": "Ernie Banks" + }, + { + "content": "Nothing but heaven itself is better than a friend who is really a friend.", + "author": "Plautus" + }, + { + "content": "Friendship is held to be the severest test of character. It is easy, we think, to be loyal to a family and clan, whose blood is in your own veins.", + "author": "Charles Eastman" + }, + { + "content": "Try not to become a man of success, but rather try to become a man of value.", + "author": "Albert Einstein" + }, + { + "content": "Dreams pass into the reality of action. From the actions stems the dream again; and this interdependence produces the highest form of living.", + "author": "Anaïs Nin" + }, + { + "content": "Yesterday is history. Tomorrow is a mystery. And today? Today is a gift. That is why we call it the present.", + "author": "Babatunde Olatunji" + }, + { + "content": "A wise man can learn more from a foolish question than a fool can learn from a wise answer.", + "author": "Bruce Lee" + }, + { + "content": "It is not fair to ask of others what you are unwilling to do yourself.", + "author": "Eleanor Roosevelt" + }, + { + "content": "The truest greatness lies in being kind, the truest wisdom in a happy mind.", + "author": "Ella Wheeler Wilcox" + }, + { + "content": "Mountains cannot be surmounted except by winding paths.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "If your actions inspire others to dream more, learn more, do more and become more, you are a leader.", + "author": "John Quincy Adams" + }, + { + "content": "To lead people walk behind them.", + "author": "Laozi" + }, + { + "content": "When you are content to be simply yourself and don't compare or compete, everybody will respect you.", + "author": "Laozi" + }, + { + "content": "It is the quality of our work which will please God, not the quantity.", + "author": "Mahatma Gandhi" + }, + { + "content": "All great achievements require time.", + "author": "Maya Angelou" + }, + { + "content": "No alibi will save you from accepting the responsibility.", + "author": "Napoleon Hill" + }, + { + "content": "There are no limitations to the mind except those we acknowledge.", + "author": "Napoleon Hill" + }, + { + "content": "All things change; nothing perishes.", + "author": "Ovid" + }, + { + "content": "Build a better mousetrap and the world will beat a path to your door.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Be not angry that you cannot make others as you wish them to be, since you cannot make yourself as you wish to be.", + "author": "Thomas à Kempis" + }, + { + "content": "For everything that lives is holy, life delights in life.", + "author": "William Blake" + }, + { + "_id": "J-Q-UnpXS3G2", + "content": "The pessimist sees difficulty in every opportunity. The optimist sees the opportunity in every difficulty.", + "author": "Winston Churchill" + }, + { + "content": "The will to win, the desire to succeed, the urge to reach your full potential... these are the keys that will unlock the door to personal excellence.", + "author": "Confucius" + }, + { + "content": "The superior man blames himself. The inferior man blames others.", + "author": "Don Shula" + }, + { + "content": "The smallest deed is better than the greatest intention.", + "author": "John Burroughs" + }, + { + "content": "The world is a book, and those who do not travel read only a page.", + "author": "Augustine of Hippo" + }, + { + "content": "The thought manifests as the word. The word manifests as the deed. The deed develops into habit. And the habit hardens into character.", + "author": "Buddha" + }, + { + "content": "We must not say every mistake is a foolish one.", + "author": "Cicero" + }, + { + "content": "The superior man is satisfied and composed; the mean man is always full of distress.", + "author": "Confucius" + }, + { + "content": "When it is obvious that the goals cannot be reached, don't adjust the goals, adjust the action steps.", + "author": "Confucius" + }, + { + "content": "The most important thing is transforming our minds, for a new way of thinking, a new outlook: we should strive to develop a new inner world.", + "author": "Dalai Lama" + }, + { + "content": "Today you are you! That is truer than true! There is no one alive who is you-er than you!", + "author": "Dr. Seuss" + }, + { + "content": "Obstacles are those frightful things you see when you take your eyes off your goal.", + "author": "Henry Ford" + }, + { + "content": "An ant on the move does more than a dozing ox", + "author": "Laozi" + }, + { + "content": "From wonder into wonder existence opens.", + "author": "Laozi" + }, + { + "content": "Cherish your visions and your dreams as they are the children of your soul; the blueprints of your ultimate achievements.", + "author": "Napoleon Hill" + }, + { + "content": "Edison failed 10,000 times before he made the electric light. Do not be discouraged if you fail a few times.", + "author": "Napoleon Hill" + }, + { + "content": "What is a weed? A plant whose virtues have not yet been discovered.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "They can conquer who believe they can.", + "author": "Virgil" + }, + { + "content": "Go for it now. The future is promised to no one.", + "author": "Wayne Dyer" + }, + { + "content": "Difficulties are meant to rouse, not discourage. The human spirit is to grow strong by conflict.", + "author": "William Ellery Channing" + }, + { + "content": "Beginning today, treat everyone you meet as if they were going to be dead by midnight. Extend to them all the care, kindness and understanding you can muster, and do it with no thought of any reward. Your life will never be the same again.", + "author": "Og Mandino" + }, + { + "content": "None knows the weight of another's burden.", + "author": "George Herbert" + }, + { + "content": "To keep your secret is wisdom; but to expect others to keep it is folly.", + "author": "Samuel Johnson" + }, + { + "content": "Walking with a friend in the dark is better than walking alone in the light.", + "author": "Helen Keller" + }, + { + "content": "There are two ways to slide easily through life: to believe everything or to doubt everything; both ways save us from thinking.", + "author": "Alfred Korzybski" + }, + { + "content": "Without passion man is a mere latent force and possibility, like the flint which awaits the shock of the iron before it can give forth its spark.", + "author": "Henri-Frédéric Amiel" + }, + { + "content": "The personal life deeply lived always expands into truths beyond itself.", + "author": "Anaïs Nin" + }, + { + "content": "Life's challenges are not supposed to paralyze you, they're supposed to help you discover who you are.", + "author": "Bernice Reagon" + }, + { + "content": "Everything that irritates us about others can lead us to a better understanding of ourselves.", + "author": "Carl Jung" + }, + { + "content": "A lot of times people look at the negative side of what they feel they can't do. I always look on the positive side of what I can do.", + "author": "Chuck Norris" + }, + { + "content": "Do one thing every day that scares you.", + "author": "Eleanor Roosevelt" + }, + { + "content": "One that desires to excel should endeavor in those things that are in themselves most excellent.", + "author": "Epictetus" + }, + { + "_id": "bEBdLymQ--0t", + "content": "A subtle thought that is in error may yet give rise to fruitful inquiry that can establish truths of great value.", + "author": "Isaac Asimov" + }, + { + "content": "A really great talent finds its happiness in execution.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "He who lives in harmony with himself lives in harmony with the world.", + "author": "Marcus Aurelius" + }, + { + "content": "Joy is what happens to us when we allow ourselves to recognize how good things really are.", + "author": "Marianne Williamson" + }, + { + "content": "Time is the most valuable thing a man can spend.", + "author": "Theophrastus" + }, + { + "content": "An invincible determination can accomplish almost anything and in this lies the great distinction between great men and little men.", + "author": "Thomas Fuller" + }, + { + "content": "Where all think alike, no one thinks very much.", + "author": "Walter Lippmann" + }, + { + "content": "I think and that is all that I am.", + "author": "Wayne Dyer" + }, + { + "content": "If you change the way you look at things, the things you look at change.", + "author": "Wayne Dyer" + }, + { + "content": "To change one's life, start immediately, do it flamboyantly, no exceptions.", + "author": "William James" + }, + { + "content": "Having nothing, nothing can he lose.", + "author": "William Shakespeare" + }, + { + "content": "Quality is not an act; it is a habit.", + "author": "Aristotle" + }, + { + "content": "The young man knows the rules, but the old man knows the exceptions.", + "author": "Oliver Wendell Holmes Jr." + }, + { + "content": "Give me a lever long enough and a fulcrum on which to place it, and I shall move the world.", + "author": "Archimedes" + }, + { + "content": "All this modern technology just makes people try to do everything at once.", + "author": "Bill Watterson" + }, + { + "content": "Sometimes being a friend means mastering the art of timing. There is a time for silence. A time to let go and allow people to hurl themselves into their own destiny. And a time to prepare to pick up the pieces when it's all over.", + "author": "Octavia E. Butler" + }, + { + "content": "Your friend is your needs answered.", + "author": "Kahlil Gibran" + }, + { + "author": "Woody Allen", + "content": "Eighty percent of success is showing up." + }, + { + "content": "When you have got an elephant by the hind legs and he is trying to run away, it's best to let him run.", + "author": "Abraham Lincoln" + }, + { + "content": "How we spend our days is, of course, how we spend our lives.", + "author": "Annie Dillard" + }, + { + "content": "You only lose what you cling to.", + "author": "Buddha" + }, + { + "content": "Life is 10% what happens to you and 90% how you react to it.", + "author": "Chuck Swindoll" + }, + { + "content": "Obstacles are those things you see when you take your eyes off the goal.", + "author": "Hannah More" + }, + { + "content": "The future is completely open, and we are writing it moment to moment.", + "author": "Pema Chödrön" + }, + { + "content": "Never promise more than you can perform.", + "author": "Publilius Syrus" + }, + { + "content": "Good luck is another name for tenacity of purpose.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "If we are not given the chance to forget, we are also not given the chance to recover our memories, to alter them with time, perspective, and wisdom. Forgetting, we can be ourselves beyond what the past has told us we are; we can evolve. That is the possibility we want from the future.", + "author": "Caterina Fake" + }, + { + "content": "Appearances are often deceiving.", + "author": "Aesop" + }, + { + "content": "I think that novels that leave out technology misrepresent life as badly as Victorians misrepresented life by leaving out sex.", + "author": "Kurt Vonnegut" + }, + { + "content": "Technology presumes there's just one right way to do things and there never is.", + "author": "Robert M. Pirsig" + }, + { + "content": "Wishing to be friends is quick work, but friendship is a slow ripening fruit.", + "author": "Aristotle" + }, + { + "content": "Friendship, like the immortality of the soul, is too good to be believed.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "All I required to be happy was friendship and people I could admire.", + "author": "Christian Dior" + }, + { + "_id": "5G-M_-ye7r", + "content": "He who hath many friends hath none.", + "author": "Aristotle" + }, + { + "content": "Imagination is more important than knowledge. For while knowledge defines all we currently know and understand, imagination points to all we might yet discover and create.", + "author": "Albert Einstein" + }, + { + "content": "The greatest pleasure I know is to do a good action by stealth, and to have it found out by accident.", + "author": "Charles Lamb" + }, + { + "content": "To avoid criticism, do nothing, say nothing, be nothing.", + "author": "Elbert Hubbard" + }, + { + "content": "It isn't where you come from, it's where you're going that counts.", + "author": "Ella Fitzgerald" + }, + { + "_id": "Um2MLxmE-Dv-", + "content": "A fine quotation is a diamond on the finger of a man of wit, and a pebble in the hand of a fool.", + "author": "Joseph Roux" + }, + { + "content": "The greatest minds are capable of the greatest vices as well as of the greatest virtues.", + "author": "René Descartes" + }, + { + "content": "Formula for success: under promise and over deliver.", + "author": "Tom Peters" + }, + { + "content": "Love is never lost. If not reciprocated, it will flow back and soften and purify the heart.", + "author": "Washington Irving" + }, + { + "content": "Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time.", + "author": "Thomas Edison" + }, + { + "content": "Without hard work, nothing grows but weeds.", + "author": "Gordon Hinckley" + }, + { + "content": "It's better to be a lion for a day than a sheep all your life.", + "author": "Elizabeth Kenny" + }, + { + "content": "It is unwise to be too sure of one's own wisdom. It is healthy to be reminded that the strongest might weaken and the wisest might err.", + "author": "Mahatma Gandhi" + }, + { + "content": "Never reach out your hand unless you're willing to extend an arm.", + "author": "Pope Paul VI" + }, + { + "content": "Technology frightens me to death. It's designed by engineers to impress other engineers. And they always come with instruction booklets that are written by engineers for other engineers — which is why almost no technology ever works.", + "author": "John Cleese" + }, + { + "content": "Technology… is a queer thing. It brings you great gifts with one hand, and it stabs you in the back with the other.", + "author": "Carrie Snow" + }, + { + "content": "Even an animal, if you show genuine affection, gradually trust develops... If you always showing bad face and beating, how can you develop friendship?", + "author": "Dalai Lama" + }, + { + "content": "What sweetness is left in life, if you take away friendship? Robbing life of friendship is like robbing the world of the sun. A true friend is more to be esteemed than kinsfolk.", + "author": "Cicero" + }, + { + "content": "Through pride we are ever deceiving ourselves. But deep down below the surface of the average conscience a still, small voice says to us, something is out of tune.", + "author": "Carl Jung" + }, + { + "content": "Lord, make me an instrument of thy peace. Where there is hatred, let me sow love.", + "author": "Francis of Assisi" + }, + { + "content": "To be tested is good. The challenged life may be the best therapist.", + "author": "Gail Sheehy" + }, + { + "content": "Sometimes our fate resembles a fruit tree in winter. Who would think that those branches would turn green again and blossom, but we hope it, we know it.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "The wise man does not lay up his own treasures. The more he gives to others, the more he has for his own.", + "author": "Laozi" + }, + { + "content": "The awareness of our own strength makes us modest.", + "author": "Paul Cézanne" + }, + { + "content": "The truth you believe and cling to makes you unavailable to hear anything new.", + "author": "Pema Chödrön" + }, + { + "content": "A good decision is based on knowledge and not on numbers.", + "author": "Plato" + }, + { + "content": "Your friends will know you better in the first minute you meet than your acquaintances will know you in a thousand years.", + "author": "Richard Bach" + }, + { + "content": "Do the difficult things while they are easy and do the great things while they are small. A journey of a thousand miles must begin with a single step.", + "author": "Laozi" + }, + { + "content": "Knowledge without justice ought to be called cunning rather than wisdom.", + "author": "Plato" + }, + { + "content": "Wisdom is found only in truth.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "I prefer the folly of enthusiasm to the indifference of wisdom.", + "author": "Anatole France" + }, + { + "content": "If you do not express your own original ideas, if you do not listen to your own being, you will have betrayed yourself.", + "author": "Rollo May" + }, + { + "content": "Humanity is acquiring all the right technology for all the wrong reasons.", + "author": "Buckminster Fuller" + }, + { + "content": "All of our technology is completely unnecessary to a happy life.", + "author": "Tom Hodgkinson" + }, + { + "content": "Most people are about as happy as they make up their minds to be", + "author": "Abraham Lincoln" + }, + { + "content": "No act of kindness, no matter how small, is ever wasted.", + "author": "Aesop" + }, + { + "content": "The possession of knowledge does not kill the sense of wonder and mystery. There is always more mystery.", + "author": "Anaïs Nin" + }, + { + "content": "If you're walking down the right path and you're willing to keep walking, eventually you'll make progress.", + "author": "Barack Obama" + }, + { + "content": "We don't stop playing because we grow old; we grow old because we stop playing.", + "author": "Bernard Shaw" + }, + { + "content": "Remembering a wrong is like carrying a burden on the mind.", + "author": "Buddha" + }, + { + "content": "A man is great by deeds, not by birth.", + "author": "Chanakya" + }, + { + "content": "Whenever something negative happens to you, there is a deep lesson concealed within it.", + "author": "Eckhart Tolle" + }, + { + "content": "It is impossible for a man to learn what he thinks he already knows.", + "author": "Epictetus" + }, + { + "content": "The only way to tell the truth is to speak with kindness. Only the words of a loving man can be heard.", + "author": "Henry David Thoreau" + }, + { + "content": "When you doubt your power, you give power to your doubt.", + "author": "Honoré de Balzac" + }, + { + "_id": "ff8I--Yqxowc", + "content": "The noblest worship is to make yourself as good and as just as you can.", + "author": "Isocrates" + }, + { + "content": "Sunshine is delicious, rain is refreshing, wind braces us up, snow is exhilarating; there is really no such thing as bad weather, only different kinds of good weather.", + "author": "John Ruskin" + }, + { + "content": "It is through science that we prove, but through intuition that we discover.", + "author": "Henri Poincaré" + }, + { + "content": "To understand the heart and mind of a person, look not at what he has already achieved, but at what he aspires to do.", + "author": "Kahlil Gibran" + }, + { + "content": "Be like the flower, turn your face to the sun.", + "author": "Kahlil Gibran" + }, + { + "content": "Anticipate the difficult by managing the easy.", + "author": "Laozi" + }, + { + "content": "Kind words can be short and easy to speak, but their echoes are truly endless.", + "author": "Mother Teresa" + }, + { + "content": "He who fears being conquered is sure of defeat.", + "author": "Napoleon" + }, + { + "content": "A rolling stone gathers no moss.", + "author": "Publilius Syrus" + }, + { + "content": "Living at risk is jumping off the cliff and building your wings on the way down.", + "author": "Ray Bradbury" + }, + { + "content": "I gave my life to become the person I am right now. Was it worth it?", + "author": "Richard Bach" + }, + { + "content": "Imagination is the living power and prime agent of all human perception.", + "author": "Samuel Taylor Coleridge" + }, + { + "content": "Think in the morning. Act in the noon. Eat in the evening. Sleep in the night.", + "author": "William Blake" + }, + { + "content": "Your attitude, not your aptitude, will determine your altitude.", + "author": "Zig Ziglar" + }, + { + "content": "Learning is the beginning of wealth. Learning is the beginning of health. Learning is the beginning of spirituality. Searching and learning is where the miracle process all begins.", + "author": "Jim Rohn" + }, + { + "content": "Beware of false knowledge; it is more dangerous than ignorance.", + "author": "Bernard Shaw" + }, + { + "content": "A friend to all is a friend to none.", + "author": "Aristotle" + }, + { + "content": "Happiness depends upon ourselves.", + "author": "Aristotle" + }, + { + "content": "There never was a good knife made of bad steel.", + "author": "Benjamin Franklin" + }, + { + "content": "Notice that the stiffest tree is most easily cracked, while the bamboo or willow survives by bending with the wind.", + "author": "Bruce Lee" + }, + { + "content": "Your work is to discover your work and then with all your heart to give yourself to it.", + "author": "Buddha" + }, + { + "content": "Being in humaneness is good. If we select other goodness and thus are far apart from humaneness, how can we be the wise?", + "author": "Confucius" + }, + { + "content": "Small opportunities are often the beginning of great enterprises.", + "author": "Demosthenes" + }, + { + "content": "The poor man is not he who is without a cent, but he who is without a dream.", + "author": "Harry Kemp" + }, + { + "content": "Science is organized knowledge. Wisdom is organized life.", + "author": "Immanuel Kant" + }, + { + "content": "Character develops itself in the stream of life.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "The person born with a talent they are meant to use will find their greatest happiness in using it.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "Kindness is the golden chain by which society is bound together.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "Discovery consists of seeing what everybody has seen and thinking what nobody else has thought.", + "author": "Jonathan Swift" + }, + { + "content": "A goal without a plan is just a wish.", + "author": "Larry Elder" + }, + { + "content": "Learning never exhausts the mind.", + "author": "Leonardo da Vinci" + }, + { + "content": "You need chaos in your soul to give birth to a dancing star.", + "author": "Friedrich Nietzsche" + }, + { + "content": "To be great is to be misunderstood.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Don't be dismayed by good-byes. A farewell is necessary before you can meet again. And meeting again, after moments or lifetimes, is certain for those who are friends.", + "author": "Richard Bach" + }, + { + "_id": "yDgu-x-mFPpU", + "content": "If one does not know to which port is sailing, no wind is favorable.", + "author": "Seneca the Younger" + }, + { + "content": "What lies behind us and what lies before us are tiny matters compared to what lies within us.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "For beautiful eyes, look for the good in others; for beautiful lips, speak only words of kindness; and for poise, walk with the knowledge that you are never alone.", + "author": "Audrey Hepburn" + }, + { + "content": "There is a wisdom of the head, and a wisdom of the heart.", + "author": "Charles Dickens" + }, + { + "content": "Only put off until tomorrow what you are willing to die having left undone.", + "author": "Pablo Picasso" + }, + { + "content": "Imagination allows us to escape the predictable. It enables us to reply to the common wisdom that we cannot soar by saying, 'Just watch!'", + "author": "Bill Bradley" + }, + { + "content": "Once you label me you negate me.", + "author": "Søren Kierkegaard" + }, + { + "content": "We gain the strength of the temptation we resist.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Just because something doesn't do what you planned it to do doesn't mean it's useless.", + "author": "Thomas Edison" + }, + { + "content": "God always takes the simplest way.", + "author": "Albert Einstein" + }, + { + "content": "There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.", + "author": "Albert Einstein" + }, + { + "content": "Imagination disposes of everything; it creates beauty, justice, and happiness, which are everything in this world.", + "author": "Blaise Pascal" + }, + { + "content": "I want you to be everything that's you, deep at the center of your being.", + "author": "Confucius" + }, + { + "content": "Don't cry because it's over. Smile because it happened.", + "author": "Dr. Seuss" + }, + { + "content": "If you seek truth, you will not seek victory by dishonorable means, and if you find truth you will become invincible.", + "author": "Epictetus" + }, + { + "content": "If you do not change direction, you may end up where you are heading.", + "author": "Laozi" + }, + { + "content": "He who is fixed to a star does not change his mind.", + "author": "Leonardo da Vinci" + }, + { + "content": "We aim above the mark to hit the mark.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Patience is the companion of wisdom.", + "author": "Augustine of Hippo" + }, + { + "content": "Don't look back. Something might be gaining on you.", + "author": "Satchel Paige" + }, + { + "content": "A short saying often contains much wisdom.", + "author": "Sophocles" + }, + { + "content": "Keep your eyes on the stars and your feet on the ground.", + "author": "Theodore Roosevelt" + }, + { + "content": "The more man meditates upon good thoughts, the better will be his world and the world at large.", + "author": "Confucius" + }, + { + "content": "By failing to prepare, you are preparing to fail.", + "author": "Benjamin Franklin" + }, + { + "content": "Wisdom is the right use of knowledge. To know is not to be wise. Many men know a great deal and are all the greater fools for it. There is no fool so great a fool as a knowing fool. But to know how to use knowledge is to have wisdom.", + "author": "Charles Spurgeon" + }, + { + "content": "If you talk to a man in a language he understands, that goes to his head. If you talk to him in his language, that goes to his heart.", + "author": "Nelson Mandela" + }, + { + "content": "There are many ways of going forward, but only one way of standing still.", + "author": "Franklin D. Roosevelt" + }, + { + "content": "Think big thoughts but relish small pleasures.", + "author": "H. Jackson Brown Jr." + }, + { + "content": "All human wisdom is summed up in two words; wait and hope.", + "author": "Alexandre Dumas" + }, + { + "content": "Cunning... is but the low mimic of wisdom.", + "author": "Plato" + }, + { + "content": "To wear your heart on your sleeve isn't a very good plan; you should wear it inside, where it functions best.", + "author": "Margaret Thatcher" + }, + { + "content": "The art challenges the technology, and the technology inspires the art.", + "author": "John Lasseter" + }, + { + "content": "I have learned that friendship isn't about who you've known the longest, it's about who came and never left your side.", + "author": "Yolanda Hadid" + }, + { + "content": "A friend is what the heart needs all the time.", + "author": "Henry van Dyke Jr." + }, + { + "content": "Let us sacrifice our today so that our children can have a better tomorrow.", + "author": "A. P. J. Abdul Kalam" + }, + { + "content": "Never say there is nothing beautiful in the world anymore. There is always something to make you wonder in the shape of a tree, the trembling of a leaf.", + "author": "Albert Schweitzer" + }, + { + "content": "Take things as they are. Punch when you have to punch. Kick when you have to kick.", + "author": "Bruce Lee" + }, + { + "content": "We are what we think. All that we are arises with our thoughts. With our thoughts, we make the world.", + "author": "Buddha" + }, + { + "content": "He who experiences the unity of life sees his own Self in all beings, and all beings in his own Self, and looks on everything with an impartial eye.", + "author": "Buddha" + }, + { + "content": "Knowing your own darkness is the best method for dealing with the darkness of other people.", + "author": "Carl Jung" + }, + { + "content": "What matters is the value we've created in our lives, the people we've made happy and how much we've grown as people.", + "author": "Daisaku Ikeda" + }, + { + "content": "No one can make you feel inferior without your consent.", + "author": "Eleanor Roosevelt" + }, + { + "content": "Know, first, who you are, and then adorn yourself accordingly.", + "author": "Epictetus" + }, + { + "content": "We have two ears and one mouth so that we can listen twice as much as we speak.", + "author": "Epictetus" + }, + { + "content": "The world turns aside to let any man pass who knows where he is going.", + "author": "Epictetus" + }, + { + "content": "I cannot make my days longer, so I strive to make them better.", + "author": "Henry David Thoreau" + }, + { + "content": "Our doubts are traitors and make us lose the good we often might win, by fearing to attempt.", + "author": "Jane Addams" + }, + { + "content": "People are so constituted that everybody would rather undertake what they see others do, whether they have an aptitude for it or not.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "We choose our joys and sorrows long before we experience them.", + "author": "Kahlil Gibran" + }, + { + "content": "When you realize there is nothing lacking, the whole world belongs to you.", + "author": "Laozi" + }, + { + "content": "It is not only for what we do that we are held responsible, but also for what we do not do.", + "author": "Molière" + }, + { + "content": "If you break your neck, if you have nothing to eat, if your house is on fire, then you got a problem. Everything else is inconvenience.", + "author": "Robert Fulghum" + }, + { + "content": "Honesty is the first chapter in the book of wisdom.", + "author": "Thomas Jefferson" + }, + { + "content": "If you'll not settle for anything less than your best, you will be amazed at what you can accomplish in your lives.", + "author": "Vince Lombardi" + }, + { + "content": "To enjoy life, we must touch much of it lightly.", + "author": "Voltaire" + }, + { + "content": "Before you can inspire with emotion, you must be swamped with it yourself. Before you can move their tears, your own must flow. To convince them, you must yourself believe.", + "author": "Winston Churchill" + }, + { + "content": "The way you see people is the way you treat them, and the way you treat them is what they become.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "Ignorant men raise questions that wise men answered a thousand years ago.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "I don't turn to greeting cards for wisdom and advice, but they are a fine reflection of the general drift of the culture.", + "author": "Susan Orlean" + }, + { + "content": "Irony is the gaiety of reflection and the joy of wisdom.", + "author": "Anatole France" + }, + { + "content": "Love demands infinitely less than friendship.", + "author": "George Jean Nathan" + }, + { + "content": "Laughter is not at all a bad beginning for a friendship, and it is far the best ending for one.", + "author": "Oscar Wilde" + }, + { + "content": "Friendship multiplies the good of life and divides the evil.", + "author": "Baltasar Gracián" + }, + { + "content": "Do good by stealth, and blush to find it fame.", + "author": "Alexander Pope" + }, + { + "content": "Be kind whenever possible. It is always possible.", + "author": "Dalai Lama" + }, + { + "content": "Keep silence for the most part, and speak only when you must, and then briefly.", + "author": "Epictetus" + }, + { + "content": "I do not believe in a fate that falls on men however they act; but I do believe in a fate that falls on man unless they act.", + "author": "G. K. Chesterton" + }, + { + "content": "If you aren't going all the way, why go at all?", + "author": "Joe Namath" + }, + { + "content": "Treat people as if they were what they ought to be, and you help them to become what they are capable of being.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "A leader is one who knows the way, goes the way, and shows the way.", + "author": "John C. Maxwell" + }, + { + "content": "Faith in oneself is the best and safest course.", + "author": "Michelangelo" + }, + { + "content": "If the stars should appear but one night every thousand years how man would marvel and adore.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "A hero is no braver than an ordinary man, but he is braver five minutes longer.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Be not afraid of greatness: some are born great, some achieve greatness, and some have greatness thrust upon them.", + "author": "William Shakespeare" + }, + { + "content": "Knowledge is knowing that a tomato is a fruit. Wisdom is knowing not to put it in a fruit salad.", + "author": "Brian O'Driscoll" + }, + { + "content": "What happens is not as important as how you react to what happens.", + "author": "Ellen Glasgow" + }, + { + "content": "The final wisdom of life requires not the annulment of incongruity but the achievement of serenity within and above it.", + "author": "Reinhold Niebuhr" + }, + { + "content": "Swim upstream. Go the other way. Ignore the conventional wisdom.", + "author": "Sam Walton" + }, + { + "content": "Dost thou love life? Then do not squander time, for that is the stuff life is made of.", + "author": "Benjamin Franklin" + }, + { + "content": "We don't receive wisdom; we must discover it for ourselves after a journey that no one can take for us or spare us.", + "author": "Marcel Proust" + }, + { + "content": "Every man is a damn fool for at least five minutes every day; wisdom consists in not exceeding the limit.", + "author": "Elbert Hubbard" + }, + { + "content": "Technology is nothing. What's important is that you have a faith in people, that they're basically good and smart, and if you give them tools, they'll do wonderful things with them.", + "author": "Steve Jobs" + }, + { + "content": "We are shaped by our thoughts; we become what we think. When the mind is pure, joy follows like a shadow that never leaves.", + "author": "Buddha" + }, + { + "content": "Silence is deep as Eternity; Speech is shallow as Time.", + "author": "Thomas Carlyle" + }, + { + "content": "You cannot change anything in your life with intention alone, which can become a watered-down, occasional hope that you'll get to tomorrow. Intention without action is useless.", + "author": "Caroline Myss" + }, + { + "content": "You do not become good by trying to be good, but by finding the goodness that is already within you.", + "author": "Eckhart Tolle" + }, + { + "content": "There is no charm equal to tenderness of heart.", + "author": "Jane Austen" + }, + { + "content": "I love you the more in that I believe you had liked me for my own sake and for nothing else.", + "author": "John Keats" + }, + { + "content": "Reality leaves a lot to the imagination.", + "author": "John Lennon" + }, + { + "_id": "aUI--Kax4njP", + "content": "Trust your hunches. They're usually based on facts filed away just below the conscious level.", + "author": "Joyce Brothers" + }, + { + "content": "I always wanted to be somebody, but I should have been more specific.", + "author": "Lily Tomlin" + }, + { + "content": "A garden is always a series of losses set against a few triumphs, like life itself.", + "author": "May Sarton" + }, + { + "content": "We may encounter many defeats, but we must not be defeated.", + "author": "Maya Angelou" + }, + { + "content": "Be yourself; everyone else is already taken.", + "author": "Oscar Wilde" + }, + { + "content": "They can do all because they think they can.", + "author": "Virgil" + }, + { + "content": "The pine stays green in winter... wisdom in hardship.", + "author": "Norman Douglas" + }, + { + "content": "There is a difference between happiness and wisdom: he that thinks himself the happiest man is really so; but he that thinks himself the wisest is generally the greatest fool.", + "author": "Francis Bacon" + }, + { + "content": "This is why I loved technology: if you used it right, it could give you power and privacy.", + "author": "Cory Doctorow" + }, + { + "content": "In romance, we feel the need to zoom in and expound on our partner's foibles in intimate detail; in friendship, we tend to do the opposite, avoiding confrontation through fear, lethargy or both.", + "author": "Mariella Frostrup" + }, + { + "content": "Friendship brings in a lot of honesty and trust into any relationship, especially a marriage.", + "author": "Farhan Akhtar" + }, + { + "content": "Friendships are the family we make - not the one we inherit. I've always been someone to whom friendship, elective affinities, is as important as family.", + "author": "Salman Rushdie" + }, + { + "content": "In friendship as well as love, ignorance very often contributes more to our happiness than knowledge.", + "author": "François de La Rochefoucauld" + }, + { + "content": "A house divided against itself cannot stand.", + "author": "Abraham Lincoln" + }, + { + "content": "No person is your friend who demands your silence or denies your right to grow.", + "author": "Alice Walker" + }, + { + "content": "Your work is to discover your world and then with all your heart give yourself to it.", + "author": "Buddha" + }, + { + "content": "Always be mindful of the kindness and not the faults of others.", + "author": "Buddha" + }, + { + "content": "Who looks outside, dreams, who looks inside, awakes.", + "author": "Carl Jung" + }, + { + "content": "Learning without reflection is a waste, reflection without learning is dangerous.", + "author": "Confucius" + }, + { + "content": "Consider that not only do negative thoughts and emotions destroy our experience of peace, but they also undermine our health.", + "author": "Dalai Lama" + }, + { + "content": "Through meditation and by giving full attention to one thing at a time, we can learn to direct attention where we choose.", + "author": "Eknath Easwaran" + }, + { + "_id": "aJ-kdYIolJ8-", + "content": "Accept challenges, so that you may feel the exhilaration of victory.", + "author": "George S. Patton" + }, + { + "content": "Never idealize others. They will never live up to your expectations.", + "author": "Leo Buscaglia" + }, + { + "content": "You're never a loser until you quit trying.", + "author": "Mike Ditka" + }, + { + "content": "Every time you smile at someone, it is an action of love, a gift to that person, a beautiful thing.", + "author": "Mother Teresa" + }, + { + "content": "You give before you get.", + "author": "Napoleon Hill" + }, + { + "content": "And as we let our own light shine, we unconsciously give other people permission to do the same.", + "author": "Nelson Mandela" + }, + { + "content": "Men in general judge more from appearances than from reality. All men have eyes, but few have the gift of penetration.", + "author": "Niccolò Machiavelli" + }, + { + "content": "In order to live free and happily you must sacrifice boredom. It is not always an easy sacrifice.", + "author": "Richard Bach" + }, + { + "content": "No man was ever wise by chance.", + "author": "Seneca the Younger" + }, + { + "content": "To be beautiful means to be yourself. You don't need to be accepted by others. You need to accept yourself.", + "author": "Thích Nhất Hạnh" + }, + { + "content": "Permanence, perseverance and persistence in spite of all obstacles, discouragements, and impossibilities: It is this, that in all things distinguishes the strong soul from the weak.", + "author": "Thomas Carlyle" + }, + { + "content": "Real magic in relationships means an absence of judgement of others.", + "author": "Wayne Dyer" + }, + { + "content": "A good head and a good heart are always a formidable combination.", + "author": "Nelson Mandela" + }, + { + "content": "If you are bitter, you are like a dry leaf that you can just squash, and you can get blown away by the wind. There is much more wisdom in forgiveness.", + "author": "Vusi Mahlasela" + }, + { + "content": "Honesty is the best policy.", + "author": "Benjamin Franklin" + }, + { + "content": "Friendship often ends in love, but love in friendship - never.", + "author": "Albert Camus" + }, + { + "content": "A person who never made a mistake never tried anything new.", + "author": "Albert Einstein" + }, + { + "content": "The dream was always running ahead of me. To catch up, to live for a moment in unison with it, that was the miracle.", + "author": "Anaïs Nin" + }, + { + "content": "Action may not always bring happiness; but there is no happiness without action.", + "author": "Benjamin Disraeli" + }, + { + "content": "In the sky, there is no distinction of east and west; people create distinctions out of their own minds and then believe them to be true.", + "author": "Buddha" + }, + { + "content": "If we could see the miracle of a single flower clearly, our whole life would change.", + "author": "Buddha" + }, + { + "content": "Life a culmination of the past, an awareness of the present, an indication of the future beyond knowledge, the quality that gives a touch of divinity to matter.", + "author": "Charles Lindbergh" + }, + { + "content": "Impossibilities are merely things which we have not yet learned.", + "author": "Charles W. Chesnutt" + }, + { + "content": "Friendship with oneself is all important because without it one cannot be friends with anybody else in the world.", + "author": "Eleanor Roosevelt" + }, + { + "content": "First say to yourself what you would be; and then do what you have to do.", + "author": "Epictetus" + }, + { + "content": "Fame usually comes to those who are thinking about something else.", + "author": "Oliver Wendell Holmes Jr." + }, + { + "content": "Give whatever you are doing and whoever you are with the gift of your attention.", + "author": "Jim Rohn" + }, + { + "content": "You cannot have what you do not want.", + "author": "John Acosta" + }, + { + "content": "Be the change that you want to see in the world.", + "author": "Mahatma Gandhi" + }, + { + "content": "Bad times have a scientific value. These are occasions a good learner would not miss.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "You are never given a wish without also being given the power to make it come true. You may have to work for it, however.", + "author": "Richard Bach" + }, + { + "content": "Many of life's failures are people who did not realize how close they were to success when they gave up.", + "author": "Thomas Edison" + }, + { + "content": "The World is my country, all mankind are my brethren, and to do good is my religion.", + "author": "Thomas Paine" + }, + { + "content": "Nature takes away any faculty that is not used.", + "author": "William Inge" + }, + { + "content": "With the new day comes new strength and new thoughts.", + "author": "Eleanor Roosevelt" + }, + { + "content": "Keep me away from the wisdom which does not cry, the philosophy which does not laugh and the greatness which does not bow before children.", + "author": "Kahlil Gibran" + }, + { + "content": "The word philosophy sounds high-minded, but it simply means the love of wisdom. If you love something, you don't just read about it; you hug it, you mess with it, you play with it, you argue with it.", + "author": "Hugh Jackman" + }, + { + "content": "TV and the Internet are good because they keep stupid people from spending too much time out in public.", + "author": "Douglas Coupland" + }, + { + "content": "The rule of friendship means there should be mutual sympathy between them, each supplying what the other lacks and trying to benefit the other, always using friendly and sincere words.", + "author": "Cicero" + }, + { + "content": "There is nothing impossible to him who will try.", + "author": "Alexander the Great" + }, + { + "content": "The most difficult thing is the decision to act, the rest is merely tenacity. The fears are paper tigers. You can do anything you decide to do. You can act to change and control your life; and the procedure, the process is its own reward.", + "author": "Amelia Earhart" + }, + { + "content": "Age does not protect you from love. But love, to some extent, protects you from age.", + "author": "Anaïs Nin" + }, + { + "content": "In all things of nature there is something of the marvelous.", + "author": "Aristotle" + }, + { + "content": "If you spend too much time thinking about a thing, you'll never get it done.", + "author": "Bruce Lee" + }, + { + "content": "Happiness does not come from having much, but from being attached to little.", + "author": "Cheng Yen" + }, + { + "content": "I find hope in the darkest of days, and focus in the brightest. I do not judge the universe.", + "author": "Dalai Lama" + }, + { + "content": "Absence makes the heart grow fonder.", + "author": "Thomas Haynes Bayly" + }, + { + "content": "Quality means doing it right when no one is looking.", + "author": "Henry Ford" + }, + { + "content": "Conflict is the gadfly of thought. It stirs us to observation and memory. It instigates to invention. It shocks us out of sheeplike passivity, and sets us at noting and contriving.", + "author": "John Dewey" + }, + { + "content": "Change is the law of life. And those who look only to the past or present are certain to miss the future.", + "author": "John F. Kennedy" + }, + { + "content": "Life is what happens to you while you're busy making other plans.", + "author": "John Lennon" + }, + { + "content": "I have always thought the actions of men the best interpreters of their thoughts.", + "author": "John Locke" + }, + { + "content": "He who has imagination without learning has wings but no feet.", + "author": "Joseph Joubert" + }, + { + "content": "Each misfortune you encounter will carry in it the seed of tomorrows good luck.", + "author": "Og Mandino" + }, + { + "content": "Follow your instincts. That is where true wisdom manifests itself.", + "author": "Oprah Winfrey" + }, + { + "content": "Skill to do comes of doing.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "You'll see it when you believe it.", + "author": "Wayne Dyer" + }, + { + "content": "Adversity causes some men to break, others to break records.", + "author": "William Arthur Ward" + }, + { + "content": "If you want to succeed you should strike out on new paths, rather than travel the worn paths of accepted success.", + "author": "John Locke" + }, + { + "content": "I'd rather regret the things I've done than regret the things I haven't done.", + "author": "Lucille Ball" + }, + { + "content": "We are stuck with technology when what we really want is just stuff that works.", + "author": "Douglas Adams" + }, + { + "content": "Technology is the campfire around which we tell our stories.", + "author": "Laurie Anderson" + }, + { + "content": "True friendship can afford true knowledge. It does not depend on darkness and ignorance.", + "author": "Henry David Thoreau" + }, + { + "author": "Abraham Lincoln", + "content": "I'll prepare and someday my chance will come." + }, + { + "content": "Trust your own instinct. Your mistakes might as well be your own, instead of someone else's.", + "author": "Billy Wilder" + }, + { + "content": "Once you choose hope, anything's possible.", + "author": "Christopher Reeve" + }, + { + "content": "It's important to know that words don't move mountains. Work, exacting work moves mountains.", + "author": "Danilo Dolci" + }, + { + "content": "Success in business requires training and discipline and hard work. But if you're not frightened by these things, the opportunities are just as great today as they ever were.", + "author": "David Rockefeller" + }, + { + "content": "The self is not something ready-made, but something in continuous formation through choice of action.", + "author": "John Dewey" + }, + { + "content": "Your big opportunity may be right where you are now.", + "author": "Napoleon Hill" + }, + { + "content": "Only do what your heart tells you.", + "author": "Princess Diana" + }, + { + "content": "It is with words as with sunbeams. The more they are condensed, the deeper they burn.", + "author": "Robert Southey" + }, + { + "content": "Most powerful is he who has himself in his own power.", + "author": "Seneca the Younger" + }, + { + "content": "We must never forget that it is through our actions, words, and thoughts that we have a choice.", + "author": "Sogyal Rinpoche" + }, + { + "content": "If we are not fully ourselves, truly in the present moment, we miss everything.", + "author": "Thích Nhất Hạnh" + }, + { + "content": "How far that little candle throws its beams! So shines a good deed in a naughty world.", + "author": "William Shakespeare" + }, + { + "content": "All the world is a stage, And all the men and women merely players. They have their exits and entrances; Each man in his time plays many parts.", + "author": "William Shakespeare" + }, + { + "content": "O, what a tangled web we weave when first we practice to deceive!", + "author": "Walter Scott" + }, + { + "content": "In life, all good things come hard, but wisdom is the hardest to come by.", + "author": "Lucille Ball" + }, + { + "content": "It is the nature of the wise to resist pleasures, but the foolish to be a slave to them.", + "author": "Epictetus" + }, + { + "content": "The great myth of our times is that technology is communication.", + "author": "Libby Larsen" + }, + { + "content": "Friendship is certainly the finest balm for the pangs of disappointed love.", + "author": "Jane Austen" + }, + { + "content": "If a man does not make new acquaintances as he advances through life, he will soon find himself left alone. A man, sir, should keep his friendship in a constant repair.", + "author": "Samuel Johnson" + }, + { + "content": "Friendship without self-interest is one of the rare and beautiful things of life.", + "author": "James F. Byrnes" + }, + { + "content": "Be sure you put your feet in the right place, then stand firm.", + "author": "Abraham Lincoln" + }, + { + "content": "Mediocrity knows nothing higher than itself, but talent instantly recognizes genius.", + "author": "Arthur Conan Doyle" + }, + { + "content": "Watch the little things; a small leak will sink a great ship.", + "author": "Benjamin Franklin" + }, + { + "content": "All fixed set patterns are incapable of adaptability or pliability. The truth is outside of all fixed patterns.", + "author": "Bruce Lee" + }, + { + "content": "Success is getting what you want. Happiness is wanting what you get.", + "author": "Dale Carnegie" + }, + { + "content": "The winner ain't the one with the fastest car it's the one who refuses to lose.", + "author": "Dale Earnhardt" + }, + { + "content": "I prefer to be true to myself, even at the hazard of incurring the ridicule of others, rather than to be false, and to incur my own abhorrence.", + "author": "Frederick Douglass" + }, + { + "content": "Every artist dips his brush in his own soul, and paints his own nature into his pictures.", + "author": "Henry Ward Beecher" + }, + { + "content": "Arriving at one point is the starting point to another.", + "author": "John Dewey" + }, + { + "content": "If you would take, you must first give, this is the beginning of intelligence.", + "author": "Laozi" + }, + { + "content": "A leader is best when people barely know he exists, when his work is done, his aim fulfilled, they will say: we did it ourselves.", + "author": "Laozi" + }, + { + "content": "To be able to give away riches is mandatory if you wish to possess them. This is the only way that you will be truly rich.", + "author": "Muhammad Ali" + }, + { + "_id": "-ScvfiXp-jo-", + "content": "You can tell whether a man is clever by his answers. You can tell whether a man is wise by his questions.", + "author": "Naguib Mahfouz" + }, + { + "content": "What lies behind us and what lies before us are small matters compared to what lies within us.", + "author": "Oliver Wendell Holmes Jr." + }, + { + "content": "Don't believe what your eyes are telling you. All they show is limitation. Look with your understanding, find out what you already know, and you'll see the way to fly.", + "author": "Richard Bach" + }, + { + "content": "The mind unlearns with difficulty what it has long learned.", + "author": "Seneca the Younger" + }, + { + "content": "Begin at once to live and count each separate day as a separate life.", + "author": "Seneca the Younger" + }, + { + "content": "Better to have loved and lost, than to have never loved at all.", + "author": "Augustine of Hippo" + }, + { + "content": "Get busy living or get busy dying.", + "author": "Stephen King" + }, + { + "content": "Believe you can and you're halfway there.", + "author": "Theodore Roosevelt" + }, + { + "content": "I'm a great believer in luck and I find the harder I work, the more I have of it.", + "author": "Thomas Jefferson" + }, + { + "content": "Only I can change my life. No one can do it for me.", + "author": "Carol Burnett" + }, + { + "content": "The greatest obstacle to being heroic is the doubt whether one may not be going to prove oneself a fool; the truest heroism is to resist the doubt; and the profoundest wisdom, to know when it ought to be resisted, and when it be obeyed.", + "author": "Nathaniel Hawthorne" + }, + { + "content": "Let my skin and sinews and bones dry up, together with all the flesh and blood of my body! I welcome it! But I will not move from this spot until I have attained the supreme and final wisdom.", + "author": "Buddha" + }, + { + "content": "I hope our wisdom will grow with our power, and teach us, that the less we use our power the greater it will be.", + "author": "Thomas Jefferson" + }, + { + "content": "A poem begins in delight and ends in wisdom.", + "author": "Robert Frost" + }, + { + "_id": "mRyh-i79x-", + "content": "Love is the only force capable of transforming an enemy into a friend.", + "author": "Martin Luther King Jr." + }, + { + "content": "The final proof of greatness lies in being able to endure criticism without resentment.", + "author": "Elbert Hubbard" + }, + { + "content": "Whoso loves, believes the impossible.", + "author": "Elizabeth Browning" + }, + { + "content": "Happiness can exist only in acceptance.", + "author": "George Orwell" + }, + { + "content": "Work while you have the light. You are responsible for the talent that has been entrusted to you.", + "author": "Henri-Frédéric Amiel" + }, + { + "content": "Perseverance is a great element of success. If you only knock long enough and loud enough at the gate, you are sure to wake up somebody.", + "author": "Henry Wadsworth Longfellow" + }, + { + "content": "Love has no age, no limit; and no death.", + "author": "John Galsworthy" + }, + { + "content": "Music in the soul can be heard by the universe.", + "author": "Laozi" + }, + { + "content": "We lost because we told ourselves we lost.", + "author": "Leo Tolstoy" + }, + { + "content": "Nothing strengthens authority so much as silence.", + "author": "Leonardo da Vinci" + }, + { + "content": "I allow my intuition to lead my path.", + "author": "Manuel Puig" + }, + { + "content": "The truth of the matter is that you always know the right thing to do. The hard part is doing it.", + "author": "Norman Schwarzkopf" + }, + { + "content": "If you want your life to be more rewarding, you have to change the way you think.", + "author": "Oprah Winfrey" + }, + { + "content": "Everything you can imagine is real.", + "author": "Pablo Picasso" + }, + { + "content": "While we stop to think, we often miss our opportunity.", + "author": "Publilius Syrus" + }, + { + "content": "The only way to have a friend is to be one.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Every person, all the events of your life are there because you have drawn them there. What you choose to do with them is up to you.", + "author": "Richard Bach" + }, + { + "content": "To dare is to lose ones footing momentarily. To not dare is to lose oneself.", + "author": "Søren Kierkegaard" + }, + { + "content": "Never put off till tomorrow what you can do today.", + "author": "Thomas Jefferson" + }, + { + "content": "You always succeed in producing a result.", + "author": "Tony Robbins" + }, + { + "content": "God gave us the gift of life; it is up to us to give ourselves the gift of living well.", + "author": "Voltaire" + }, + { + "content": "No matter how carefully you plan your goals they will never be more that pipe dreams unless you pursue them with gusto.", + "author": "W. Clement Stone" + }, + { + "content": "It is not wisdom but Authority that makes a law.", + "author": "Thomas Hobbes" + }, + { + "content": "Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?", + "author": "George Eliot" + }, + { + "content": "I think that we have a great opportunity to impart our wisdom and our knowledge and our experience to this younger generation. It may be different times, but experience transcends time, and wisdom transcends time.", + "author": "Victoria Osteen" + }, + { + "content": "No party has a monopoly on wisdom. No democracy works without compromise.", + "author": "Barack Obama" + }, + { + "content": "Wisdom has never made a bigot, but learning has.", + "author": "Josh Billings" + }, + { + "content": "First we thought the PC was a calculator. Then we found out how to turn numbers into letters with ASCII — and we thought it was a typewriter. Then we discovered graphics, and we thought it was a television. With the World Wide Web, we've realized it's a brochure.", + "author": "Douglas Adams" + }, + { + "content": "I cannot even imagine where I would be today were it not for that handful of friends who have given me a heart full of joy. Let's face it, friends make life a lot more fun.", + "author": "Chuck Swindoll" + }, + { + "content": "I never considered a difference of opinion in politics, in religion, in philosophy, as cause for withdrawing from a friend.", + "author": "Thomas Jefferson" + }, + { + "content": "The best thing about the future is that it only comes one day at a time.", + "author": "Abraham Lincoln" + }, + { + "content": "Well begun is half done.", + "author": "Aristotle" + }, + { + "content": "No yesterdays are ever wasted for those who give themselves to today.", + "author": "Brendan Behan" + }, + { + "content": "The less effort, the faster and more powerful you will be.", + "author": "Bruce Lee" + }, + { + "content": "No one saves us but ourselves. No one can and no one may. We ourselves must walk the path.", + "author": "Buddha" + }, + { + "content": "However many holy words you read, however many you speak, what good will they do you if you do not act on upon them?", + "author": "Buddha" + }, + { + "content": "Gratitude is riches. Complaint is poverty.", + "author": "Doris Day" + }, + { + "content": "A man sees in the world what he carries in his heart.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "Before you put on a frown, make absolutely sure there are no smiles available.", + "author": "James M. Beggs" + }, + { + "content": "Difficulties increase the nearer we get to the goal.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "When I let go of what I am, I become what I might be.", + "author": "Laozi" + }, + { + "content": "Let us always meet each other with smile, for the smile is the beginning of love.", + "author": "Mother Teresa" + }, + { + "content": "The aim of life is self-development. To realize one's nature perfectly - that is what each of us is here for.", + "author": "Oscar Wilde" + }, + { + "content": "Great are they who see that spiritual is stronger than any material force, that thoughts rule the world.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "So is cheerfulness, or a good temper, the more it is spent, the more remains.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "The conditions of conquest are always easy. We have but to toil awhile, endure awhile, believe always, and never turn back.", + "author": "Seneca the Younger" + }, + { + "content": "Love all, trust a few, do wrong to none.", + "author": "William Shakespeare" + }, + { + "content": "We should not give up and we should not allow the problem to defeat us.", + "author": "A. P. J. Abdul Kalam" + }, + { + "content": "That old law about 'an eye for an eye' leaves everybody blind. The time is always right to do the right thing.", + "author": "Martin Luther King Jr." + }, + { + "content": "The opportunity for brotherhood presents itself every time you meet a human being.", + "author": "Jane Wyman" + }, + { + "content": "A ruffled mind makes a restless pillow.", + "author": "Charlotte Brontë" + }, + { + "content": "Wisdom and penetration are the fruit of experience, not the lessons of retirement and leisure. Great necessities call out great virtues.", + "author": "Abigail Adams" + }, + { + "content": "Never accept ultimatums, conventional wisdom, or absolutes.", + "author": "Christopher Reeve" + }, + { + "content": "All love that has not friendship for its base, is like a mansion built upon the sand.", + "author": "Ella Wheeler Wilcox" + }, + { + "content": "A man cannot be said to succeed in this life who does not satisfy one friend.", + "author": "Henry David Thoreau" + }, + { + "content": "The fact is, with every friendship you make, and every bond of trust you establish, you are shaping the image of America projected to the rest of the world. That is so important. So when you study abroad, you're actually helping to make America stronger.", + "author": "Michelle Obama" + }, + { + "content": "Of course there is no formula for success except perhaps an unconditional acceptance of life and what it brings.", + "author": "Arthur Rubinstein" + }, + { + "content": "The heart has its reasons which reason knows not of.", + "author": "Blaise Pascal" + }, + { + "content": "Always be yourself, express yourself, have faith in yourself, do not go out and look for a successful personality and duplicate it.", + "author": "Bruce Lee" + }, + { + "content": "Do not overrate what you have received, nor envy others. He who envies others does not obtain peace of mind.", + "author": "Buddha" + }, + { + "content": "On every thorn, delightful wisdom grows, in every rill a sweet instruction flows.", + "author": "Edward Young" + }, + { + "content": "The beginning of knowledge is the discovery of something we do not understand.", + "author": "Frank Herbert" + }, + { + "content": "Intuition is the very force or activity of the soul in its experience through whatever has been the experience of the soul itself.", + "author": "Henry Reed" + }, + { + "content": "Be glad of life because it gives you the chance to love, to work, to play, and to look up at the stars.", + "author": "Henry van Dyke Jr." + }, + { + "content": "Either you run the day or the day runs you.", + "author": "Jim Rohn" + }, + { + "content": "Not what we have but what we enjoy constitutes our abundance.", + "author": "Jean Antoine Petit-Senn" + }, + { + "content": "Dreams come true. Without that possibility, nature would not incite us to have them.", + "author": "John Updike" + }, + { + "content": "As an organizer I start from where the world is, as it is, not as I would like it to be.", + "author": "Saul Alinsky" + }, + { + "content": "The greatest way to live with honor in this world is to be what we pretend to be.", + "author": "Socrates" + }, + { + "content": "To be aware of a single shortcoming in oneself is more useful than to be aware of a thousand in someone else.", + "author": "Dalai Lama" + }, + { + "content": "No garden is without its weeds.", + "author": "Thomas Fuller" + }, + { + "content": "Life is like a sewer. What you get out of it depends on what you put into it.", + "author": "Tom Lehrer" + }, + { + "content": "In seed time learn, in harvest teach, in winter enjoy.", + "author": "William Blake" + }, + { + "content": "Accept the challenges so that you can feel the exhilaration of victory.", + "author": "George S. Patton" + }, + { + "content": "The more you like yourself, the less you are like anyone else, which makes you unique.", + "author": "Walt Disney" + }, + { + "content": "If you set out to be liked, you would be prepared to compromise on anything at any time, and you would achieve nothing.", + "author": "Margaret Thatcher" + }, + { + "content": "The most I can do for my friend is simply be his friend.", + "author": "Henry David Thoreau" + }, + { + "content": "Rejoicing in our joy, not suffering over our suffering, makes someone a friend.", + "author": "Friedrich Nietzsche" + }, + { + "content": "Love and friendship exclude each other.", + "author": "Jean de La Bruyère" + }, + { + "content": "Trust only movement. Life happens at the level of events, not of words. Trust movement.", + "author": "Alfred Adler" + }, + { + "content": "I have never been hurt by anything I didn't say.", + "author": "Calvin Coolidge" + }, + { + "content": "Our lives are the only meaningful expression of what we believe and in Whom we believe. And the only real wealth, for any of us, lies in our faith.", + "author": "Gordon Hinckley" + }, + { + "content": "Promises are the uniquely human way of ordering the future, making it predictable and reliable to the extent that this is humanly possible.", + "author": "Hannah Arendt" + }, + { + "content": "He who knows himself is enlightened.", + "author": "Laozi" + }, + { + "content": "Iron rusts from disuse; water loses its purity from stagnation... even so does inaction sap the vigor of the mind.", + "author": "Leonardo da Vinci" + }, + { + "content": "The years teach much which the days never know.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Life is a progress, and not a station.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Everything in the universe goes by indirection. There are no straight lines.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Luck is what happens when preparation meets opportunity.", + "author": "Seneca the Younger" + }, + { + "content": "Genius is one percent inspiration and ninety-nine percent perspiration.", + "author": "Thomas Edison" + }, + { + "content": "All our dreams can come true, if we have the courage to pursue them.", + "author": "Walt Disney" + }, + { + "content": "Good, better, best. Never let it rest. ‘Til your good is better and your better is best.", + "author": "Jerome" + }, + { + "content": "A long habit of not thinking a thing wrong gives it a superficial appearance of being right.", + "author": "Thomas Paine" + }, + { + "content": "The doorstep to the temple of wisdom is a knowledge of our own ignorance.", + "author": "Benjamin Franklin" + }, + { + "content": "The more sand that has escaped from the hourglass of our life, the clearer we should see through it.", + "author": "Jean-Paul Sartre" + }, + { + "content": "My best friend is the one who brings out the best in me.", + "author": "Henry Ford" + }, + { + "content": "We must reach out our hand in friendship and dignity both to those who would befriend us and those who would be our enemy.", + "author": "Arthur Ashe" + }, + { + "content": "Life is like riding a bicycle. To keep your balance you must keep moving.", + "author": "Albert Einstein" + }, + { + "content": "Change in all things is sweet.", + "author": "Aristotle" + }, + { + "content": "Trust yourself. You know more than you think you do.", + "author": "Benjamin Spock" + }, + { + "content": "Life's challenges are not supposed to paralyze you, they're supposed to help you discover who you are.", + "author": "Bernice Reagon" + }, + { + "content": "We are all something, but none of us are everything.", + "author": "Blaise Pascal" + }, + { + "content": "You cannot find yourself by going into the past. You can find yourself by coming into the present.", + "author": "Eckhart Tolle" + }, + { + "content": "Love doesn't make the world go round; love is what makes the ride worthwhile.", + "author": "Elizabeth Browning" + }, + { + "content": "A wise man will make more opportunities than he finds.", + "author": "Francis Bacon" + }, + { + "content": "So long as a person is capable of self-renewal they are a living being.", + "author": "Henri-Frédéric Amiel" + }, + { + "content": "The world is round and the place which may seem like the end may also be the beginning.", + "author": "Ivy Baker Priest" + }, + { + "content": "The most successful people are those who are good at plan B.", + "author": "James A. Yorke" + }, + { + "content": "If opportunity doesn't knock, build a door.", + "author": "Milton Berle" + }, + { + "content": "We can do no great things, only small things with great love.", + "author": "Mother Teresa" + }, + { + "_id": "K4fn0Bz-4V1-", + "content": "When you begin to touch your heart or let your heart be touched, you begin to discover that it's bottomless.", + "author": "Pema Chödrön" + }, + { + "content": "Allow the world to live as it chooses, and allow yourself to live as you choose.", + "author": "Richard Bach" + }, + { + "content": "May our hearts garden of awakening bloom with hundreds of flowers.", + "author": "Thích Nhất Hạnh" + }, + { + "content": "Whatever happens, take responsibility.", + "author": "Tony Robbins" + }, + { + "content": "True wisdom is less presuming than folly. The wise man doubteth often, and changeth his mind; the fool is obstinate, and doubteth not; he knoweth all things but his own ignorance.", + "author": "Akhenaten" + }, + { + "content": "Computers are useless. They can only give you answers.", + "author": "Pablo Picasso" + }, + { + "content": "Business, you know, may bring you money, but friendship hardly ever does.", + "author": "Jane Austen" + }, + { + "content": "The world is round so that friendship may encircle it.", + "author": "Pierre Teilhard de Chardin" + }, + { + "content": "To effectively communicate, we must realize that we are all different in the way we perceive the world and use this understanding as a guide to our communication with others.", + "author": "Tony Robbins" + }, + { + "content": "Work out your own salvation. Do not depend on others.", + "author": "Buddha" + }, + { + "content": "The way is not in the sky. The way is in the heart.", + "author": "Buddha" + }, + { + "content": "What is not started today is never finished tomorrow.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "It is not so important to know everything as to appreciate what we learn.", + "author": "Hannah More" + }, + { + "content": "Kindness in words creates confidence. Kindness in thinking creates profoundness. Kindness in giving creates love.", + "author": "Laozi" + }, + { + "content": "Loss is nothing else but change, and change is Nature's delight.", + "author": "Marcus Aurelius" + }, + { + "content": "The greatest part of our happiness depends on our dispositions, not our circumstances.", + "author": "Martha Washington" + }, + { + "content": "First comes thought; then organization of that thought, into ideas and plans; then transformation of those plans into reality. The beginning, as you will observe, is in your imagination.", + "author": "Napoleon Hill" + }, + { + "content": "There is nothing like returning to a place that remains unchanged to find the ways in which you yourself have altered.", + "author": "Nelson Mandela" + }, + { + "content": "Good actions give strength to ourselves and inspire good actions in others.", + "author": "Plato" + }, + { + "content": "Nature is a mutable cloud which is always and never the same.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "In three words I can sum up everything I've learned about life: it goes on.", + "author": "Robert Frost" + }, + { + "content": "Sometimes your joy is the source of your smile, but sometimes your smile can be the source of your joy.", + "author": "Thích Nhất Hạnh" + }, + { + "content": "The spirit, the will to win, and the will to excel, are the things that endure. These qualities are so much more important than the events that occur.", + "author": "Vince Lombardi" + }, + { + "content": "Good people are good because they've come to wisdom through failure. We get very little wisdom from success, you know.", + "author": "William Saroyan" + }, + { + "content": "When we seek to discover the best in others, we somehow bring out the best in ourselves.", + "author": "William Arthur Ward" + }, + { + "content": "A man must be big enough to admit his mistakes, smart enough to profit from them, and strong enough to correct them.", + "author": "John C. Maxwell" + }, + { + "content": "The problem with Google is you have 360 degrees of omnidirectional information on a linear basis, but the algorithms for irony and ambiguity are not there. And those are the algorithms of wisdom.", + "author": "William Hurt" + }, + { + "content": "The greatest achievement of humanity is not its works of art, science, or technology, but the recognition of its own dysfunction.", + "author": "Eckhart Tolle" + }, + { + "content": "A true friend freely, advises justly, assists readily, adventures boldly, takes all patiently, defends courageously, and continues a friend unchangeably.", + "author": "William C. Menninger" + }, + { + "content": "Of all possessions a friend is the most precious.", + "author": "Herodotus" + }, + { + "content": "Friendship is the source of the greatest pleasures, and without friends even the most agreeable pursuits become tedious.", + "author": "Thomas Aquinas" + }, + { + "content": "Logic will get you from A to B. Imagination will take you everywhere.", + "author": "Albert Einstein" + }, + { + "content": "Experience is not what happens to a man. It is what a man does with what happens to him.", + "author": "Aldous Huxley" + }, + { + "content": "Never do things others can do and will do, if there are things others cannot do or will not do.", + "author": "Amelia Earhart" + }, + { + "content": "One today is worth two tomorrows.", + "author": "Benjamin Franklin" + }, + { + "content": "I am of the opinion that my life belongs to the community, and as long as I live it is my privilege to do for it whatever I can.", + "author": "Bernard Shaw" + }, + { + "content": "Gratitude is not only the greatest of virtues, but the parent of all the others.", + "author": "Cicero" + }, + { + "content": "I believe that we are fundamentally the same and have the same basic potential.", + "author": "Dalai Lama" + }, + { + "content": "A man is not old as long as he is seeking something.", + "author": "Edmond Rostand" + }, + { + "content": "I'm not interested in age. People who tell me their age are silly. You're as old as you feel.", + "author": "Elizabeth Arden" + }, + { + "content": "A life spent making mistakes is not only more honorable, but more useful than a life spent doing nothing.", + "author": "George Bernard Shaw" + }, + { + "content": "It is on our failures that we base a new and different and better success.", + "author": "Havelock Ellis" + }, + { + "content": "The really unhappy person is the one who leaves undone what they can do, and starts doing what they don't understand; no wonder they come to grief.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "As we express our gratitude, we must never forget that the highest appreciation is not to utter words, but to live by them.", + "author": "John F. Kennedy" + }, + { + "content": "A single rose can be my garden... a single friend, my world.", + "author": "Leo Buscaglia" + }, + { + "content": "The right way is not always the popular and easy way. Standing for right when it is unpopular is a true test of moral character.", + "author": "Margaret Chase Smith" + }, + { + "content": "Don't settle for a relationship that won't let you be yourself.", + "author": "Oprah Winfrey" + }, + { + "content": "The only thing to do with good advice is to pass it on. It is never of any use to oneself.", + "author": "Oscar Wilde" + }, + { + "content": "The best way out is always through.", + "author": "Robert Frost" + }, + { + "content": "If we did the things we are capable of, we would astound ourselves.", + "author": "Thomas Edison" + }, + { + "content": "If you surrender to the wind, you can ride it.", + "author": "Toni Morrison" + }, + { + "content": "Using the power of decision gives you the capacity to get past any excuse to change any and every part of your life in an instant.", + "author": "Tony Robbins" + }, + { + "content": "Optimism is the faith that leads to achievement. Nothing can be done without hope and confidence.", + "author": "Helen Keller" + }, + { + "content": "It always seems impossible until it's done.", + "author": "Nelson Mandela" + }, + { + "content": "The Universal Zulu Nation stands to acknowledge wisdom, understanding, freedom, justice, and equality, peace, unity, love, and having fun, work, overcoming the negative through the positive, science, mathematics, faith, facts, and the wonders of God, whether we call him Allah, Jehovah, Yahweh, or Jah.", + "author": "Afrika Bambaataa" + }, + { + "content": "All things must come to the soul from its roots, from where it is planted.", + "author": "Teresa of Ávila" + }, + { + "content": "He is no fool who gives what he cannot keep to gain what he cannot lose.", + "author": "Jim Elliot" + }, + { + "content": "Experience is not what happens to you; it's what you do with what happens to you.", + "author": "Aldous Huxley" + }, + { + "content": "America's freedom of religion, and freedom from religion, offers every wisdom tradition an opportunity to address our soul-deep needs: Christianity, Judaism, Islam, Buddhism, Hinduism, secular humanism, agnosticism and atheism among others.", + "author": "Parker Palmer" + }, + { + "content": "I love wisdom. And you can never be great at anything unless you love it. Not be in love with it, but love the thing, admire the thing. And it seems that if you love the thing, and you don't just want to possess it, it will find you.", + "author": "Maya Angelou" + }, + { + "content": "As you walk down the fairway of life you must smell the roses, for you only get to play one round.", + "author": "Ben Hogan" + }, + { + "content": "It is the province of knowledge to speak, and it is the privilege of wisdom to listen.", + "author": "Oliver Wendell Holmes Jr." + }, + { + "content": "Technology has to be invented or adopted.", + "author": "Jared Diamond" + }, + { + "content": "It is only the great hearted who can be true friends. The mean and cowardly, can never know what true friendship means.", + "author": "Charles Kingsley" + }, + { + "content": "Sustaining true friendship is a lot more challenging than we give it credit for.", + "author": "Mariella Frostrup" + }, + { + "content": "Friendship needs no words - it is solitude delivered from the anguish of loneliness.", + "author": "Dag Hammarskjöld" + }, + { + "author": "Woody Allen", + "content": "If it turns out that there is a God, I don't think that he's evil. But the worst that you can say about him is that basically he's an underachiever." + }, + { + "content": "One of the advantages of being disorderly is that one is constantly making exciting discoveries.", + "author": "A. A. Milne" + }, + { + "content": "In a controversy the instant we feel anger we have already ceased striving for the truth, and have begun striving for ourselves.", + "author": "Buddha" + }, + { + "content": "All that we are is the result of what we have thought. The mind is everything. What we think we become.", + "author": "Buddha" + }, + { + "content": "I hear and I forget. I see and I remember. I do and I understand.", + "author": "Confucius" + }, + { + "content": "He who wishes to secure the good of others, has already secured his own.", + "author": "Confucius" + }, + { + "content": "There is no need for temples, no need for complicated philosophies. My brain and my heart are my temples; my philosophy is kindness.", + "author": "Dalai Lama" + }, + { + "content": "It is better to have enough ideas for some of them to be wrong, than to be always right by having no ideas at all.", + "author": "Edward de Bono" + }, + { + "content": "Friends show their love in times of trouble, not in happiness.", + "author": "Euripides" + }, + { + "content": "I would maintain that thanks are the highest form of thought, and that gratitude is happiness doubled by wonder.", + "author": "G. K. Chesterton" + }, + { + "content": "I'd rather regret the things that I have done than the things that I have not done.", + "author": "Lucille Ball" + }, + { + "content": "Prejudice is a burden that confuses the past, threatens the future and renders the present inaccessible.", + "author": "Maya Angelou" + }, + { + "content": "If you spend your whole life waiting for the storm, you'll never enjoy the sunshine.", + "author": "Morris West" + }, + { + "content": "We do not quit playing because we grow old, we grow old because we quit playing.", + "author": "Oliver Wendell Holmes Jr." + }, + { + "content": "Do not follow where the path may lead. Go, instead, where there is no path and leave a trail.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "You cannot be lonely if you like the person you're alone with.", + "author": "Wayne Dyer" + }, + { + "content": "God has given you one face, and you make yourself another.", + "author": "William Shakespeare" + }, + { + "content": "You got to be careful if you don't know where you're going, because you might not get there.", + "author": "Yogi Berra" + }, + { + "content": "Whatever you do in life, surround yourself with smart people who'll argue with you.", + "author": "John Wooden" + }, + { + "content": "The truth is not for all men, but only for those who seek it.", + "author": "Ayn Rand" + }, + { + "content": "The human spirit must prevail over technology.", + "author": "Albert Einstein" + }, + { + "content": "Friends are the siblings God never gave us.", + "author": "Mencius" + }, + { + "content": "You win the victory when you yield to friends.", + "author": "Sophocles" + }, + { + "content": "Friendship is Love without his wings!", + "author": "Lord Byron" + }, + { + "content": "Blessed are the hearts that can bend; they shall never be broken.", + "author": "Albert Camus" + }, + { + "content": "Change will not come if we wait for some other person or some other time. We are the ones we've been waiting for. We are the change that we seek.", + "author": "Barack Obama" + }, + { + "content": "We make our own fortunes and we call them fate.", + "author": "Benjamin Disraeli" + }, + { + "content": "Life isn't about finding yourself. Life is about creating yourself.", + "author": "Bernard Shaw" + }, + { + "content": "The world cares very little about what a man or woman knows; it is what a man or woman is able to do that counts.", + "author": "Booker T. Washington" + }, + { + "content": "The trick is in what one emphasizes. We either make ourselves miserable, or we make ourselves happy. The amount of work is the same.", + "author": "Carlos Castaneda" + }, + { + "content": "The cautious seldom err.", + "author": "Confucius" + }, + { + "content": "It is difficult to achieve a spirit of genuine cooperation as long as people remain indifferent to the feelings and happiness of others.", + "author": "Dalai Lama" + }, + { + "content": "The fox has many tricks. The hedgehog has but one. But that is the best of all.", + "author": "Erasmus" + }, + { + "content": "A failure is a man who has blundered but is not capable of cashing in on the experience.", + "author": "Elbert Hubbard" + }, + { + "content": "Remember always that you not only have the right to be an individual, you have an obligation to be one.", + "author": "Eleanor Roosevelt" + }, + { + "content": "Never mistake motion for action.", + "author": "Ernest Hemingway" + }, + { + "content": "If there is no struggle, there is no progress.", + "author": "Frederick Douglass" + }, + { + "content": "Life is what happens while you are making other plans.", + "author": "John Lennon" + }, + { + "content": "Life without love is like a tree without blossoms or fruit.", + "author": "Kahlil Gibran" + }, + { + "content": "One who is too insistent on his own views, finds few to agree with him.", + "author": "Laozi" + }, + { + "content": "If you don't know where you are going, you will probably end up somewhere else.", + "author": "Laurence J. Peter" + }, + { + "content": "Strength does not come from physical capacity. It comes from an indomitable will.", + "author": "Mahatma Gandhi" + }, + { + "content": "You might well remember that nothing can bring you success but yourself.", + "author": "Napoleon Hill" + }, + { + "content": "It is not enough to have a good mind; the main thing is to use it well.", + "author": "René Descartes" + }, + { + "content": "Failure doesn't mean you are a failure it just means you haven't succeeded yet.", + "author": "Robert Schuller" + }, + { + "content": "Stay committed to your decisions, but stay flexible in your approach.", + "author": "Tony Robbins" + }, + { + "content": "If you do what you've always done, you'll get what you've always gotten.", + "author": "Tony Robbins" + }, + { + "content": "Knowledge comes, but wisdom lingers. It may not be difficult to store up in the mind a vast quantity of facts within a comparatively short time, but the ability to form judgments requires the severe discipline of hard work and the tempering heat of experience and maturity.", + "author": "Calvin Coolidge" + }, + { + "content": "If you're trying to achieve, there will be roadblocks. I've had them; everybody has had them. But obstacles don't have to stop you. If you run into a wall, don't turn around and give up. Figure out how to climb it, go through it, or work around it.", + "author": "Michael Jordan" + }, + { + "content": "What makes Superman a hero is not that he has power, but that he has the wisdom and the maturity to use the power wisely. From an acting point of view, that's how I approached the part.", + "author": "Christopher Reeve" + }, + { + "content": "The man who makes everything that leads to happiness depends upon himself, and not upon other men, has adopted the very best plan for living happily. This is the man of moderation, the man of manly character and of wisdom.", + "author": "Plato" + }, + { + "content": "You are a product of your environment. So choose the environment that will best develop you toward your objective. Analyze your life in terms of its environment. Are the things around you helping you toward success - or are they holding you back?", + "author": "W. Clement Stone" + }, + { + "content": "Technology is a word that describes something that doesn't work yet.", + "author": "Douglas Adams" + }, + { + "content": "Science and technology revolutionize our lives, but memory, tradition and myth frame our response.", + "author": "Arthur M. Schlesinger Jr." + }, + { + "content": "True friendship is a plant of slow growth, and must undergo and withstand the shocks of adversity, before it is entitled to the appellation.", + "author": "George Washington" + }, + { + "content": "It is the mark of an educated mind to be able to entertain a thought without accepting it.", + "author": "Aristotle" + }, + { + "content": "Better than a thousand hollow words, is one word that brings peace.", + "author": "Buddha" + }, + { + "content": "The heart has eyes which the brain knows nothing of.", + "author": "Charles Henry Parkhurst" + }, + { + "content": "When you see a good person, think of becoming like him. When you see someone not so good, reflect on your own weak points.", + "author": "Confucius" + }, + { + "content": "We have committed the Golden Rule to memory; let us now commit it to life.", + "author": "Edwin Markham" + }, + { + "content": "The thing always happens that you really believe in; and the belief in a thing makes it happen.", + "author": "Frank Lloyd Wright" + }, + { + "content": "Don't be afraid to go out on a limb. That's where the fruit is.", + "author": "H. Jackson Brown Jr." + }, + { + "content": "If one advances confidently in the direction of his dream, and endeavors to live the life which he had imagines, he will meet with a success unexpected in common hours.", + "author": "Henry David Thoreau" + }, + { + "content": "I care not so much what I am to others as what I am to myself. I will be rich by myself, and not by borrowing.", + "author": "Michel de Montaigne" + }, + { + "content": "Happiness is when what you think, what you say, and what you do are in harmony.", + "author": "Mahatma Gandhi" + }, + { + "content": "As we are liberated from our own fear, our presence automatically liberates others.", + "author": "Nelson Mandela" + }, + { + "content": "Efficiency is doing things right; effectiveness is doing the right things.", + "author": "Peter Drucker" + }, + { + "content": "I have often regretted my speech, never my silence.", + "author": "Publilius Syrus" + }, + { + "content": "You teach best what you most need to learn.", + "author": "Richard Bach" + }, + { + "content": "One's philosophy is not best expressed in words; it is expressed in the choices one makes... and the choices we make are ultimately our responsibility.", + "author": "Eleanor Roosevelt" + }, + { + "content": "It is the neglect of timely repair that makes rebuilding necessary.", + "author": "Richard Whately" + }, + { + "content": "Use what talents you possess; the woods would be very silent if no birds sang there except those that sang best.", + "author": "Henry van Dyke Jr." + }, + { + "content": "In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you.", + "author": "Janet Jackson" + }, + { + "content": "If you want to go east, don't go west.", + "author": "Ramakrishna" + }, + { + "content": "Ignorance and bungling with love are better than wisdom and skill without.", + "author": "Henry David Thoreau" + }, + { + "content": "Computers are like bikinis. They save people a lot of guesswork.", + "author": "Sam Ewing" + }, + { + "content": "Every friendship is different because everyone's personality is different.", + "author": "Nargis Fakhri" + }, + { + "content": "The friend who can be silent with us in a moment of despair or confusion, who can stay with us in an hour of grief and bereavement, who can tolerate not knowing... not healing, not curing... that is a friend who cares.", + "author": "Henri Nouwen" + }, + { + "author": "Woody Allen", + "content": "It is impossible to experience one's death objectively and still carry a tune." + }, + { + "content": "One may say the eternal mystery of the world is its comprehensibility.", + "author": "Albert Einstein" + }, + { + "content": "We should all be thankful for those people who rekindle the inner spirit.", + "author": "Albert Schweitzer" + }, + { + "content": "I'm not in this world to live up to your expectations and you're not in this world to live up to mine.", + "author": "Bruce Lee" + }, + { + "content": "There is no failure except in no longer trying.", + "author": "Elbert Hubbard" + }, + { + "content": "We are either progressing or retrograding all the while. There is no such thing as remaining stationary in this life.", + "author": "James Freeman Clarke" + }, + { + "content": "There is no greater harm than that of time wasted.", + "author": "Michelangelo" + }, + { + "content": "Ideas are the beginning points of all fortunes.", + "author": "Napoleon Hill" + }, + { + "content": "Nothing ever goes away until it has taught us what we need to know.", + "author": "Pema Chödrön" + }, + { + "content": "If facts are the seeds that later produce knowledge and wisdom, then the emotions and the impressions of the senses are the fertile soil in which the seeds must grow.", + "author": "Rachel Carson" + }, + { + "content": "Excellence is not a skill. It is an attitude.", + "author": "Ralph Marston" + }, + { + "content": "Sometimes it is better to lose and do the right thing than to win and do the wrong thing.", + "author": "Tony Blair" + }, + { + "content": "Where there is great love, there are always miracles.", + "author": "Willa Cather" + }, + { + "content": "A tree is known by its fruit; a man by his deeds. A good deed is never lost; he who sows courtesy reaps friendship, and he who plants kindness gathers love.", + "author": "Basil of Caesarea" + }, + { + "content": "Never interrupt your enemy when he is making a mistake.", + "author": "Napoleon" + }, + { + "content": "We respect our elders. There is wisdom that comes from experience, and I am not going to stop learning from wise counsel.", + "author": "Marcia Fudge" + }, + { + "content": "Not engaging in ignorance is wisdom.", + "author": "Bodhidharma" + }, + { + "content": "Wisdom has its root in goodness, not goodness its root in wisdom.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "There is a magnet in your heart that will attract true friends. That magnet is unselfishness, thinking of others first; when you learn to live for others, they will live for you.", + "author": "Paramahansa Yogananda" + }, + { + "content": "A true friend is the greatest of all blessings, and that which we take the least care of all to acquire.", + "author": "François de La Rochefoucauld" + }, + { + "content": "You can always tell a real friend: when you've made a fool of yourself he doesn't feel you've done a permanent job.", + "author": "Laurence J. Peter" + }, + { + "content": "Friendship is one of our most treasured relationships, but it isn't codified and celebrated; it's never going to give you a party.", + "author": "Hanya Yanagihara" + }, + { + "content": "A quarrel between friends, when made up, adds a new tie to friendship.", + "author": "Francis de Sales" + }, + { + "content": "Yesterday's home runs don't win today's games.", + "author": "Babe Ruth" + }, + { + "content": "Study the past, if you would divine the future.", + "author": "Confucius" + }, + { + "content": "Wherever you go, go with all your heart.", + "author": "Confucius" + }, + { + "content": "With the realization of one's own potential and self-confidence in one's ability, one can build a better world.", + "author": "Dalai Lama" + }, + { + "content": "Coming together is a beginning; keeping together is progress; working together is success.", + "author": "Edward Everett Hale" + }, + { + "content": "Happiness is not in the mere possession of money; it lies in the joy of achievement, in the thrill of creative effort.", + "author": "Franklin D. Roosevelt" + }, + { + "content": "It is fatal to enter any war without the will to win it.", + "author": "Douglas MacArthur" + }, + { + "content": "The eye sees only what the mind is prepared to comprehend.", + "author": "Henri Bergson" + }, + { + "content": "Don't smother each other. No one can grow in the shade.", + "author": "Leo Buscaglia" + }, + { + "content": "Everyone thinks of changing the world, but no one thinks of changing himself.", + "author": "Leo Tolstoy" + }, + { + "content": "That's the risk you take if you change: that people you've been involved with won't like the new you. But other people who do will come along.", + "author": "Lisa Alther" + }, + { + "content": "I'm selfish, impatient and a little insecure. I make mistakes, I am out of control and at times hard to handle. But if you can't handle me at my worst, then you sure as hell don't deserve me at my best.", + "author": "Marilyn Monroe" + }, + { + "content": "Courage is not the absence of fear, but simply moving on with dignity despite that fear.", + "author": "Pat Riley" + }, + { + "content": "Love is a serious mental disease.", + "author": "Plato" + }, + { + "content": "Our distrust is very expensive.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "To bring anything into your life, imagine that it's already there.", + "author": "Richard Bach" + }, + { + "_id": "9-V6Bzl0nfN-", + "content": "The trouble with most people is that they think with their hopes or fears or wishes rather than with their minds.", + "author": "Will Durant" + }, + { + "content": "The teacher who is indeed wise does not bid you to enter the house of his wisdom but rather leads you to the threshold of your mind.", + "author": "Kahlil Gibran" + }, + { + "content": "We live in a society bloated with data yet starved for wisdom. We're connected 24/7, yet anxiety, fear, depression and loneliness are at an all-time high. We must course-correct.", + "author": "Elizabeth Kapu'uwailani Lindsey" + }, + { + "content": "It has long been an axiom of mine that the little things are infinitely the most important.", + "author": "Arthur Conan Doyle" + }, + { + "content": "The day of fortune is like a harvest day, we must be busy when the corn is ripe.", + "author": "Torquato Tasso" + }, + { + "content": "The invariable mark of wisdom is to see the miraculous in the common.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "He who is taught to live upon little owes more to his father's wisdom than he who has a great deal left him does to his father's care.", + "author": "William C. Menninger" + }, + { + "content": "The greatest gift of life is friendship, and I have received it.", + "author": "Hubert Humphrey" + }, + { + "content": "The friendship that can cease has never been real.", + "author": "Jerome" + }, + { + "content": "Character is like a tree and reputation like a shadow. The shadow is what we think of it; the tree is the real thing.", + "author": "Abraham Lincoln" + }, + { + "content": "If you smile when no one else is around, you really mean it.", + "author": "Andy Rooney" + }, + { + "_id": "8IyWC1hl--Je", + "content": "You, yourself, as much as anybody in the entire universe, deserve your love and affection.", + "author": "Buddha" + }, + { + "content": "A jug fills drop by drop.", + "author": "Buddha" + }, + { + "content": "Your body is precious. It is our vehicle for awakening. Treat it with care.", + "author": "Buddha" + }, + { + "content": "If you look into your own heart, and you find nothing wrong there, what is there to worry about? What is there to fear?", + "author": "Confucius" + }, + { + "content": "Happiness resides not in possessions, and not in gold, happiness dwells in the soul.", + "author": "Democritus" + }, + { + "content": "A little more persistence, a little more effort, and what seemed hopeless failure may turn to glorious success.", + "author": "Elbert Hubbard" + }, + { + "content": "What worries you masters you.", + "author": "Haddon Robinson" + }, + { + "content": "Every great dream begins with a dreamer. Always remember, you have within you the strength, the patience, and the passion to reach for the stars to change the world.", + "author": "Harriet Tubman" + }, + { + "content": "To exist is to change, to change is to mature, to mature is to go on creating oneself endlessly.", + "author": "Henri Bergson" + }, + { + "content": "Love cures people - both the ones who give it and the ones who receive it.", + "author": "Karl Menninger" + }, + { + "content": "We must embrace pain and burn it as fuel for our journey.", + "author": "Kenji Miyazawa" + }, + { + "content": "It had long since come to my attention that people of accomplishment rarely sat back and let things happen to them. They went out and happened to things.", + "author": "Leonardo da Vinci" + }, + { + "content": "Wrinkles should merely indicate where smiles have been.", + "author": "Mark Twain" + }, + { + "content": "The beginning is always today.", + "author": "Mary Wollstonecraft" + }, + { + "content": "If one is lucky, a solitary fantasy can totally transform one million realities.", + "author": "Maya Angelou" + }, + { + "content": "Kindness is more important than wisdom, and the recognition of this is the beginning of wisdom.", + "author": "Theodore Isaac Rubin" + }, + { + "content": "I think people who are creative are the luckiest people on earth. I know that there are no shortcuts, but you must keep your faith in something Greater than you and keep doing what you love. Do what you love, and you will find the way to get it out to the world.", + "author": "Judy Collins" + }, + { + "content": "The hours of folly are measured by the clock; but of wisdom, no clock can measure.", + "author": "William Blake" + }, + { + "content": "Of all the things which wisdom provides to make us entirely happy, much the greatest is the possession of friendship.", + "author": "Epicurus" + }, + { + "content": "If you have the guts to keep making mistakes, your wisdom and intelligence leap forward with huge momentum.", + "author": "Holly Near" + }, + { + "content": "We all grow up. Hopefully, we get wiser. Age brings wisdom, and fatherhood changes one's life completely.", + "author": "Frank Abagnale" + }, + { + "content": "When an opponent comes forward, move in and greet him; if he wants to pull back, send him on his way.", + "author": "Morihei Ueshiba" + }, + { + "content": "Never explain - your friends do not need it and your enemies will not believe you anyway.", + "author": "Elbert Hubbard" + }, + { + "content": "A friend is, as it were, a second self.", + "author": "Cicero" + }, + { + "content": "In the middle of every difficulty lies opportunity.", + "author": "Albert Einstein" + }, + { + "content": "The only real failure in life is not to be true to the best one knows.", + "author": "Buddha" + }, + { + "content": "A man who doesn't trust himself can never really trust anyone else.", + "author": "Jean François Paul de Gondi" + }, + { + "content": "Be here now. Be someplace else later. Is that so complicated?", + "author": "David Bader" + }, + { + "content": "You must welcome change as the rule but not as your ruler.", + "author": "Denis Waitley" + }, + { + "content": "Men are disturbed not by things, but by the view which they take of them.", + "author": "Epictetus" + }, + { + "content": "Just trust yourself, then you will know how to live.", + "author": "Johann Wolfgang von Goethe" + }, + { + "content": "He who knows others is wise. He who knows himself is enlightened.", + "author": "Laozi" + }, + { + "content": "All our knowledge has its origins in our perceptions.", + "author": "Leonardo da Vinci" + }, + { + "content": "Until you value yourself, you won't value your time. Until you value your time, you won't do anything with it.", + "author": "M. Scott Peck" + }, + { + "content": "Never doubt that a small group of thoughtful, committed people can change the world. Indeed. It is the only thing that ever has.", + "author": "Margaret Mead" + }, + { + "content": "Nothing will work unless you do.", + "author": "Maya Angelou" + }, + { + "content": "Fears are nothing more than a state of mind.", + "author": "Napoleon Hill" + }, + { + "content": "Thought is the blossom; language the bud; action the fruit behind it.", + "author": "Ralph Waldo Emerson" + }, + { + "content": "Argue for your limitations, and sure enough they're yours.", + "author": "Richard Bach" + }, + { + "content": "Good judgment comes from experience, and a lot of that comes from bad judgment.", + "author": "Will Rogers" + }, + { + "content": "He that is giddy thinks the world turns round.", + "author": "William Shakespeare" + }, + { + "content": "Wisdom ceases to be wisdom when it becomes too proud to weep, too grave to laugh, and too selfish to seek other than itself.", + "author": "Kahlil Gibran" + }, + { + "content": "In wisdom gathered over time I have found that every experience is a form of exploration.", + "author": "Ansel Adams" + }, + { + "content": "The greater our knowledge increases the more our ignorance unfolds.", + "author": "John F. Kennedy" + }, + { + "content": "Mistakes are the usual bridge between inexperience and wisdom.", + "author": "Phyllis Grissim-Theroux" + }, + { + "content": "Our character is what we do when we think no one is looking.", + "author": "H. Jackson Brown Jr." + }, + { + "content": "Life is the only real counselor; wisdom unfiltered through personal experience does not become a part of the moral tissue.", + "author": "Edith Wharton" + }, + { + "content": "One of the most beautiful qualities of true friendship is to understand and to be understood.", + "author": "Seneca the Younger" + }, + { + "content": "Friendship is a very taxing and arduous form of leisure activity.", + "author": "Mortimer J. Adler" + }, + { + "content": "You can't blame gravity for falling in love.", + "author": "Albert Einstein" + }, + { + "content": "Success is not the key to happiness. Happiness is the key to success. If you love what you are doing, you will be successful.", + "author": "Albert Schweitzer" + }, + { + "content": "The least of things with a meaning is worth more in life than the greatest of things without it.", + "author": "Carl Jung" + }, + { + "_id": "Oh-e1-oygRPX", + "content": "To be wronged is nothing unless you continue to remember it.", + "author": "Confucius" + }, + { + "content": "Friends are those rare people who ask how we are and then wait to hear the answer.", + "author": "Ed Cunningham" + }, + { + "content": "You can stand tall without standing on someone. You can be a victor without having victims.", + "author": "Harriet Woods" + }, + { + "content": "Some people thrive on huge, dramatic change. Some people prefer the slow and steady route. Do what's right for you.", + "author": "Julie Morgenstern" + }, + { + "content": "He who controls others may be powerful, but he who has mastered himself is mightier still.", + "author": "Laozi" + }, + { + "_id": "Log-YUXR2i-", + "content": "Truth is powerful and it prevails.", + "author": "Sojourner Truth" + }, + { + "content": "Take up one idea. Make that one idea your life - think of it, dream of it, live on that idea. Let the brain, muscles, nerves, every part of your body, be full of that idea, and just leave every other idea alone. This is the way to success.", + "author": "Swami Vivekananda" + }, + { + "content": "Don't talk about what you have done or what you are going to do.", + "author": "Thomas Jefferson" + }, + { + "content": "The things that one most wants to do are the things that are probably most worth doing.", + "author": "Winifred Holtby" + }, + { + "content": "Wisdom, compassion, and courage are the three universally recognized moral qualities of men.", + "author": "Confucius" + }, + { + "content": "With age comes wisdom and a high sex drive. And the wisdom to enjoy it.", + "author": "Amber Valletta" + }, + { + "content": "Make it your habit not to be critical about small things.", + "author": "Edward Everett Hale" + }, + { + "content": "Silence is the sleep that nourishes wisdom.", + "author": "Francis Bacon" + }, + { + "content": "When a thing is done, it's done. Don't look back. Look forward to your next objective.", + "author": "George Marshall" + }, + { + "content": "There is some self-interest behind every friendship. There is no friendship without self-interests. This is a bitter truth.", + "author": "Chanakya" + }, + { + "content": "Two persons cannot long be friends if they cannot forgive each other's little failings.", + "author": "Jean de La Bruyère" + }, + { + "content": "Friendship, like credit, is highest when it is not used.", + "author": "Elbert Hubbard" + }, + { + "content": "Friendship increases in visiting friends, but in visiting them seldom.", + "author": "Francis Bacon" + }, + { + "author": "Helmut Schmidt", + "content": "The biggest room in the world is room for improvement." + }, + { + "author": "Amy Poehler", + "content": "There's power in looking silly and not caring that you do." + }, + { + "author": "Eric Hoffer", + "content": "In times of change, learners inherit the earth, while the learned find themselves beautifully equipped to deal with a world that no longer exists." + }, + { + "author": "Henry Ford", + "content": "Whether you think you can or you think you can't, you are right." + }, + { + "author": "Larry Page", + "content": "If you're changing the world, you're working on important things. You're excited to get up in the morning." + }, + { + "author": "Neil Gaiman", + "content": "The one thing that you have that nobody else has is you. Your voice, your mind, your story, your vision. So write and draw and build and play and dance and live as only you can." + }, + { + "author": "Winston Churchill", + "content": "Now this is not the end. It is not even the beginning of the end. But it is, perhaps, the end of the beginning.", + "tags": [] + }, + { + "author": "Winston Churchill", + "content": "If you're going through hell, keep going." + }, + { + "author": "Winston Churchill", + "content": "To improve is to change; to be perfect is to change often." + }, + { + "author": "Winston Churchill", + "content": "The best argument against democracy is a five-minute conversation with the average voter." + }, + { + "author": "Winston Churchill", + "content": "Attitude is a little thing that makes a big difference.", + "tags": [] + }, + { + "author": "Winston Churchill", + "content": "A lie gets halfway around the world before the truth has a chance to get its pants on." + }, + { + "author": "Winston Churchill", + "content": "I am fond of pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals." + }, + { + "author": "Winston Churchill", + "content": "Success consists of going from failure to failure without loss of enthusiasm." + }, + { + "author": "Winston Churchill", + "content": "You can always count on Americans to do the right thing - after they've tried everything else." + }, + { + "author": "Winston Churchill", + "content": "The truth is incontrovertible. Malice may attack it, ignorance may deride it, but in the end, there it is." + }, + { + "author": "Winston Churchill", + "content": "All the great things are simple, and many can be expressed in a single word: freedom, justice, honor, duty, mercy, hope." + }, + { + "author": "Winston Churchill", + "content": "History is written by the victors." + }, + { + "author": "Winston Churchill", + "content": "The farther backward you can look, the farther forward you can see." + }, + { + "author": "Winston Churchill", + "content": "I am an optimist. It does not seem too much use being anything else.", + "tags": [] + }, + { + "author": "Winston Churchill", + "content": "It is no use saying, 'We are doing our best.' You have got to succeed in doing what is necessary." + }, + { + "author": "Winston Churchill", + "content": "Russia is a riddle wrapped in a mystery inside an enigma." + }, + { + "author": "Winston Churchill", + "content": "An appeaser is one who feeds a crocodile, hoping it will eat him last." + }, + { + "author": "Winston Churchill", + "content": "If we open a quarrel between past and present, we shall find that we have lost the future." + }, + { + "author": "Winston Churchill", + "content": "The inherent vice of capitalism is the unequal sharing of blessings; the inherent virtue of socialism is the equal sharing of miseries." + }, + { + "author": "Winston Churchill", + "content": "In wartime, truth is so precious that she should always be attended by a bodyguard of lies." + }, + { + "author": "Winston Churchill", + "content": "We are masters of the unsaid words, but slaves of those we let slip out." + }, + { + "author": "Winston Churchill", + "content": "Courage is rightly esteemed the first of human qualities... because it is the quality which guarantees all others." + }, + { + "author": "Winston Churchill", + "content": "Nothing in life is so exhilarating as to be shot at without result." + }, + { + "author": "Winston Churchill", + "content": "I am always ready to learn although I do not always like being taught." + }, + { + "author": "Abraham Lincoln", + "content": "You can fool all the people some of the time, and some of the people all the time, but you cannot fool all the people all the time." + }, + { + "author": "Abraham Lincoln", + "content": "Sir, my concern is not whether God is on our side; my greatest concern is to be on God's side, for God is always right." + }, + { + "author": "Abraham Lincoln", + "content": "You cannot escape the responsibility of tomorrow by evading it today." + }, + { + "author": "Abraham Lincoln", + "content": "Government of the people, by the people, for the people, shall not perish from the Earth." + }, + { + "author": "Abraham Lincoln", + "content": "All that I am, or hope to be, I owe to my angel mother." + }, + { + "author": "Abraham Lincoln", + "content": "Most folks are as happy as they make up their minds to be." + }, + { + "author": "Abraham Lincoln", + "content": "The ballot is stronger than the bullet." + }, + { + "author": "Abraham Lincoln", + "content": "The philosophy of the school room in one generation will be the philosophy of government in the next." + }, + { + "author": "Abraham Lincoln", + "content": "How many legs does a dog have if you call his tail a leg? Four. Saying that a tail is a leg doesn't make it a leg." + }, + { + "author": "Abraham Lincoln", + "content": "Always bear in mind that your own resolution to succeed is more important than any other." + }, + { + "author": "Abraham Lincoln", + "content": "If I were two-faced, would I be wearing this one?" + }, + { + "author": "Abraham Lincoln", + "content": "I will prepare and some day my chance will come." + }, + { + "author": "Abraham Lincoln", + "content": "No man has a good enough memory to be a successful liar." + }, + { + "author": "Abraham Lincoln", + "content": "I am not bound to win, but I am bound to be true. I am not bound to succeed, but I am bound to live by the light that I have. I must stand with anybody that stands right, and stand with him while he is right, and part with him when he goes wrong." + }, + { + "author": "Abraham Lincoln", + "content": "I am a firm believer in the people. If given the truth, they can be depended upon to meet any national crisis. The great point is to bring them the real facts." + }, + { + "author": "Abraham Lincoln", + "content": "We the people are the rightful masters of both Congress and the courts, not to overthrow the Constitution but to overthrow the men who pervert the Constitution." + }, + { + "author": "Abraham Lincoln", + "content": "I have always found that mercy bears richer fruits than strict justice." + }, + { + "author": "Abraham Lincoln", + "content": "When I do good I feel good, when I do bad I feel bad, and that's my religion." + }, + { + "author": "Abraham Lincoln", + "content": "It has been my experience that folks who have no vices have very few virtues." + }, + { + "author": "Alan Watts", + "content": "The only way to make sense out of change is to plunge into it, move with it, and join the dance." + }, + { + "author": "Alan Watts", + "content": "To have faith is to trust yourself to the water. When you swim you don't grab hold of the water, because if you do you will sink and drown. Instead you relax, and float." + }, + { + "author": "Alan Watts", + "content": "I have realized that the past and future are real illusions, that they exist in the present, which is what there is and all there is." + }, + { + "author": "Alan Watts", + "content": "But the attitude of faith is to let go, and become open to truth, whatever it might turn out to be." + }, + { + "author": "Alan Watts", + "content": "We cannot be more sensitive to pleasure without being more sensitive to pain." + }, + { + "author": "Alan Watts", + "content": "Never pretend to a love which you do not actually feel, for love is not ours to command." + }, + { + "author": "Alan Watts", + "content": "But I'll tell you what hermits realize. If you go off into a far, far forest and get very quiet, you'll come to understand that you're connected with everything." + }, + { + "author": "Alan Watts", + "content": "You and I are all as much continuous with the physical universe as a wave is continuous with the ocean." + }, + { + "author": "Alan Watts", + "content": "You don't look out there for God, something in the sky, you look in you." + }, + { + "author": "Alan Watts", + "content": "How is it possible that a being with such sensitive jewels as the eyes, such enchanted musical instruments as the ears, and such fabulous arabesque of nerves as the brain can experience itself anything less than a god." + }, + { + "author": "Alan Watts", + "content": "No work or love will flourish out of guilt, fear, or hollowness of heart, just as no valid plans for the future can be made by those who have no capacity for living now." + }, + { + "author": "Alan Watts", + "content": "The ego is nothing other than the focus of conscious attention.", + "tags": [] + }, + { + "author": "Alan Watts", + "content": "Things are as they are. Looking out into it the universe at night, we make no comparisons between right and wrong stars, nor between well and badly arranged constellations." + }, + { + "author": "Alan Watts", + "content": "You are that vast thing that you see far, far off with great telescopes." + }, + { + "author": "Alan Watts", + "content": "I owe my solitude to other people." + }, + { + "author": "Alan Watts", + "content": "Trying to define yourself is like trying to bite your own teeth." + }, + { + "author": "Alan Watts", + "content": "Unless one is able to live fully in the present, the future is a hoax." + }, + { + "author": "Alan Watts", + "content": "And the attitude of faith is the very opposite of clinging to belief, of holding on." + }, + { + "author": "Alan Watts", + "content": "So then, the relationship of self to other is the complete realization that loving yourself is impossible without loving everything defined as other than yourself." + }, + { + "author": "Alan Watts", + "content": "But at any rate, the point is that God is what nobody admits to being, and everybody really is." + }, + { + "author": "Alan Watts", + "content": "Technology is destructive only in the hands of people who do not realize that they are one and the same process as the universe." + }, + { + "author": "Michael Jordan", + "content": "I've missed more than 9000 shots in my career. I've lost almost 300 games. 26 times, I've been trusted to take the game winning shot and missed. I've failed over and over and over again in my life. And that is why I succeed." + }, + { + "author": "Henry David Thoreau", + "content": "Many men go fishing all of their lives without knowing that it is not fish they are after." + }, + { + "author": "Vince Lombardi", + "content": "Winners never quit and quitters never win." + }, + { + "author": "Babe Ruth", + "content": "The way a team plays as a whole determines its success. You may have the greatest bunch of individual stars in the world, but if they don't play together, the club won't be worth a dime." + }, + { + "author": "Bob Feller", + "content": "Every day is a new opportunity. You can build on yesterday's success or put its failures behind and start over again. That's the way life is, with a new game every day, and that's the way baseball is." + }, + { + "author": "Dan Gable", + "content": "Gold medals aren't really made of gold. They're made of sweat, determination, and a hard-to-find alloy called guts." + }, + { + "author": "Bobby Unser", + "content": "Success is where preparation and opportunity meet." + }, + { + "author": "Kareem Abdul-Jabbar", + "content": "You can't win unless you learn how to lose." + }, + { + "author": "Barry Switzer", + "content": "Some people are born on third base and go through life thinking they hit a triple." + }, + { + "author": "Wayne Gretzky", + "content": "A good hockey player plays where the puck is. A great hockey player plays where the puck is going to be." + }, + { + "author": "Michael Phelps", + "content": "You can't put a limit on anything. The more you dream, the farther you get." + }, + { + "author": "Mia Hamm", + "content": "I am building a fire, and everyday I train, I add more fuel. At just the right moment, I light the match." + }, + { + "author": "Muhammad Ali", + "content": "It's just a job. Grass grows, birds fly, waves pound the sand. I beat people up." + }, + { + "author": "George Orwell", + "content": "Serious sport has nothing to do with fair play. It is bound up with hatred, jealousy, boastfulness, disregard of all rules and sadistic pleasure in witnessing violence. In other words, it is war minus the shooting." + }, + { + "author": "Eric Liddell", + "content": "God made me fast. And when I run, I feel His pleasure." + }, + { + "author": "Yogi Berra", + "content": "Half the lies they tell about me aren't true." + }, + { + "author": "P. G. Wodehouse", + "content": "To find a man's true character, play golf with him." + }, + { + "author": "Earl Monroe", + "content": "Just be patient. Let the game come to you. Don't rush. Be quick, but don't hurry." + }, + { + "author": "Billie Jean King", + "content": "Champions keep playing until they get it right." + }, + { + "author": "Heywood Broun", + "content": "Sports do not build character. They reveal it." + }, + { + "author": "Casey Stengel", + "content": "Finding good players is easy. Getting them to play as a team is another story." + }, + { + "author": "Reggie Jackson (basketball, born 1990)", + "content": "Fans don't boo nobodies." + }, + { + "author": "Shaquille O'Neal", + "content": "I'm tired of hearing about money, money, money, money, money. I just want to play the game, drink Pepsi, and wear Reebok." + }, + { + "author": "Ian Botham", + "content": "To me, it doesn't matter how good you are. Sport is all about playing and competing. Whatever you do in cricket and in sport, enjoy it, be positive and try to win." + }, + { + "author": "Knute Rockne", + "content": "One man practicing sportsmanship is far better than a hundred teaching it." + }, + { + "author": "William James", + "content": "Most people never run far enough on their first wind to find out they've got a second." + }, + { + "author": "Hank Aaron", + "content": "My motto was always to keep swinging. Whether I was in a slump or feeling badly or having trouble off the field, the only thing to do was keep swinging." + }, + { + "author": "Jim Bouton", + "content": "You spend a good piece of your life gripping a baseball and in the end it turns out that it was the other way around all the time." + }, + { + "author": "Rogers Hornsby", + "content": "People ask me what I do in winter when there's no baseball. I'll tell you what I do. I stare out the window and wait for spring." + }, + { + "author": "Ernie Banks", + "content": "The only way to prove that you're a good sport is to lose." + }, + { + "author": "Sandy Koufax", + "content": "Pitching is the art of instilling fear." + }, + { + "author": "Carl Lewis", + "content": "Life is about timing." + }, + { + "author": "Ted Williams", + "content": "Baseball is the only field of endeavor where a man can succeed three times out of ten and be considered a good performer." + }, + { + "author": "Robert Griffin III", + "content": "Football is football and talent is talent. But the mindset of your team makes all the difference." + }, + { + "author": "Erma Bombeck", + "content": "If a man watches three football games in a row, he should be declared legally dead." + }, + { + "author": "Joe Adcock", + "content": "Trying to sneak a fastball past Hank Aaron is like trying to sneak the sunrise past a rooster." + }, + { + "author": "Mike Singletary (basketball)", + "content": "Do you know what my favorite part of the game is? The opportunity to play." + }, + { + "author": "Bob Knight", + "content": "You don't play against opponents, you play against the game of basketball." + }, + { + "author": "Woodrow Wilson", + "content": "Golf is a game in which one endeavors to control a ball with implements ill adapted for the purpose." + }, + { + "author": "Billie Jean King", + "content": "Tennis is a perfect combination of violent action taking place in an atmosphere of total tranquillity." + }, + { + "author": "Arnold Palmer", + "content": "What other people may find in poetry or art museums, I find in the flight of a good drive." + }, + { + "author": "Hugo Black", + "content": "When I was 40, my doctor advised me that a man in his 40s shouldn't play tennis. I heeded his advice carefully and could hardly wait until I reached 50 to start again." + }, + { + "author": "John Madden", + "content": "The fewer rules a coach has, the fewer rules there are for players to break." + }, + { + "author": "Mark Twain", + "content": "Whenever you find yourself on the side of the majority, it is time to pause and reflect." + }, + { + "author": "Colin Powell", + "content": "There are no secrets to success. It is the result of preparation, hard work, and learning from failure." + }, + { + "author": "Seneca the Younger", + "content": "If one does not know to which port one is sailing, no wind is favorable." + }, + { + "author": "J. Paul Getty", + "content": "If you owe the bank $100 that's your problem. If you owe the bank $100 million, that's the bank's problem." + }, + { + "author": "Elon Musk", + "content": "If you're trying to create a company, it's like baking a cake. You have to have all the ingredients in the right proportion." + }, + { + "author": "Sam Walton", + "content": "There is only one boss. The customer. And he can fire everybody in the company from the chairman on down, simply by spending his money somewhere else." + }, + { + "author": "Ambrose Bierce", + "content": "The gambling known as business looks with austere disfavor upon the business known as gambling." + }, + { + "author": "Tom Brokaw", + "content": "It's easy to make a buck. It's a lot tougher to make a difference." + }, + { + "author": "Theodore Isaac Rubin", + "content": "Happiness does not come from doing easy work but from the afterglow of satisfaction that comes after the achievement of a difficult task that demanded our best." + }, + { + "author": "Jeff Bezos", + "content": "A brand for a company is like a reputation for a person. You earn reputation by trying to do hard things well." + }, + { + "author": "Peter Drucker", + "content": "The entrepreneur always searches for change, responds to it, and exploits it as an opportunity." + }, + { + "author": "Don Marquis", + "content": "Ideas pull the trigger, but instinct loads the gun." + }, + { + "author": "Jack Welch", + "content": "An organization's ability to learn, and translate that learning into action rapidly, is the ultimate competitive advantage." + }, + { + "author": "Thomas Jefferson", + "content": "I hope we shall crush in its birth the aristocracy of our monied corporations which dare already to challenge our government to a trial by strength, and bid defiance to the laws of our country." + }, + { + "author": "Napoleon Hill", + "content": "Effort only fully releases its reward after a person refuses to quit." + }, + { + "author": "Henry Ford", + "content": "A business that makes nothing but money is a poor business." + }, + { + "author": "Aristotle Onassis", + "content": "The secret of business is to know something that nobody else knows." + }, + { + "author": "Charles F. Kettering", + "content": "If you want to kill any idea in the world, get a committee working on it." + }, + { + "author": "Laurence J. Peter", + "content": "An economist is an expert who will know tomorrow why the things he predicted yesterday didn't happen today." + }, + { + "author": "Dee Hock", + "content": "An organization, no matter how well designed, is only as good as the people who live and work in it." + }, + { + "author": "Leo Rosten", + "content": "First-rate people hire first-rate people; second-rate people hire third-rate people." + }, + { + "_id": "T-E-4pGn5i1", + "author": "Olivier Messiaen", + "content": "One of the tests of leadership is the ability to recognize a problem before it becomes an emergency." + }, + { + "author": "Confucius", + "content": "The superior man understands what is right; the inferior man understands what will sell." + }, + { + "author": "Mary Kay Ash", + "content": "Everyone has an invisible sign hanging from their neck saying, 'Make me feel important.' Never forget this message when working with people." + }, + { + "author": "Niccolò Machiavelli", + "content": "No enterprise is more likely to succeed than one concealed from the enemy until it is ripe for execution." + }, + { + "author": "Harold Geneen", + "content": "In the business world, everyone is paid in two coins: cash and experience. Take the experience first; the cash will come later." + }, + { + "author": "Robert Kiyosaki", + "content": "When times are bad is when the real entrepreneurs emerge." + }, + { + "author": "André Malraux", + "content": "To command is to serve, nothing more and nothing less." + }, + { + "author": "John Kenneth Galbraith", + "content": "Meetings are indispensable when you don't want to do anything." + }, + { + "author": "Howard H. Aiken", + "content": "Don't worry about people stealing your ideas. If your ideas are any good, you'll have to ram them down people's throats." + }, + { + "author": "Edward Gibbon", + "content": "Our work is the presentation of our capabilities." + }, + { + "author": "Warren Bennis", + "content": "Trust is the lubrication that makes it possible for organizations to work." + }, + { + "author": "Elon Musk", + "content": "When something is important enough, you do it even if the odds are not in your favor." + }, + { + "author": "Ralph Marston", + "content": "What you do today can improve all your tomorrows." + }, + { + "author": "H. G. Wells", + "content": "If you fell down yesterday, stand up today." + }, + { + "author": "George S. Patton", + "content": "A good plan violently executed now is better than a perfect plan executed next week." + }, + { + "author": "Ken Venturi", + "content": "I don't believe you have to be better than everybody else. I believe you have to be better than you ever thought you could be." + }, + { + "author": "Johann Wolfgang von Goethe", + "content": "Knowing is not enough; we must apply. Willing is not enough; we must do." + }, + { + "author": "W. Clement Stone", + "content": "Aim for the moon. If you miss, you may hit a star." + }, + { + "author": "Sam Levenson", + "content": "Don't watch the clock; do what it does. Keep going." + }, + { + "author": "Benjamin Disraeli", + "content": "Never complain and never explain." + }, + { + "author": "Robert Schuller", + "content": "Problems are not stop signs, they are guidelines." + }, + { + "author": "John F. Kennedy", + "content": "Things do not happen. Things are made to happen." + }, + { + "author": "Amelia Earhart", + "content": "The most effective way to do it, is to do it." + }, + { + "author": "Pauline Kael", + "content": "Where there is a will, there is a way. If there is a chance in a million that you can do something, anything, to keep what you want from ending, do it. Pry the door open or, if need be, wedge your foot in that door and keep it open." + }, + { + "author": "Babe Ruth", + "content": "You just can't beat the person who never gives up." + }, + { + "author": "Harriet Beecher Stowe", + "content": "Never give up, for that is just the place and time that the tide will turn." + }, + { + "author": "Kyle Chandler", + "content": "Opportunity does not knock, it presents itself when you beat down the door." + }, + { + "author": "Ayn Rand", + "content": "A creative man is motivated by the desire to achieve, not by the desire to beat others." + }, + { + "author": "Nikos Kazantzakis", + "content": "In order to succeed, we must first believe that we can." + }, + { + "author": "William Blake", + "content": "No bird soars too high if he soars with his own wings." + } +] \ No newline at end of file diff --git a/app/src/main/assets/release_notes/notes.json b/app/src/main/assets/release_notes/notes.json index a98bff24..c44d304a 100644 --- a/app/src/main/assets/release_notes/notes.json +++ b/app/src/main/assets/release_notes/notes.json @@ -1,4 +1,24 @@ [ + { + "version": "3.13.0", + "code": "454", + "note": "Added:\n- Post random quotes\n- Group reblogs in home timeline\n- Rename Nitter timelines\n- Android 13 support\n- Pagination with search / trending\n- Allow to remove left margin in messages (default: disabled)\n\nChanged:\n- Display translate button only when language is different\n- Respect blank spaces between words in messages\n- Focus button more accessible when editing media\n- Visual feedback for block on account list\n- Visual changes with compose / top bar\n- Use custom Nitter timeline name in manage timelines\n\nFixed:\n- Behavior with cw toggle\n- Truncated gimini links\n- Nav buttons not visible with media (Light theme)\n- Status bar with Android 5\n- Fix links not clickable\n- Fix deep links\n- Fix remote threads not fetched for some instances\n- Adding description to shared media\n- Open with another accounts\n- Chars size not respected for Android 5-6\n- Wrong instance fetched for instances.social\n- Bouncing Timeline on refresh\n- Links to mentions, tags, urls, not visible.\n- Custom channel sounds not applied\n- users with short username are not linked\n- Fix crashes" + }, + { + "version": "3.12.3", + "code": "453", + "note": "Added:\n- Pagination with search / trending\n\nFixed:\n- Long press on Nitter tabs\n- Open with another accounts\n- Chars size not respected for Android 5-6\n- Wrong instance fetched for instances.social" + }, + { + "version": "3.12.2", + "code": "452", + "note": "Added:\n- Rename Nitter timelines\n- Android 13 support\n\nChanged:\n- Visual feedback for block on account list\n- Visual changes with compose / top bar\n\nFixed:\n- Nav buttons not visible with media (Light theme)\n- Status bar with Android 5\n- Fix links not clickable\n- Fix deep links\n- Fix remote threads not fetched for some instances\n- Adding description to shared media\n- Fix crashes" + }, + { + "version": "3.12.1", + "code": "451", + "note": "Added:\n- Post random quotes\n- Group reblogs in home timeline\n\nChanged:\n- Display translate button only when language is different\n- Respect blank spaces between words in messages\n- Focus button more accessible when editing media\n\nFixed:\n- Behavior with cw toggle\n- Truncated gimini links" + }, { "version": "3.12.0", "code": "450", diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_ACN.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_ACN.csv deleted file mode 100644 index c743dfdf..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_ACN.csv +++ /dev/null @@ -1,15 +0,0 @@ -base_theme,1 -author,acn128 -name,ACN -theme_boost_header_color,-727060 -theme_text_header_1_line,-10865760 -theme_text_header_2_line,-11719543 -theme_statuses_color,-197380 -theme_link_color,-13681272 -theme_icons_color,-15395562 -pref_color_background,-1 -pref_color_navigation_bar,true -pref_color_status_bar,true -theme_accent,-14059009 -theme_text_color,-13027015 -theme_primary,-1 diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Breeze_Dark_Yellow.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Breeze_Dark_Yellow.csv deleted file mode 100644 index 3eec93e4..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Breeze_Dark_Yellow.csv +++ /dev/null @@ -1,13 +0,0 @@ -base_theme,2 -author,Fedilab -name,Breeze Dark - Yellow -theme_boost_header_color,-14012878 -theme_statuses_color,-14473687 -theme_link_color,-12734743 -theme_icons_color,-4340793 -pref_color_background,-15658735 -pref_color_navigation_bar,true -pref_color_status_bar,true -theme_accent,-148405 -theme_text_color,-1052431 -theme_primary,-13552069 diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Cyberpunk_Neon.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Cyberpunk_Neon.csv deleted file mode 100644 index 7fb99a5d..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Cyberpunk_Neon.csv +++ /dev/null @@ -1,15 +0,0 @@ -base_theme,2 -author,Roboron -name,Cyberpunk Neon -theme_boost_header_color,-16776697, -theme_text_header_1_line,-1441575, -theme_text_header_2_line,-5242717, -theme_statuses_color,-16181197, -theme_link_color,-1441575, -theme_icons_color,-16138810, -pref_color_background,-16774370, -pref_color_navigation_bar,true, -pref_color_status_bar,true, -theme_accent,-1441575, -theme_text_color,-16138810, -theme_primary,-16774370, diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Dark_Elephant.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Dark_Elephant.csv deleted file mode 100644 index 5bd65f60..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Dark_Elephant.csv +++ /dev/null @@ -1,15 +0,0 @@ -base_theme,0 -author,S1m -name,Dark Elephant -theme_boost_header_color,-13552317 -theme_text_header_1_line,-3479297 -theme_text_header_2_line,-7287815 -theme_statuses_color,-13552317 -theme_link_color,-11098143 -theme_icons_color,-789517 -pref_color_background,-14144456 -pref_color_navigation_bar,true -pref_color_status_bar,true -theme_accent,-13922086 -theme_text_color,-789517 -theme_primary,-14144456 diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Grey_Orange.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Grey_Orange.csv deleted file mode 100644 index 2c5c107c..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Grey_Orange.csv +++ /dev/null @@ -1,15 +0,0 @@ -base_theme,2 -author,Jøta Seth -name,Grey Orange -theme_boost_header_color,-14869219 -theme_text_header_1_line,-1 -theme_text_header_2_line,-1 -theme_statuses_color,-14145496 -theme_link_color,-26624 -theme_icons_color,-26624 -pref_color_background,-13092808 -pref_color_navigation_bar,true -pref_color_status_bar,true -theme_accent,-26624 -theme_text_color,-1 -theme_primary,-14408668 diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Gruvbox_OLED.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Gruvbox_OLED.csv deleted file mode 100644 index d03b3b81..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Gruvbox_OLED.csv +++ /dev/null @@ -1,15 +0,0 @@ -base_theme,2 -author,@AntoineD@h.kher.nl -name,Gruvbox OLED -theme_boost_header_color,-16777216 -theme_text_header_1_line,-265785 -theme_text_header_2_line,-6777062 -theme_statuses_color,-16777216 -theme_link_color,-2647775 -theme_icons_color,-7175308 -pref_color_background,-16777216 -pref_color_navigation_bar,true -pref_color_status_bar,true -theme_accent,-9921174 -theme_text_color,-265785 -theme_primary,-16777216 diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Less_Angry_Orange.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Less_Angry_Orange.csv deleted file mode 100644 index 26c89789..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Less_Angry_Orange.csv +++ /dev/null @@ -1,15 +0,0 @@ -base_theme,2 -author,AngryTux -name,Less Angry Orange -theme_boost_header_color,-15855063 -theme_text_header_1_line,-2128640 -theme_text_header_2_line,-5329234 -theme_statuses_color,-1 -theme_link_color,-12146699 -theme_icons_color,-2128640 -pref_color_background,-15987700 -pref_color_navigation_bar,true -pref_color_status_bar,true -theme_accent,-3968000 -theme_text_color,-197380 -theme_primary,-14408668 diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Mondstern_Fedilab.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Mondstern_Fedilab.csv deleted file mode 100644 index b9b23d8f..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Mondstern_Fedilab.csv +++ /dev/null @@ -1,15 +0,0 @@ -base_theme,2 -author,Mondstern -name,Mondstern Fedilab -theme_boost_header_color,-1, -theme_text_header_1_line,-13855804, -theme_text_header_2_line,-16227945, -theme_statuses_color,-14935012, -theme_link_color,-15542685, -theme_icons_color,-10723999, -pref_color_background,-15921907, -pref_color_navigation_bar,false, -pref_color_status_bar,false, -theme_accent,-15542685, -theme_text_color,-1, -theme_primary,-14474461, diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Nocturnal.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Nocturnal.csv deleted file mode 100644 index ed442449..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Nocturnal.csv +++ /dev/null @@ -1,13 +0,0 @@ -base_theme,2 -author,Fedilab -name,Nocturnal -theme_boost_header_color,-12895429 -theme_statuses_color,-13553359 -theme_link_color,-16747570 -theme_icons_color,-10158118 -pref_color_background,-14606047 -pref_color_navigation_bar,true -pref_color_status_bar,true -theme_accent,-13136013 -theme_text_color,-2236963 -theme_primary,-14013910 diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Photon_Dark.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Photon_Dark.csv deleted file mode 100644 index 3284a4e4..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Photon_Dark.csv +++ /dev/null @@ -1,15 +0,0 @@ -base_theme,2 -author,Jøta Seth -name,Photon Dark -theme_boost_header_color,-14145496 -theme_text_header_1_line,-1 -theme_text_header_2_line,-1 -theme_statuses_color,-14935012 -theme_link_color,-14059009 -theme_icons_color,-9474193 -pref_color_background,-15921907 -pref_color_navigation_bar,true -pref_color_status_bar,true -theme_accent,-14059009 -theme_text_color,-1 -theme_primary,-14474461 diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Solarized_Cyan_Accent.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Solarized_Cyan_Accent.csv deleted file mode 100644 index 5a259123..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Solarized_Cyan_Accent.csv +++ /dev/null @@ -1,15 +0,0 @@ -base_theme,1 -author,Animaly -name,Solarized - Cyan Accent -theme_boost_header_color,-69167 -theme_text_header_1_line,-4880128 -theme_text_header_2_line,-7102047 -theme_statuses_color,-133405 -theme_link_color,-14251054 -theme_icons_color,-10106727 -pref_color_background,-1120043 -pref_color_navigation_bar,true -pref_color_status_bar,true -theme_accent,-8021760 -theme_text_color,-16766154 -theme_primary,-1120043 diff --git a/app/src/main/assets/themes/contributors/Fedilab_theme_Solarized_Dark_Purple.csv b/app/src/main/assets/themes/contributors/Fedilab_theme_Solarized_Dark_Purple.csv deleted file mode 100644 index 6c434327..00000000 --- a/app/src/main/assets/themes/contributors/Fedilab_theme_Solarized_Dark_Purple.csv +++ /dev/null @@ -1,15 +0,0 @@ -base_theme,2 -author,Fedilab -name,Solarized Dark - Purple -theme_boost_header_color,-16506327 -theme_text_header_1_line,-1120043 -theme_text_header_2_line,-1120043 -theme_statuses_color,-16304574 -theme_link_color,-14251054 -theme_icons_color,-7102047 -pref_color_background,-16766154 -pref_color_navigation_bar,true -pref_color_status_bar,true -theme_accent,-9670204 -theme_text_color,-133405 -theme_primary,-16304574 diff --git a/app/src/main/assets/themes/cyanea_themes.json b/app/src/main/assets/themes/cyanea_themes.json deleted file mode 100644 index ae30ea31..00000000 --- a/app/src/main/assets/themes/cyanea_themes.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "theme_name": "Dark", - "base_theme": "DARK", - "primary": "#FF272727", - "primary_dark": "#FF272727", - "primary_light": "#FFd9e1e8", - "accent": "#FF2b90d9", - "accent_dark": "#FF1b80c9", - "accent_light": "#FF772b90d9", - "background": "#FF272727", - "background_dark": "#FF282c37", - "background_light": "#FF282c37", - "should_tint_statusbar": true, - "should_tint_navbar": true - }, - { - "theme_name": "Light", - "base_theme": "LIGHT", - "primary": "#FFFFFF", - "primary_dark": "#FFFFFFFF", - "primary_light": "#FFd9e1e8", - "accent": "#FF2b90d9", - "accent_dark": "#FF1b80c9", - "accent_light": "#FF772b90d9", - "background": "#FFFFFFFF", - "background_dark": "#FFFFFFFF", - "background_light": "#FFFFFFFF", - "should_tint_statusbar": true, - "should_tint_navbar": true - }, - { - "theme_name": "Black", - "base_theme": "DARK", - "primary": "#FF000000", - "primary_dark": "#FF000000", - "primary_light": "#FF000000", - "accent": "#FF606984", - "accent_dark": "#FF606984", - "accent_light": "#FF606984", - "background": "#FF000000", - "background_dark": "#FF000000", - "background_light": "#FF000000", - "should_tint_statusbar": true, - "should_tint_navbar": true - } -] \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java index 0ebb6a3b..cffdb745 100644 --- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java @@ -1076,8 +1076,12 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt Uri imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); if (imageUri != null) { Bundle b = new Bundle(); - b.putParcelable(Helper.ARG_SHARE_URI, imageUri); - CrossActionHelper.doCrossShare(BaseMainActivity.this, b); + List uris = new ArrayList<>(); + uris.add(imageUri); + Helper.createAttachmentFromUri(BaseMainActivity.this, uris, attachments -> { + b.putSerializable(Helper.ARG_MEDIA_ATTACHMENTS, new ArrayList<>(attachments)); + CrossActionHelper.doCrossShare(BaseMainActivity.this, b); + }); } else { Toasty.warning(BaseMainActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); } @@ -1087,7 +1091,10 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt ArrayList imageList = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); if (imageList != null) { Bundle b = new Bundle(); - b.putParcelableArrayList(Helper.ARG_SHARE_URI_LIST, imageList); + Helper.createAttachmentFromUri(BaseMainActivity.this, imageList, attachments -> { + b.putSerializable(Helper.ARG_MEDIA_ATTACHMENTS, new ArrayList<>(attachments)); + CrossActionHelper.doCrossShare(BaseMainActivity.this, b); + }); CrossActionHelper.doCrossShare(BaseMainActivity.this, b); } else { Toasty.warning(BaseMainActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show(); @@ -1118,8 +1125,8 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } //Here we know that the intent contains a valid URL if (!url.contains("medium.com")) { - Pattern link = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w._-]*[0-9]*)(/[0-9]+)?$"); - Matcher matcherLink = null; + Pattern link = Pattern.compile("https?://([\\da-z.-]+[à-ü]?\\.[a-z.]{2,10})/(@[\\w._-]*[0-9]*)(/[0-9]+)?$"); + Matcher matcherLink; matcherLink = link.matcher(url); if (matcherLink.find()) { if (currentAccount == null) { @@ -1137,10 +1144,14 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt CrossActionHelper.fetchRemoteStatus(BaseMainActivity.this, currentAccount, url, new CrossActionHelper.Callback() { @Override public void federatedStatus(Status status) { - Intent intent = new Intent(BaseMainActivity.this, ContextActivity.class); - intent.putExtra(Helper.ARG_STATUS, status); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); + if (status != null) { + Intent intent = new Intent(BaseMainActivity.this, ContextActivity.class); + intent.putExtra(Helper.ARG_STATUS, status); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } else { + Toasty.error(BaseMainActivity.this, getString(R.string.toast_error), Toasty.LENGTH_SHORT).show(); + } } @Override @@ -1155,12 +1166,16 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt @Override public void federatedAccount(app.fedilab.android.client.entities.api.Account account) { - Intent intent = new Intent(BaseMainActivity.this, ProfileActivity.class); - Bundle b = new Bundle(); - b.putSerializable(Helper.ARG_ACCOUNT, account); - intent.putExtras(b); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); + if (account != null) { + Intent intent = new Intent(BaseMainActivity.this, ProfileActivity.class); + Bundle b = new Bundle(); + b.putSerializable(Helper.ARG_ACCOUNT, account); + intent.putExtras(b); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } else { + Toasty.error(BaseMainActivity.this, getString(R.string.toast_error), Toasty.LENGTH_SHORT).show(); + } } }); } diff --git a/app/src/main/java/app/fedilab/android/activities/BaseActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseActivity.java index 2f2b870f..87193a7c 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseActivity.java @@ -19,8 +19,11 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.graphics.Color; import android.os.Build; import android.os.Bundle; +import android.view.Window; +import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; @@ -125,9 +128,15 @@ public class BaseActivity extends AppCompatActivity { } } super.onCreate(savedInstanceState); - if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) { ThemeHelper.adjustFontScale(this, getResources().getConfiguration()); } + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); + window.setNavigationBarColor(Color.BLACK); + } Helper.setLocale(this); } diff --git a/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java index e8f0111e..156d81b8 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java @@ -19,8 +19,11 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.graphics.Color; import android.os.Build; import android.os.Bundle; +import android.view.Window; +import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; @@ -111,6 +114,12 @@ public class BaseBarActivity extends AppCompatActivity { } } super.onCreate(savedInstanceState); + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); + window.setNavigationBarColor(Color.BLACK); + } if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) { ThemeHelper.adjustFontScale(this, getResources().getConfiguration()); } diff --git a/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java index 77f2df73..6b1c46f5 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java @@ -19,8 +19,11 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; +import android.graphics.Color; import android.os.Build; import android.os.Bundle; +import android.view.Window; +import android.view.WindowManager; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; @@ -111,6 +114,12 @@ public class BaseTransparentActivity extends AppCompatActivity { } } super.onCreate(savedInstanceState); + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.BLACK); + window.setNavigationBarColor(Color.BLACK); + } if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) { ThemeHelper.adjustFontScale(this, getResources().getConfiguration()); } diff --git a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java index 1688d292..88addf67 100644 --- a/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ComposeActivity.java @@ -109,6 +109,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana private ComposeAdapter composeAdapter; private boolean promptSaveDraft; private boolean restoredDraft; + private List sharedAttachments; private final BroadcastReceiver imageReceiver = new BroadcastReceiver() { @@ -126,6 +127,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana if (focusX != -2) { attachment.focus = focusX + "," + focusY; } + composeAdapter.notifyItemChanged(position); break; } @@ -146,8 +148,6 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana private app.fedilab.android.client.entities.api.Account accountMention; private String statusReplyId; private app.fedilab.android.client.entities.api.Account mentionBooster; - private ArrayList sharedUriList = new ArrayList<>(); - private Uri sharedUri; private String sharedSubject, sharedContent, sharedTitle, sharedDescription, shareURL, sharedUrlMedia; private String editMessageId; @@ -482,8 +482,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana mentionBooster = (app.fedilab.android.client.entities.api.Account) b.getSerializable(Helper.ARG_MENTION_BOOSTER); accountMention = (app.fedilab.android.client.entities.api.Account) b.getSerializable(Helper.ARG_ACCOUNT_MENTION); //Shared elements - sharedUriList = b.getParcelableArrayList(Helper.ARG_SHARE_URI_LIST); - sharedUri = b.getParcelable(Helper.ARG_SHARE_URI); + sharedAttachments = (ArrayList) b.getSerializable(Helper.ARG_MEDIA_ATTACHMENTS); sharedUrlMedia = b.getString(Helper.ARG_SHARE_URL_MEDIA); sharedSubject = b.getString(Helper.ARG_SHARE_SUBJECT, null); sharedContent = b.getString(Helper.ARG_SHARE_CONTENT, null); @@ -677,18 +676,19 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana }, 0, 10000); } - if (sharedUriList != null && sharedUriList.size() > 0) { - List uris = new ArrayList<>(sharedUriList); - Helper.createAttachmentFromUri(ComposeActivity.this, uris, attachment -> { + if (sharedAttachments != null && sharedAttachments.size() > 0) { + for (Attachment attachment : sharedAttachments) { composeAdapter.addAttachment(-1, attachment); - }); - } else if (sharedUri != null && !sharedUri.toString().startsWith("http")) { + } + } /*else if (sharedUri != null && !sharedUri.toString().startsWith("http")) { List uris = new ArrayList<>(); uris.add(sharedUri); - Helper.createAttachmentFromUri(ComposeActivity.this, uris, attachment -> { - composeAdapter.addAttachment(-1, attachment); + Helper.createAttachmentFromUri(ComposeActivity.this, uris, attachments -> { + for(Attachment attachment: attachments) { + composeAdapter.addAttachment(-1, attachment); + } }); - } else if (shareURL != null) { + } */ else if (shareURL != null) { Helper.download(ComposeActivity.this, sharedUrlMedia, new OnDownloadInterface() { @Override diff --git a/app/src/main/java/app/fedilab/android/activities/ContextActivity.java b/app/src/main/java/app/fedilab/android/activities/ContextActivity.java index 5a87a62d..4f9da9a6 100644 --- a/app/src/main/java/app/fedilab/android/activities/ContextActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ContextActivity.java @@ -34,6 +34,8 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.preference.PreferenceManager; +import java.net.MalformedURLException; +import java.net.URL; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -184,11 +186,18 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon return true; } if (firstMessage.account.acct != null) { - String[] splitAcct = firstMessage.account.acct.split("@"); - String instance; - if (splitAcct.length > 1) { - instance = splitAcct[1]; - } else { + String instance = null; + try { + URL url = new URL(firstMessage.uri); + instance = url.getHost(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + if (instance == null) { + Toasty.info(ContextActivity.this, getString(R.string.toast_error_fetch_message), Toasty.LENGTH_SHORT).show(); + return true; + } + if (instance.equalsIgnoreCase(MainActivity.currentInstance)) { Toasty.info(ContextActivity.this, getString(R.string.toast_on_your_instance), Toasty.LENGTH_SHORT).show(); return true; } @@ -200,11 +209,12 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon } if (remoteId != null) { StatusesVM statusesVM = new ViewModelProvider(ContextActivity.this).get(StatusesVM.class); + String finalInstance = instance; statusesVM.getStatus(instance, null, remoteId).observe(ContextActivity.this, status -> { if (status != null) { Intent intentContext = new Intent(ContextActivity.this, ContextActivity.class); intentContext.putExtra(Helper.ARG_STATUS, status); - intentContext.putExtra(Helper.ARG_REMOTE_INSTANCE, instance); + intentContext.putExtra(Helper.ARG_REMOTE_INSTANCE, finalInstance); intentContext.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intentContext); } else { diff --git a/app/src/main/java/app/fedilab/android/activities/InstanceHealthActivity.java b/app/src/main/java/app/fedilab/android/activities/InstanceHealthActivity.java index 85de47a2..e25e8801 100644 --- a/app/src/main/java/app/fedilab/android/activities/InstanceHealthActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/InstanceHealthActivity.java @@ -81,6 +81,12 @@ public class InstanceHealthActivity extends BaseAlertDialogActivity { instanceSocialVM.getInstances(BaseMainActivity.currentInstance.trim()).observe(InstanceHealthActivity.this, instanceSocialList -> { if (instanceSocialList != null && instanceSocialList.instances.size() > 0) { InstanceSocial.Instance instanceSocial = instanceSocialList.instances.get(0); + for (InstanceSocial.Instance instance : instanceSocialList.instances) { + if (instance.name.equalsIgnoreCase(BaseMainActivity.currentInstance.trim())) { + instanceSocial = instance; + break; + } + } if (instanceSocial.thumbnail != null && !instanceSocial.thumbnail.equals("null")) Glide.with(InstanceHealthActivity.this) .asBitmap() diff --git a/app/src/main/java/app/fedilab/android/activities/MediaActivity.java b/app/src/main/java/app/fedilab/android/activities/MediaActivity.java index c8d83615..608f6f35 100644 --- a/app/src/main/java/app/fedilab/android/activities/MediaActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/MediaActivity.java @@ -495,10 +495,10 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload // except for the ones that make the content appear under the system bars. private void showSystemUI() { View decorView = getWindow().getDecorView(); - decorView.setSystemUiVisibility( + decorView.setSystemUiVisibility(flags | View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } public FragmentMedia getCurrentFragment() { diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonStatusesService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonStatusesService.java index 08ae1d50..cf8613b4 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonStatusesService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonStatusesService.java @@ -251,7 +251,7 @@ public interface MastodonStatusesService { @Part MultipartBody.Part file, @Part MultipartBody.Part thumbnail, @Part("description") RequestBody description, - @Part("focus") String focus + @Part("focus") RequestBody focus ); //Edit a Media diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java index 7fdf0744..619bc92a 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java @@ -62,7 +62,9 @@ public interface MastodonTimelinesService { @GET("trends/tags") - Call> getTagTrends(@Header("Authorization") String token); + Call> getTagTrends(@Header("Authorization") String token, + @Query("offset") Integer offset, + @Query("limit") Integer limit); //Public Tags timelines @GET("timelines/tag/{hashtag}") diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Pagination.java b/app/src/main/java/app/fedilab/android/client/entities/api/Pagination.java index 1b024270..3e36371a 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Pagination.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Pagination.java @@ -19,4 +19,5 @@ public class Pagination { public String max_id; public String min_id; public String since_id; + public Integer offset; } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Results.java b/app/src/main/java/app/fedilab/android/client/entities/api/Results.java index 9e6b387e..60fc77d9 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Results.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Results.java @@ -24,5 +24,6 @@ public class Results { public java.util.List statuses; @SerializedName("hashtags") public java.util.List hashtags; + public Pagination pagination; } diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/Quotes.java b/app/src/main/java/app/fedilab/android/client/entities/app/Quotes.java new file mode 100644 index 00000000..95c82ff1 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/client/entities/app/Quotes.java @@ -0,0 +1,34 @@ +package app.fedilab.android.client.entities.app; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Fedilab; if not, + * see . */ + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.List; + + +public class Quotes implements Serializable { + + @SerializedName("quotes") + public List quotes; + + public static class Quote implements Serializable { + @SerializedName("author") + public String author; + @SerializedName("content") + public String content; + } +} diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/RemoteInstance.java b/app/src/main/java/app/fedilab/android/client/entities/app/RemoteInstance.java index 39b73df4..6230dd1b 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/RemoteInstance.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/RemoteInstance.java @@ -27,6 +27,8 @@ public class RemoteInstance implements Serializable { public String id; @SerializedName("host") public String host; + @SerializedName("displayName") + public String displayName; @SerializedName("type") public InstanceType type; @SerializedName("tags") diff --git a/app/src/main/java/app/fedilab/android/helper/CacheHelper.java b/app/src/main/java/app/fedilab/android/helper/CacheHelper.java index ca328240..46ecb5c9 100644 --- a/app/src/main/java/app/fedilab/android/helper/CacheHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/CacheHelper.java @@ -96,7 +96,7 @@ public class CacheHelper { String[] children = dir.list(); assert children != null; for (String aChildren : children) { - if (!aChildren.equals("databases") && !aChildren.equals("shared_prefs")) { + if (!aChildren.equals("databases") && !aChildren.equals("shared_prefs") && !aChildren.equals(Helper.TEMP_MEDIA_DIRECTORY)) { boolean success = deleteDir(new File(dir, aChildren)); if (!success) { return false; diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index fe70d4fe..75ea7626 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -36,7 +36,6 @@ import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; @@ -44,7 +43,6 @@ import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; -import android.media.AudioAttributes; import android.media.RingtoneManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -157,7 +155,6 @@ import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.databinding.PopupReleaseNotesBinding; import app.fedilab.android.exception.DBException; import app.fedilab.android.interfaces.OnDownloadInterface; -import app.fedilab.android.sqlite.Sqlite; import app.fedilab.android.ui.drawer.ReleaseNoteAdapter; import app.fedilab.android.viewmodel.mastodon.AccountsVM; import app.fedilab.android.viewmodel.mastodon.OauthVM; @@ -171,10 +168,6 @@ import okhttp3.RequestBody; public class Helper { public static final String TAG = "fedilab_app"; - public static final String APP_CLIENT_ID = "APP_CLIENT_ID"; - public static final String APP_CLIENT_SECRET = "APP_CLIENT_SECRET"; - public static final String APP_INSTANCE = "APP_INSTANCE"; - public static final String APP_API = "APP_API"; public static final String CLIP_BOARD = "CLIP_BOARD"; public static final String INSTANCE_SOCIAL_KEY = "jGj9gW3z9ptyIpB8CMGhAlTlslcemMV6AgoiImfw3vPP98birAJTHOWiu5ZWfCkLvcaLsFZw9e3Pb7TIwkbIyrj3z6S7r2oE6uy6EFHvls3YtapP8QKNZ980p9RfzTb4"; @@ -241,10 +234,8 @@ public class Helper { public static final String ARG_MINIFIED = "ARG_MINIFIED"; public static final String ARG_STATUS_REPORT = "ARG_STATUS_REPORT"; public static final String ARG_STATUS_MENTION = "ARG_STATUS_MENTION"; - public static final String ARG_SHARE_URI = "ARG_SHARE_URI"; public static final String ARG_SHARE_URL_MEDIA = "ARG_SHARE_URL_MEDIA"; public static final String ARG_SHARE_URL = "ARG_SHARE_URL"; - public static final String ARG_SHARE_URI_LIST = "ARG_SHARE_URI_LIST"; public static final String ARG_SHARE_TITLE = "ARG_SHARE_TITLE"; public static final String ARG_SHARE_SUBJECT = "ARG_SHARE_SUBJECT"; public static final String ARG_SHARE_DESCRIPTION = "ARG_SHARE_DESCRIPTION"; @@ -264,6 +255,7 @@ public class Helper { public static final String ARG_TAG_TIMELINE = "ARG_TAG_TIMELINE"; public static final String ARG_MEDIA_POSITION = "ARG_MEDIA_POSITION"; public static final String ARG_MEDIA_ATTACHMENT = "ARG_MEDIA_ATTACHMENT"; + public static final String ARG_MEDIA_ATTACHMENTS = "ARG_MEDIA_ATTACHMENTS"; public static final String ARG_SHOW_REPLIES = "ARG_SHOW_REPLIES"; public static final String ARG_SHOW_REBLOGS = "ARG_SHOW_REBLOGS"; public static final String ARG_INITIALIZE_VIEW = "ARG_INITIALIZE_VIEW"; @@ -323,9 +315,9 @@ public class Helper { Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);*/ - public static final Pattern hashtagPattern = Pattern.compile("(^|\\s+|[.,;?!-]+)(#[\\w_A-zÀ-ÿ]+)"); + public static final Pattern hashtagPattern = Pattern.compile("(#[\\w_A-zÀ-ÿ]+)"); public static final Pattern groupPattern = Pattern.compile("(![\\w_]+)"); - public static final Pattern mentionPattern = Pattern.compile("(@[\\w_.-]+[\\w])"); + public static final Pattern mentionPattern = Pattern.compile("(@[\\w_.-]?[\\w]+)"); public static final Pattern mentionLongPattern = Pattern.compile("(@[\\w_.-]+@[a-zA-Z0-9][a-zA-Z0-9.-]{1,61}[a-zA-Z0-9](?:\\.[a-zA-Z]{2,})+)"); public static final Pattern twitterPattern = Pattern.compile("((@[\\w]+)@twitter\\.com)"); @@ -1226,6 +1218,7 @@ public class Helper { public static void createAttachmentFromUri(Context context, List uris, OnAttachmentCopied callBack) { new Thread(() -> { + List attachments = new ArrayList<>(); for (Uri uri : uris) { Attachment attachment = new Attachment(); attachment.filename = Helper.getFileName(context, uri); @@ -1243,36 +1236,48 @@ public class Helper { counter++; Date now = new Date(); attachment.filename = formatter.format(now) + "." + extension; - InputStream selectedFileInputStream; - try { - selectedFileInputStream = context.getContentResolver().openInputStream(uri); - if (selectedFileInputStream != null) { - final File certCacheDir = new File(context.getCacheDir(), TEMP_MEDIA_DIRECTORY); - boolean isCertCacheDirExists = certCacheDir.exists(); - if (!isCertCacheDirExists) { - isCertCacheDirExists = certCacheDir.mkdirs(); - } - if (isCertCacheDirExists) { - String filePath = certCacheDir.getAbsolutePath() + "/" + attachment.filename; - attachment.local_path = filePath; - OutputStream selectedFileOutPutStream = new FileOutputStream(filePath); - byte[] buffer = new byte[1024]; - int length; - while ((length = selectedFileInputStream.read(buffer)) > 0) { - selectedFileOutPutStream.write(buffer, 0, length); + if (attachment.mimeType.startsWith("image")) { + final File certCacheDir = new File(context.getCacheDir(), TEMP_MEDIA_DIRECTORY); + boolean isCertCacheDirExists = certCacheDir.exists(); + if (!isCertCacheDirExists) { + certCacheDir.mkdirs(); + } + String filePath = certCacheDir.getAbsolutePath() + "/" + attachment.filename; + MediaHelper.ResizedImageRequestBody(context, uri, new File(filePath)); + attachment.local_path = filePath; + } else { + InputStream selectedFileInputStream; + try { + selectedFileInputStream = context.getContentResolver().openInputStream(uri); + if (selectedFileInputStream != null) { + final File certCacheDir = new File(context.getCacheDir(), TEMP_MEDIA_DIRECTORY); + boolean isCertCacheDirExists = certCacheDir.exists(); + if (!isCertCacheDirExists) { + isCertCacheDirExists = certCacheDir.mkdirs(); } - selectedFileOutPutStream.flush(); - selectedFileOutPutStream.close(); + if (isCertCacheDirExists) { + String filePath = certCacheDir.getAbsolutePath() + "/" + attachment.filename; + attachment.local_path = filePath; + OutputStream selectedFileOutPutStream = new FileOutputStream(filePath); + byte[] buffer = new byte[1024]; + int length; + while ((length = selectedFileInputStream.read(buffer)) > 0) { + selectedFileOutPutStream.write(buffer, 0, length); + } + selectedFileOutPutStream.flush(); + selectedFileOutPutStream.close(); + } + selectedFileInputStream.close(); } - selectedFileInputStream.close(); + } catch (Exception e) { + e.printStackTrace(); } - } catch (Exception e) { - e.printStackTrace(); } - Handler mainHandler = new Handler(Looper.getMainLooper()); - Runnable myRunnable = () -> callBack.onAttachmentCopied(attachment); - mainHandler.post(myRunnable); + attachments.add(attachment); } + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> callBack.onAttachmentCopied(attachments); + mainHandler.post(myRunnable); }).start(); } @@ -1322,6 +1327,7 @@ public class Helper { public static void createAttachmentFromPAth(String path, OnAttachmentCopied callBack) { new Thread(() -> { + List attachmentList = new ArrayList<>(); Attachment attachment = new Attachment(); attachment.mimeType = "image/*"; String extension = "jpg"; @@ -1330,7 +1336,8 @@ public class Helper { Date now = new Date(); attachment.filename = formatter.format(now) + "." + extension; Handler mainHandler = new Handler(Looper.getMainLooper()); - Runnable myRunnable = () -> callBack.onAttachmentCopied(attachment); + attachmentList.add(attachment); + Runnable myRunnable = () -> callBack.onAttachmentCopied(attachmentList); mainHandler.post(myRunnable); }).start(); } @@ -1492,7 +1499,7 @@ public class Helper { channelTitle = context.getString(R.string.channel_notif_backup); break; case STORE: - channelId = "channel_store"; + channelId = "channel_media"; channelTitle = context.getString(R.string.channel_notif_media); break; case TOOT: @@ -1561,12 +1568,12 @@ public class Helper { channel.setLightColor(ledColour); } else { channel = new NotificationChannel(channelId, channelTitle, NotificationManager.IMPORTANCE_DEFAULT); - String soundUri = sharedpreferences.getString(context.getString(R.string.SET_NOTIF_SOUND), ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.getPackageName() + "/" + R.raw.boop); + /*String soundUri = sharedpreferences.getString(context.getString(R.string.SET_NOTIF_SOUND), ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.getPackageName() + "/" + R.raw.boop); AudioAttributes audioAttributes = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setUsage(AudioAttributes.USAGE_NOTIFICATION) .build(); - channel.setSound(Uri.parse(soundUri), audioAttributes); + channel.setSound(Uri.parse(soundUri), audioAttributes);*/ } assert mNotificationManager != null; mNotificationManager.createNotificationChannel(channel); @@ -1600,28 +1607,6 @@ public class Helper { } } - public static void transfertIfExist(Context context) { - File dbFile = context.getDatabasePath(OLD_DB_NAME); - if (!dbFile.exists()) { - return; - } - int version = -1; - try { - SQLiteDatabase sqlDb = SQLiteDatabase.openDatabase - (context.getDatabasePath(OLD_DB_NAME).getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY); - version = sqlDb.getVersion(); - } catch (Exception ignored) { - } - try { - if (version == -1) { - version = 38; - } - SQLiteDatabase oldDb = Sqlite.getInstance(context.getApplicationContext(), OLD_DB_NAME, null, version).open(); - - } catch (Exception ignored) { - } - context.deleteDatabase(OLD_DB_NAME); - } public static String dateDiffFull(Date dateToot) { SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM, Locale.getDefault()); @@ -1749,7 +1734,11 @@ public class Helper { fileName = FileNameCleaner.cleanFileName(fileName); // opens input stream from the HTTP connection InputStream inputStream = httpURLConnection.getInputStream(); - File saveDir = context.getCacheDir(); + final File saveDir = new File(context.getCacheDir(), TEMP_MEDIA_DIRECTORY); + boolean isCertCacheDirExists = saveDir.exists(); + if (!isCertCacheDirExists) { + saveDir.mkdirs(); + } final String saveFilePath = saveDir + File.separator + fileName; // opens an output stream to save into file FileOutputStream outputStream = new FileOutputStream(saveFilePath); @@ -1995,7 +1984,7 @@ public class Helper { } public interface OnAttachmentCopied { - void onAttachmentCopied(Attachment attachment); + void onAttachmentCopied(List attachments); } public interface OnFileCopied { diff --git a/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java b/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java index 954c38ff..b86a9ecd 100644 --- a/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java @@ -80,6 +80,7 @@ public class MastodonHelper { public static final int ACCOUNTS_PER_CALL = 40; public static final int STATUSES_PER_CALL = 40; + public static final int SEARCH_PER_CALL = 20; public static final int NOTIFICATIONS_PER_CALL = 30; diff --git a/app/src/main/java/app/fedilab/android/helper/MediaHelper.java b/app/src/main/java/app/fedilab/android/helper/MediaHelper.java index 93c1b8d3..8a45fdb0 100644 --- a/app/src/main/java/app/fedilab/android/helper/MediaHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/MediaHelper.java @@ -21,10 +21,12 @@ import static app.fedilab.android.helper.LogoHelper.getMainLogo; import android.app.Activity; import android.app.DownloadManager; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; +import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Matrix; import android.graphics.drawable.Drawable; import android.media.MediaRecorder; import android.media.MediaScannerConnection; @@ -42,7 +44,7 @@ import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.core.content.FileProvider; -import androidx.preference.PreferenceManager; +import androidx.exifinterface.media.ExifInterface; import com.bumptech.glide.Glide; import com.bumptech.glide.request.target.CustomTarget; @@ -53,8 +55,10 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -69,6 +73,7 @@ import java.util.concurrent.atomic.AtomicInteger; import app.fedilab.android.BuildConfig; import app.fedilab.android.R; import app.fedilab.android.activities.ComposeActivity; +import app.fedilab.android.activities.MainActivity; import app.fedilab.android.client.entities.api.Attachment; import app.fedilab.android.databinding.DatetimePickerBinding; import app.fedilab.android.databinding.PopupRecordBinding; @@ -84,7 +89,6 @@ public class MediaHelper { * @param url String download url */ public static long manageDownloadsNoPopup(final Context context, final String url) { - final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); final DownloadManager.Request request; try { @@ -108,7 +112,11 @@ public class MediaHelper { } if (!new File(myDir).exists()) { - new File(myDir).mkdir(); + boolean created = new File(myDir).mkdir(); + if (!created) { + Toasty.error(context, context.getString(R.string.toast_error), Toasty.LENGTH_SHORT).show(); + return -1; + } } if (mime.toLowerCase().startsWith("video")) { request.setDestinationInExternalPublicDir(Environment.DIRECTORY_MOVIES, context.getString(R.string.app_name) + "/" + fileName); @@ -148,7 +156,11 @@ public class MediaHelper { File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); File targeted_folder = new File(path, context.getString(R.string.app_name)); if (!targeted_folder.exists()) { - targeted_folder.mkdir(); + boolean created = targeted_folder.mkdir(); + if (!created) { + Toasty.error(context, context.getString(R.string.toast_error), Toasty.LENGTH_SHORT).show(); + return; + } } FileInputStream fis = null; FileOutputStream fos = null; @@ -217,20 +229,6 @@ public class MediaHelper { }); } - public static String formatSeconds(int seconds) { - return getTwoDecimalsValue(seconds / 3600) + ":" - + getTwoDecimalsValue(seconds / 60) + ":" - + getTwoDecimalsValue(seconds % 60); - } - - private static String getTwoDecimalsValue(int value) { - if (value >= 0 && value <= 9) { - return "0" + value; - } else { - return value + ""; - } - } - public static String getMimeType(String url) { String type = null; @@ -272,14 +270,12 @@ public class MediaHelper { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); - File image = File.createTempFile( + // Save a file: path for use with ACTION_VIEW intents + return File.createTempFile( imageFileName, /* prefix */ ".jpg", /* suffix */ storageDir /* directory */ ); - // Save a file: path for use with ACTION_VIEW intents - String mCurrentPhotoPath = image.getAbsolutePath(); - return image; } /** @@ -400,6 +396,7 @@ public class MediaHelper { * @param attachmentList - List * @return int - The max height */ + @SuppressWarnings("unused") public static int returnMaxHeightForPreviews(Context context, List attachmentList) { int maxHeight = RelativeLayout.LayoutParams.WRAP_CONTENT; if (attachmentList != null && attachmentList.size() > 0) { @@ -420,4 +417,168 @@ public class MediaHelper { public interface OnSchedule { void scheduledAt(String scheduledDate); } + + public static void ResizedImageRequestBody(Context context, Uri uri, File targetedFile) { + InputStream decodeBitmapInputStream = null; + try { + InputStream inputStream = context.getContentResolver().openInputStream(uri); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(inputStream, null, options); + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + int orientation = getImageOrientation(uri, context.getContentResolver()); + int scaledImageSize = 1024; + do { + FileOutputStream outputStream = new FileOutputStream(targetedFile); + decodeBitmapInputStream = context.getContentResolver().openInputStream(uri); + options.inSampleSize = calculateInSampleSize(options, scaledImageSize, scaledImageSize); + options.inJustDecodeBounds = false; + Bitmap scaledBitmap = BitmapFactory.decodeStream(decodeBitmapInputStream, null, options); + Bitmap reorientedBitmap = reorientBitmap(scaledBitmap, orientation); + if (reorientedBitmap == null) { + scaledBitmap.recycle(); + return; + } + Bitmap.CompressFormat format; + if (!reorientedBitmap.hasAlpha()) { + format = Bitmap.CompressFormat.JPEG; + } else { + format = Bitmap.CompressFormat.PNG; + } + reorientedBitmap.compress(format, 100, outputStream); + reorientedBitmap.recycle(); + scaledImageSize /= 2; + } while (targetedFile.length() > getMaxSize(targetedFile.length())); + } catch (Exception e) { + e.printStackTrace(); + if (decodeBitmapInputStream != null) { + try { + decodeBitmapInputStream.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + } + } + + private static int calculateInSampleSize(BitmapFactory.Options options, int rqWidth, int rqHeight) { + int height = options.outHeight; + int width = options.outWidth; + int inSampleSize = 1; + if (height > rqHeight || width > rqWidth) { + + int halfHeight = height / 2; + int halfWidth = width / 2; + while ((halfHeight / inSampleSize) > rqHeight && (halfWidth / inSampleSize) > rqWidth) { + inSampleSize *= 2; + } + } + return inSampleSize; + } + + private static int getImageOrientation(Uri uri, ContentResolver contentResolver) { + InputStream inputStream; + try { + inputStream = contentResolver.openInputStream(uri); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return ExifInterface.ORIENTATION_UNDEFINED; + } + if (inputStream == null) { + return ExifInterface.ORIENTATION_UNDEFINED; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + try { + ExifInterface exifInterface = new ExifInterface(inputStream); + int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); + inputStream.close(); + return orientation; + } catch (IOException e) { + try { + inputStream.close(); + } catch (IOException ex) { + ex.printStackTrace(); + return ExifInterface.ORIENTATION_UNDEFINED; + } + e.printStackTrace(); + return ExifInterface.ORIENTATION_UNDEFINED; + } + } else { + try { + ExifInterface exifInterface = new ExifInterface(uri.getPath()); + int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); + inputStream.close(); + return orientation; + } catch (IOException e) { + try { + inputStream.close(); + } catch (IOException ex) { + ex.printStackTrace(); + return ExifInterface.ORIENTATION_UNDEFINED; + } + e.printStackTrace(); + return ExifInterface.ORIENTATION_UNDEFINED; + } + } + } + + + private static long getMaxSize(long maxSize) { + if (MainActivity.instanceInfo != null && MainActivity.instanceInfo.configuration != null && MainActivity.instanceInfo.configuration.media_attachments != null) { + maxSize = MainActivity.instanceInfo.configuration.media_attachments.image_size_limit; + } + return maxSize; + } + + public static Bitmap reorientBitmap(Bitmap bitmap, int orientation) { + Matrix matrix = new Matrix(); + switch (orientation) { + case ExifInterface.ORIENTATION_FLIP_HORIZONTAL: + matrix.setScale(-1.0f, 1.0f); + break; + case ExifInterface.ORIENTATION_ROTATE_180: + matrix.setRotate(180.0f); + break; + case ExifInterface.ORIENTATION_FLIP_VERTICAL: + matrix.setRotate(180.0f); + matrix.postScale(-1.0f, 1.0f); + break; + case ExifInterface.ORIENTATION_TRANSPOSE: + matrix.setRotate(90.0f); + matrix.postScale(-1.0f, 1.0f); + break; + case ExifInterface.ORIENTATION_ROTATE_90: + matrix.setRotate(90.0f); + break; + case ExifInterface.ORIENTATION_TRANSVERSE: + matrix.setRotate(-90.0f); + matrix.postScale(-1.0f, 1.0f); + break; + case ExifInterface.ORIENTATION_ROTATE_270: + matrix.setRotate(-90.0f); + break; + default: + return bitmap; + } + if (bitmap == null) { + return null; + } + try { + Bitmap result = Bitmap.createBitmap( + bitmap, 0, 0, bitmap.getWidth(), + bitmap.getHeight(), matrix, true); + if (!bitmap.sameAs(result)) { + bitmap.recycle(); + } + return result; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + } diff --git a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java index 52bb8e81..e39da314 100644 --- a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java @@ -39,6 +39,7 @@ import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.AppCompatTextView; import androidx.appcompat.widget.PopupMenu; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; @@ -356,6 +357,10 @@ public class PinnedTimelineHelper { name = pinnedTimeline.remoteInstance.host; if (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER) { String remoteInstance = sharedpreferences.getString(activity.getString(R.string.SET_NITTER_HOST), activity.getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase(); + //Custom name for Nitter instances + if (pinnedTimeline.remoteInstance.displayName != null && pinnedTimeline.remoteInstance.displayName.trim().length() > 0) { + name = pinnedTimeline.remoteInstance.displayName; + } ident = "@R@" + remoteInstance; } else { ident = "@R@" + pinnedTimeline.remoteInstance.host; @@ -521,7 +526,7 @@ public class PinnedTimelineHelper { if (pinnedTimelineVisibleList.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER) { instanceClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString()); } else { - nitterClick(activity, finalPinned, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString()); + nitterClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString()); } break; case HOME: @@ -979,6 +984,10 @@ public class PinnedTimelineHelper { if (values.trim().length() == 0) values = tag; tagTimeline.displayName = values; + View titleView = view.findViewById(R.id.title); + if (titleView instanceof AppCompatTextView) { + ((AppCompatTextView) titleView).setText(tagTimeline.displayName); + } pinned.pinnedTimelines.get(finalOffSetPosition).tagTimeline = tagTimeline; try { new Pinned(activity).updatePinned(pinned); @@ -1224,7 +1233,7 @@ public class PinnedTimelineHelper { * @param pinned - {@link Pinned} * @param position - int position of the tab */ - public static void nitterClick(BaseMainActivity activity, Pinned pinned, ActivityMainBinding activityMainBinding, int position, String slug) { + public static void nitterClick(BaseMainActivity activity, Pinned pinned, View view, ActivityMainBinding activityMainBinding, int position, String slug) { int toRemove = itemToRemoveInBottomMenu(activity); int offSetPosition = position - (BOTTOM_TIMELINE_COUNT - toRemove); @@ -1236,55 +1245,98 @@ public class PinnedTimelineHelper { RemoteInstance remoteInstance = pinned.pinnedTimelines.get(offSetPosition).remoteInstance; if (remoteInstance == null) return; - String accounts = remoteInstance.host; - AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity, Helper.dialogStyle()); - LayoutInflater inflater = activity.getLayoutInflater(); - View dialogView = inflater.inflate(R.layout.tags_any, new LinearLayout(activity), false); - dialogBuilder.setView(dialogView); - final EditText editText = dialogView.findViewById(R.id.filter_any); - editText.setHint(R.string.list_of_twitter_accounts); - if (accounts != null) { - editText.setText(accounts); - editText.setSelection(editText.getText().toString().length()); - } + PopupMenu popup = new PopupMenu(activity, view); + popup.getMenuInflater() + .inflate(R.menu.option_nitter_timeline, popup.getMenu()); int finalOffSetPosition = offSetPosition; - dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> { - pinned.pinnedTimelines.get(finalOffSetPosition).remoteInstance.host = editText.getText().toString().trim(); - try { - new Pinned(activity).updatePinned(pinned); - } catch (DBException e) { - e.printStackTrace(); - } - FragmentMastodonTimeline fragmentMastodonTimeline = null; - try { - new StatusCache(activity).deleteForSlug(slug); - } catch (DBException e) { - e.printStackTrace(); - } - if (activityMainBinding.viewPager.getAdapter() != null) { - Fragment fragment = (Fragment) activityMainBinding.viewPager.getAdapter().instantiateItem(activityMainBinding.viewPager, activityMainBinding.tabLayout.getSelectedTabPosition()); - if (fragment instanceof FragmentMastodonTimeline && fragment.isVisible()) { - fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment); - fragmentMastodonTimeline.refreshAllAdapters(); + popup.setOnMenuItemClickListener(item -> { + int itemId = item.getItemId(); + if (itemId == R.id.action_displayname) { + AlertDialog.Builder dialogBuilder; + LayoutInflater inflater; + View dialogView; + AlertDialog alertDialog; + dialogBuilder = new AlertDialog.Builder(activity, Helper.dialogStyle()); + inflater = activity.getLayoutInflater(); + dialogView = inflater.inflate(R.layout.tags_name, new LinearLayout(activity), false); + dialogBuilder.setView(dialogView); + final EditText editTextName = dialogView.findViewById(R.id.column_name); + if (remoteInstance.displayName != null) { + editTextName.setText(remoteInstance.displayName); + editTextName.setSelection(editTextName.getText().toString().length()); + } + dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> { + String values = editTextName.getText().toString(); + if (values.trim().length() == 0) { + values = remoteInstance.displayName; + } + remoteInstance.displayName = values; + View titleView = view.findViewById(R.id.title); + if (titleView instanceof AppCompatTextView) { + ((AppCompatTextView) titleView).setText(remoteInstance.displayName); + } + pinned.pinnedTimelines.get(finalOffSetPosition).remoteInstance = remoteInstance; + try { + new Pinned(activity).updatePinned(pinned); + } catch (DBException e) { + e.printStackTrace(); + } + }); + alertDialog = dialogBuilder.create(); + alertDialog.show(); + } else if (itemId == R.id.action_nitter_manage_accounts) { + String accounts = remoteInstance.host; + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity, Helper.dialogStyle()); + LayoutInflater inflater = activity.getLayoutInflater(); + View dialogView = inflater.inflate(R.layout.tags_any, new LinearLayout(activity), false); + dialogBuilder.setView(dialogView); + final EditText editText = dialogView.findViewById(R.id.filter_any); + editText.setHint(R.string.list_of_twitter_accounts); + if (accounts != null) { + editText.setText(accounts); + editText.setSelection(editText.getText().toString().length()); } + dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> { + pinned.pinnedTimelines.get(finalOffSetPosition).remoteInstance.host = editText.getText().toString().trim(); + try { + new Pinned(activity).updatePinned(pinned); + } catch (DBException e) { + e.printStackTrace(); + } + FragmentMastodonTimeline fragmentMastodonTimeline = null; + try { + new StatusCache(activity).deleteForSlug(slug); + } catch (DBException e) { + e.printStackTrace(); + } + if (activityMainBinding.viewPager.getAdapter() != null) { + Fragment fragment = (Fragment) activityMainBinding.viewPager.getAdapter().instantiateItem(activityMainBinding.viewPager, activityMainBinding.tabLayout.getSelectedTabPosition()); + if (fragment instanceof FragmentMastodonTimeline && fragment.isVisible()) { + fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment); + fragmentMastodonTimeline.refreshAllAdapters(); + } + } + FragmentTransaction fragTransaction1 = activity.getSupportFragmentManager().beginTransaction(); + if (fragmentMastodonTimeline == null) + return; + fragTransaction1.detach(fragmentMastodonTimeline).commit(); + Bundle bundle = new Bundle(); + bundle.putSerializable(Helper.ARG_REMOTE_INSTANCE, pinned.pinnedTimelines.get(finalOffSetPosition)); + bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.REMOTE); + bundle.putSerializable(Helper.ARG_INITIALIZE_VIEW, false); + fragmentMastodonTimeline.setArguments(bundle); + FragmentTransaction fragTransaction2 = activity.getSupportFragmentManager().beginTransaction(); + fragTransaction2.attach(fragmentMastodonTimeline); + fragTransaction2.commit(); + fragmentMastodonTimeline.recreate(); + }); + AlertDialog alertDialog = dialogBuilder.create(); + alertDialog.show(); } - FragmentTransaction fragTransaction1 = activity.getSupportFragmentManager().beginTransaction(); - if (fragmentMastodonTimeline == null) - return; - fragTransaction1.detach(fragmentMastodonTimeline).commit(); - Bundle bundle = new Bundle(); - bundle.putSerializable(Helper.ARG_REMOTE_INSTANCE, pinned.pinnedTimelines.get(finalOffSetPosition)); - bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.REMOTE); - bundle.putSerializable(Helper.ARG_INITIALIZE_VIEW, false); - fragmentMastodonTimeline.setArguments(bundle); - FragmentTransaction fragTransaction2 = activity.getSupportFragmentManager().beginTransaction(); - fragTransaction2.attach(fragmentMastodonTimeline); - fragTransaction2.commit(); - fragmentMastodonTimeline.recreate(); + return true; }); - AlertDialog alertDialog = dialogBuilder.create(); - alertDialog.show(); + popup.show(); } -} +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index 6179f6b9..49021fcc 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -127,7 +127,9 @@ public class SpannableHelper { } else { linkColor = -1; } - + if (linkColor == 0) { + linkColor = -1; + } SpannableString initialContent; if (text == null) { return null; @@ -185,6 +187,8 @@ public class SpannableHelper { urlDetails.put(url, urlText); } } + text = text.trim().replaceAll("\\s{3}", "   "); + text = text.trim().replaceAll("\\s{2}", "  "); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) initialContent = new SpannableString(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)); else @@ -252,6 +256,14 @@ public class SpannableHelper { if (urlDetails.containsKey(url)) { continue; } + + ClickableSpan[] clickableSpans = content.getSpans(matchStart, matchEnd, ClickableSpan.class); + if (clickableSpans != null) { + for (ClickableSpan clickableSpan : clickableSpans) { + content.removeSpan(clickableSpan); + } + } + content.removeSpan(clickableSpans); String newURL = Helper.transformURL(context, url); //If URL has been transformed if (newURL.compareTo(url) != 0) { @@ -263,7 +275,7 @@ public class SpannableHelper { //Truncate URL if needed //TODO: add an option to disable truncated URLs String urlText = newURL; - if (newURL.length() > 30 && !urlDetails.containsKey(urlText)) { + if (newURL.length() > 30 && !urlDetails.containsKey(urlText) && !urlText.startsWith("gemini")) { urlText = urlText.substring(0, 30); urlText += "…"; content.replace(matchStart, matchEnd, urlText); @@ -512,6 +524,15 @@ public class SpannableHelper { if (content.toString().length() < matchEnd || matchStart < 0 || matchStart > matchEnd) { continue; } + + ClickableSpan[] clickableSpans = content.getSpans(matchStart, matchEnd, ClickableSpan.class); + if (clickableSpans != null) { + for (ClickableSpan clickableSpan : clickableSpans) { + content.removeSpan(clickableSpan); + } + } + content.removeSpan(clickableSpans); + if (matchEnd <= content.length()) { content.setSpan(new LongClickableSpan() { @Override diff --git a/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java index 4ad014c1..6c94cf29 100644 --- a/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java @@ -17,6 +17,7 @@ package app.fedilab.android.helper; import static app.fedilab.android.BaseMainActivity.filteredAccounts; import android.content.Context; +import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Build; @@ -25,6 +26,7 @@ import android.text.Html; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelStoreOwner; +import androidx.preference.PreferenceManager; import java.io.IOException; import java.util.ArrayList; @@ -35,6 +37,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import app.fedilab.android.BaseMainActivity; +import app.fedilab.android.R; import app.fedilab.android.activities.MainActivity; import app.fedilab.android.client.endpoints.MastodonFiltersService; import app.fedilab.android.client.entities.api.Account; @@ -153,21 +156,40 @@ public class TimelineHelper { } } } + + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + boolean groupReblogs = sharedpreferences.getBoolean(context.getString(R.string.SET_GROUP_REBLOGS), true); if (filterTimeLineType == Timeline.TimeLineEnum.HOME) { - if (filteredAccounts != null && filteredAccounts.size() > 0) { - for (Status status : statuses) { + + for (int i = 0; i < statuses.size(); i++) { + if (filteredAccounts != null && filteredAccounts.size() > 0) { for (Account account : filteredAccounts) { - if (account.acct.equals(status.account.acct) || (status.reblog != null && account.acct.equals(status.reblog.account.acct))) { + if (account.acct.equals(statuses.get(i).account.acct) || (statuses.get(i).reblog != null && account.acct.equals(statuses.get(i).reblog.account.acct))) { Filter filterCustom = new Filter(); filterCustom.filter_action = "hide"; ArrayList contextCustom = new ArrayList<>(); contextCustom.add("home"); filterCustom.title = "Fedilab"; filterCustom.context = contextCustom; - status.filteredByApp = filterCustom; + statuses.get(i).filteredByApp = filterCustom; } } } + //Group boosts + if (groupReblogs && statuses.get(i).filteredByApp == null && statuses.get(i).reblog != null) { + for (int j = 0; j < i; j++) { + if (statuses.get(j).reblog != null && statuses.get(j).reblog.id.equals(statuses.get(i).reblog.id)) { + Filter filterCustom = new Filter(); + filterCustom.filter_action = "hide"; + ArrayList contextCustom = new ArrayList<>(); + contextCustom.add("home"); + filterCustom.title = "Fedilab reblog"; + filterCustom.context = contextCustom; + statuses.get(i).filteredByApp = filterCustom; + } + } + } + } } } diff --git a/app/src/main/java/app/fedilab/android/imageeditor/EditImageActivity.java b/app/src/main/java/app/fedilab/android/imageeditor/EditImageActivity.java index 81e65086..65c5545e 100644 --- a/app/src/main/java/app/fedilab/android/imageeditor/EditImageActivity.java +++ b/app/src/main/java/app/fedilab/android/imageeditor/EditImageActivity.java @@ -14,6 +14,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.animation.AnticipateOvershootInterpolator; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.constraintlayout.widget.ConstraintSet; @@ -25,8 +26,12 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.transition.ChangeBounds; import androidx.transition.TransitionManager; +import com.canhub.cropper.CropImage; +import com.canhub.cropper.CropImageContract; +import com.canhub.cropper.CropImageContractOptions; +import com.canhub.cropper.CropImageOptions; +import com.canhub.cropper.CropImageView; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; -import com.theartofdev.edmodo.cropper.CropImage; import java.io.File; import java.io.IOException; @@ -73,6 +78,8 @@ public class EditImageActivity extends BaseActivity implements OnPhotoEditorList private Uri uri; private boolean exit; private ActivityEditImageBinding binding; + CropImageContractOptions cropImageContractOptions; + ActivityResultLauncher cropImageContractOptionsActivityResultLauncher; private static int exifToDegrees(int exifOrientation) { if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { @@ -146,6 +153,33 @@ public class EditImageActivity extends BaseActivity implements OnPhotoEditorList } } + cropImageContractOptions = new CropImageContractOptions(uri, new CropImageOptions()) + .setGuidelines(CropImageView.Guidelines.ON) + .setCropShape(CropImageView.CropShape.RECTANGLE) + .setAllowRotation(true) + .setAllowFlipping(true) + .setOutputCompressFormat(Bitmap.CompressFormat.PNG) + .setAllowCounterRotation(true) + .setImageSource(true, false) + .setScaleType(CropImageView.ScaleType.CENTER); + cropImageContractOptionsActivityResultLauncher = registerForActivityResult( + new CropImageContract(), + result -> { + if (result.isSuccessful()) { + Uri resultUri = result.getUriContent(); + if (resultUri != null) { + binding.photoEditorView.getSource().setImageURI(resultUri); + if (uri != null && uri.getPath() != null) { + File fdelete = new File(uri.getPath()); + if (fdelete.exists()) { + //noinspection ResultOfMethodCallIgnored + fdelete.delete(); + } + } + uri = resultUri; + } + } + }); mPhotoEditor.setFilterEffect(PhotoFilter.NONE); binding.send.setOnClickListener(v -> { exit = true; @@ -262,7 +296,7 @@ public class EditImageActivity extends BaseActivity implements OnPhotoEditorList int imgHeightInEditor; int imgWidthInEditor; //If the original image has its height greater than width => heights are equals - float focusX = -2, focusY = -2; + float focusX, focusY; if (imageHeight > imageWidth) { imgHeightInEditor = pHeight; float ratio = (float) pHeight / (float) imageHeight; @@ -286,8 +320,8 @@ public class EditImageActivity extends BaseActivity implements OnPhotoEditorList } intentImage.putExtra("focusX", focusX); intentImage.putExtra("focusY", focusY); - } + } LocalBroadcastManager.getInstance(EditImageActivity.this).sendBroadcast(intentImage); finish(); } @@ -351,22 +385,35 @@ public class EditImageActivity extends BaseActivity implements OnPhotoEditorList } break; case CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE: - - CropImage.ActivityResult result = CropImage.getActivityResult(data); - if (result != null) { - Uri resultUri = result.getUri(); - if (resultUri != null) { - binding.photoEditorView.getSource().setImageURI(resultUri); - binding.photoEditorView.getSource().setRotation(rotationInDegrees); - if (uri != null && uri.getPath() != null) { - File fdelete = new File(uri.getPath()); - if (fdelete.exists()) { - //noinspection ResultOfMethodCallIgnored - fdelete.delete(); - } - } - uri = resultUri; - } + if (data != null && data.getData() != null) { + CropImageContractOptions cropImageContractOptions = new CropImageContractOptions(data.getData(), new CropImageOptions()) + .setGuidelines(CropImageView.Guidelines.ON) + .setCropShape(CropImageView.CropShape.RECTANGLE) + .setAllowRotation(true) + .setAllowFlipping(true) + .setOutputCompressFormat(Bitmap.CompressFormat.PNG) + .setAllowCounterRotation(true) + .setImageSource(true, false) + .setScaleType(CropImageView.ScaleType.CENTER); + ActivityResultLauncher cropImageContractOptionsActivityResultLauncher = registerForActivityResult( + new CropImageContract(), + result -> { + if (result.isSuccessful()) { + Uri resultUri = result.getUriContent(); + if (resultUri != null) { + binding.photoEditorView.getSource().setImageURI(resultUri); + if (uri != null && uri.getPath() != null) { + File fdelete = new File(uri.getPath()); + if (fdelete.exists()) { + //noinspection ResultOfMethodCallIgnored + fdelete.delete(); + } + } + uri = resultUri; + } + } + }); + cropImageContractOptionsActivityResultLauncher.launch(cropImageContractOptions); } break; } @@ -454,8 +501,8 @@ public class EditImageActivity extends BaseActivity implements OnPhotoEditorList mPropertiesBSFragment.show(getSupportFragmentManager(), mPropertiesBSFragment.getTag()); break; case CROP: - CropImage.activity(uri) - .start(this); + + cropImageContractOptionsActivityResultLauncher.launch(cropImageContractOptions); break; case FOCUS: binding.focusCircle.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/app/fedilab/android/imageeditor/tools/EditingToolsAdapter.java b/app/src/main/java/app/fedilab/android/imageeditor/tools/EditingToolsAdapter.java index 5415c24c..845b47df 100644 --- a/app/src/main/java/app/fedilab/android/imageeditor/tools/EditingToolsAdapter.java +++ b/app/src/main/java/app/fedilab/android/imageeditor/tools/EditingToolsAdapter.java @@ -27,12 +27,12 @@ public class EditingToolsAdapter extends RecyclerView.Adapter statusResponse = statusCall.execute(); @@ -285,7 +285,7 @@ public class ComposeWorker extends Worker { } } else { Call scheduledStatusCall = mastodonStatusesService.createScheduledStatus(null, dataPost.token, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in, - poll_multiple, poll_hide_totals, in_reply_to_status, statuses.get(i).sensitive, statuses.get(i).spoiler_text, statuses.get(i).visibility.toLowerCase(), dataPost.scheduledDate, statuses.get(i).language); + poll_multiple, poll_hide_totals, in_reply_to_status, statuses.get(i).sensitive, statuses.get(i).spoilerChecked ? statuses.get(i).spoiler_text : null, statuses.get(i).visibility.toLowerCase(), dataPost.scheduledDate, statuses.get(i).language); try { Response statusResponse = scheduledStatusCall.execute(); @@ -341,10 +341,14 @@ public class ComposeWorker extends Worker { private static String postAttachment(MastodonStatusesService mastodonStatusesService, DataPost dataPost, MultipartBody.Part fileMultipartBody, Attachment attachment) { RequestBody descriptionBody = null; + RequestBody focusBody = null; if (attachment.description != null && attachment.description.trim().length() > 0) { descriptionBody = RequestBody.create(MediaType.parse("text/plain"), attachment.description); } - Call attachmentCall = mastodonStatusesService.postMedia(dataPost.token, fileMultipartBody, null, descriptionBody, attachment.focus); + if (attachment.focus != null && attachment.focus.trim().length() > 0) { + focusBody = RequestBody.create(MediaType.parse("text/plain"), attachment.focus); + } + Call attachmentCall = mastodonStatusesService.postMedia(dataPost.token, fileMultipartBody, null, descriptionBody, focusBody); if (attachmentCall != null) { try { diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java index 031030ba..3ccea89d 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java @@ -142,14 +142,18 @@ public class AccountAdapter extends RecyclerView.Adapter accountsVM.unblock(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id) .observe((LifecycleOwner) context, relationShip -> { account.relationShip = relationShip; adapter.notifyItemChanged(position); })); } else { - accountViewHolder.binding.block.setChecked(false); + accountViewHolder.binding.block.setBackgroundTintList(ColorStateList.valueOf(ThemeHelper.getAttColor(context, R.attr.colorPrimary))); + accountViewHolder.binding.block.setIconResource(R.drawable.ic_baseline_block_24); + accountViewHolder.binding.block.setContentDescription(context.getString(R.string.more_action_2)); accountViewHolder.binding.block.setOnClickListener(v -> accountsVM.block(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id) .observe((LifecycleOwner) context, relationShip -> { account.relationShip = relationShip; diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index 9fdeb620..ea5311c4 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -71,12 +71,17 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import com.vanniktech.emoji.EmojiManager; import com.vanniktech.emoji.EmojiPopup; import com.vanniktech.emoji.one.EmojiOneProvider; import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.lang.ref.WeakReference; +import java.nio.charset.StandardCharsets; import java.text.Normalizer; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -86,6 +91,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.Random; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -102,6 +108,7 @@ import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.api.Tag; import app.fedilab.android.client.entities.app.BaseAccount; import app.fedilab.android.client.entities.app.Languages; +import app.fedilab.android.client.entities.app.Quotes; import app.fedilab.android.client.entities.app.StatusDraft; import app.fedilab.android.databinding.ComposeAttachmentItemBinding; import app.fedilab.android.databinding.ComposePollBinding; @@ -214,8 +221,10 @@ public class ComposeAdapter extends RecyclerView.Adapter { - statusList.get(finalPosition).media_attachments.add(attachment); + Helper.createAttachmentFromUri(context, uris, attachments -> { + for (Attachment attachment : attachments) { + statusList.get(finalPosition).media_attachments.add(attachment); + } notifyItemChanged(finalPosition); }); } @@ -545,6 +554,7 @@ public class ComposeAdapter extends RecyclerView.Adapter { + holder.binding.content.setText(newContent[0]); + statusList.get(holder.getBindingAdapterPosition()).text = newContent[0]; + holder.binding.content.setSelection(holder.binding.content.getText().length()); + autocomplete = false; + updateCharacterCount(holder); + }; + mainHandler.post(myRunnable); + } else if (s.toString().contains(fedilabQuoteTrigger)) { + newContent[0] = s.toString().replaceAll(fedilabQuoteTrigger, "").trim(); + List mentions = new ArrayList<>(); + String mentionPattern = "@[a-z0-9_]+(@[a-z0-9.\\-]+[a-z0-9]+)?"; + final Pattern mPattern = Pattern.compile(mentionPattern, Pattern.CASE_INSENSITIVE); + Matcher matcherMentions = mPattern.matcher(newContent[0]); + while (matcherMentions.find()) { + mentions.add(matcherMentions.group()); + } + for (String mention : mentions) { + newContent[0] = newContent[0].replace(mention, ""); + } + + InputStream is; + newContent[0] = ""; + if (mentions.size() > 0) { + for (String mention : mentions) { + newContent[0] += mention + " "; + } + } + try { + is = context.getAssets().open("quotes/famous.json"); + int size; + size = is.available(); + byte[] buffer = new byte[size]; + //noinspection ResultOfMethodCallIgnored + is.read(buffer); + is.close(); + String json = new String(buffer, StandardCharsets.UTF_8); + Gson gson = new Gson(); + List quotes = gson.fromJson(json, new TypeToken>() { + }.getType()); + if (quotes != null && quotes.size() > 0) { + final int random = new Random().nextInt(quotes.size()); + Quotes.Quote quote = quotes.get(random); + newContent[0] += quote.content + "\n- " + quote.author; + } + } catch (IOException e) { + e.printStackTrace(); + } + + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> { holder.binding.content.setText(newContent[0]); statusList.get(holder.getBindingAdapterPosition()).text = newContent[0]; @@ -649,6 +710,15 @@ public class ComposeAdapter extends RecyclerView.Adapter dialog.dismiss()); if (attachment.description != null) { @@ -1088,15 +1163,15 @@ public class ComposeAdapter extends RecyclerView.Adapter displayAttachments(holder, position, finalMediaPosition)); if (attachment.description == null || attachment.description.trim().isEmpty()) { - composeAttachmentItemBinding.buttonDescription.setIconResource(R.drawable.ic_baseline_warning_24); + composeAttachmentItemBinding.buttonDescription.setChipIconResource(R.drawable.ic_baseline_warning_24); composeAttachmentItemBinding.buttonDescription.setTextColor(ContextCompat.getColor(context, R.color.black)); - composeAttachmentItemBinding.buttonDescription.setIconTintResource(R.color.black); - composeAttachmentItemBinding.buttonDescription.setBackgroundTintList(ThemeHelper.getNoDescriptionColorStateList(context)); + composeAttachmentItemBinding.buttonDescription.setChipIconTintResource(R.color.black); + composeAttachmentItemBinding.buttonDescription.setChipBackgroundColor(ThemeHelper.getNoDescriptionColorStateList(context)); } else { - composeAttachmentItemBinding.buttonDescription.setIconResource(R.drawable.ic_baseline_check_circle_24); + composeAttachmentItemBinding.buttonDescription.setChipIconResource(R.drawable.ic_baseline_check_circle_24); composeAttachmentItemBinding.buttonDescription.setTextColor(ContextCompat.getColor(context, R.color.white)); - composeAttachmentItemBinding.buttonDescription.setIconTintResource(R.color.white); - composeAttachmentItemBinding.buttonDescription.setBackgroundTintList(ThemeHelper.getHavingDescriptionColorStateList(context)); + composeAttachmentItemBinding.buttonDescription.setChipIconTintResource(R.color.white); + composeAttachmentItemBinding.buttonDescription.setChipBackgroundColor(ThemeHelper.getHavingDescriptionColorStateList(context)); } holder.binding.attachmentsList.addView(composeAttachmentItemBinding.getRoot()); mediaPosition++; @@ -1296,6 +1371,7 @@ public class ComposeAdapter extends RecyclerView.Adapter true); holder.binding.buttonCloseAttachmentPanel.setOnClickListener(v -> holder.binding.attachmentChoicesPanel.setVisibility(View.GONE)); holder.binding.buttonVisibility.setOnClickListener(v -> { holder.binding.visibilityPanel.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java index e85afc09..7665ca4e 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ReorderTabAdapter.java @@ -36,6 +36,7 @@ import app.fedilab.android.R; import app.fedilab.android.activities.ReorderTimelinesActivity; import app.fedilab.android.client.entities.app.Pinned; import app.fedilab.android.client.entities.app.PinnedTimeline; +import app.fedilab.android.client.entities.app.RemoteInstance; import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.databinding.DrawerReorderBinding; import app.fedilab.android.exception.DBException; @@ -99,7 +100,15 @@ public class ReorderTabAdapter extends RecyclerView.Adapter 0) { + holder.binding.text.setText(pinned.pinnedTimelines.get(position).remoteInstance.displayName); + } else { + holder.binding.text.setText(pinned.pinnedTimelines.get(position).remoteInstance.host); + } + } break; case TAG: holder.binding.icon.setImageResource(R.drawable.ic_baseline_label_24); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 82df20bf..a2f6013f 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -68,6 +68,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.LinearLayoutCompat; import androidx.appcompat.widget.PopupMenu; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.app.ActivityOptionsCompat; @@ -397,6 +398,47 @@ public class StatusAdapter extends RecyclerView.Adapter boolean displayBookmark = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_BOOKMARK), true); boolean displayTranslate = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_TRANSLATE), false); boolean displayCounters = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_COUNTER_FAV_BOOST), false); + boolean removeLeftMargin = sharedpreferences.getBoolean(context.getString(R.string.SET_REMOVE_LEFT_MARGIN), false); + + if (removeLeftMargin) { + LinearLayoutCompat.MarginLayoutParams p = (LinearLayoutCompat.MarginLayoutParams) holder.binding.spoiler.getLayoutParams(); + p.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.spoiler.setLayoutParams(p); + LinearLayoutCompat.MarginLayoutParams pe = (LinearLayoutCompat.MarginLayoutParams) holder.binding.spoilerExpand.getLayoutParams(); + pe.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.spoilerExpand.setLayoutParams(pe); + LinearLayoutCompat.MarginLayoutParams psc = (LinearLayoutCompat.MarginLayoutParams) holder.binding.statusContent.getLayoutParams(); + psc.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.statusContent.setLayoutParams(psc); + LinearLayoutCompat.MarginLayoutParams pct = (LinearLayoutCompat.MarginLayoutParams) holder.binding.containerTrans.getLayoutParams(); + psc.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.containerTrans.setLayoutParams(psc); + LinearLayoutCompat.MarginLayoutParams pcv = (LinearLayoutCompat.MarginLayoutParams) holder.binding.card.getLayoutParams(); + pcv.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.card.setLayoutParams(pcv); + LinearLayoutCompat.MarginLayoutParams pmc = (LinearLayoutCompat.MarginLayoutParams) holder.binding.mediaContainer.getLayoutParams(); + pmc.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.mediaContainer.setLayoutParams(pmc); + LinearLayoutCompat.MarginLayoutParams pal = (LinearLayoutCompat.MarginLayoutParams) holder.binding.attachmentsListContainer.getLayoutParams(); + pal.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.attachmentsListContainer.setLayoutParams(pal); + LinearLayoutCompat.MarginLayoutParams pp = (LinearLayoutCompat.MarginLayoutParams) holder.binding.poll.pollContainer.getLayoutParams(); + pp.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.poll.pollContainer.setLayoutParams(pp); + LinearLayoutCompat.MarginLayoutParams pet = (LinearLayoutCompat.MarginLayoutParams) holder.binding.editTime.getLayoutParams(); + pet.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.editTime.setLayoutParams(pet); + LinearLayoutCompat.MarginLayoutParams psi = (LinearLayoutCompat.MarginLayoutParams) holder.binding.statusInfo.getLayoutParams(); + psi.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.statusInfo.setLayoutParams(psi); + LinearLayoutCompat.MarginLayoutParams pas = (LinearLayoutCompat.MarginLayoutParams) holder.binding.actionShareContainer.getLayoutParams(); + pas.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.actionShareContainer.setLayoutParams(pas); + LinearLayoutCompat.MarginLayoutParams pab = (LinearLayoutCompat.MarginLayoutParams) holder.binding.actionButtons.getLayoutParams(); + pab.setMarginStart((int) Helper.convertDpToPixel(6, context)); + holder.binding.actionButtons.setLayoutParams(pab); + } + String loadMediaType = sharedpreferences.getString(context.getString(R.string.SET_LOAD_MEDIA_TYPE), "ALWAYS"); if (currentAccount != null && currentAccount.api == Account.API.PLEROMA) { @@ -630,7 +672,11 @@ public class StatusAdapter extends RecyclerView.Adapter holder.binding.actionButtonBookmark.setVisibility(View.GONE); } if (displayTranslate) { - holder.binding.actionButtonTranslate.setVisibility(View.VISIBLE); + if (statusToDeal.language != null && statusToDeal.language.trim().length() > 0 && statusToDeal.language.equalsIgnoreCase(MyTransL.getLocale())) { + holder.binding.actionButtonTranslate.setVisibility(View.GONE); + } else { + holder.binding.actionButtonTranslate.setVisibility(View.VISIBLE); + } } else { holder.binding.actionButtonTranslate.setVisibility(View.GONE); } @@ -1163,15 +1209,15 @@ public class StatusAdapter extends RecyclerView.Adapter float mediaH = -1.0f; if (attachment.measuredWidth > 0) { + float viewWidth = attachment.measuredWidth; if (attachment.meta != null && attachment.meta.small != null) { - float viewWidth = attachment.measuredWidth; mediaH = attachment.meta.small.height; float mediaW = attachment.meta.small.width; if (mediaW != 0) { ratio = viewWidth / mediaW; } } - loadAndAddAttachment(context, layoutMediaBinding, holder, adapter, mediaPosition, mediaH, ratio, statusToDeal, attachment, singleMedia); + loadAndAddAttachment(context, layoutMediaBinding, holder, adapter, mediaPosition, viewWidth, mediaH, ratio, statusToDeal, attachment, singleMedia); } else { int finalMediaPosition = mediaPosition; layoutMediaBinding.media.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @@ -1181,20 +1227,20 @@ public class StatusAdapter extends RecyclerView.Adapter attachment.measuredWidth = layoutMediaBinding.media.getWidth(); float ratio = 1.0f; float mediaH = -1.0f; + float viewWidth = attachment.measuredWidth; if (attachment.meta != null && attachment.meta.small != null) { - float viewWidth = attachment.measuredWidth; mediaH = attachment.meta.small.height; float mediaW = attachment.meta.small.width; if (mediaW != 0) { ratio = viewWidth / mediaW; } } - loadAndAddAttachment(context, layoutMediaBinding, holder, adapter, finalMediaPosition, mediaH, ratio, statusToDeal, attachment, singleMedia); + loadAndAddAttachment(context, layoutMediaBinding, holder, adapter, finalMediaPosition, viewWidth, mediaH, ratio, statusToDeal, attachment, singleMedia); } }); } } else { - loadAndAddAttachment(context, layoutMediaBinding, holder, adapter, mediaPosition, -1.f, -1.f, statusToDeal, attachment, singleMedia); + loadAndAddAttachment(context, layoutMediaBinding, holder, adapter, mediaPosition, -1.f, -1.f, -1.f, statusToDeal, attachment, singleMedia); } mediaPosition++; if (fullAttachement || singleMedia) { @@ -1429,18 +1475,20 @@ public class StatusAdapter extends RecyclerView.Adapter } holder.binding.poll.refreshPoll.setOnClickListener(v -> statusesVM.getPoll(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.poll.id) .observe((LifecycleOwner) context, poll -> { - //Store span elements - int i = 0; - for (Poll.PollItem item : statusToDeal.poll.options) { - if (item.span_title != null) { - poll.options.get(i).span_title = item.span_title; - } else { - poll.options.get(i).span_title = new SpannableString(item.title); + if (poll != null) { + //Store span elements + int i = 0; + for (Poll.PollItem item : statusToDeal.poll.options) { + if (item.span_title != null) { + poll.options.get(i).span_title = item.span_title; + } else { + poll.options.get(i).span_title = new SpannableString(item.title); + } + i++; } - i++; + statusToDeal.poll = poll; + adapter.notifyItemChanged(holder.getBindingAdapterPosition()); } - statusToDeal.poll = poll; - adapter.notifyItemChanged(holder.getBindingAdapterPosition()); })); holder.binding.poll.pollContainer.setVisibility(View.VISIBLE); String pollInfo = context.getResources().getQuantityString(R.plurals.number_of_voters, statusToDeal.poll.voters_count, statusToDeal.poll.voters_count); @@ -1799,7 +1847,7 @@ public class StatusAdapter extends RecyclerView.Adapter BaseMainActivity.currentToken = account.token; BaseMainActivity.currentUserID = account.user_id; BaseMainActivity.currentInstance = account.instance; - MainActivity.currentAccount = account; + currentAccount = account; SharedPreferences.Editor editor = sharedpreferences.edit(); editor.putString(PREF_USER_TOKEN, account.token); editor.putString(PREF_USER_INSTANCE, account.instance); @@ -1816,6 +1864,28 @@ public class StatusAdapter extends RecyclerView.Adapter builderSingle.show(); }; mainHandler.post(myRunnable); + } else if (accounts.size() == 1) { + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> { + BaseAccount account = accounts.get(0); + Toasty.info(context, context.getString(R.string.toast_account_changed, "@" + account.mastodon_account.acct + "@" + account.instance), Toasty.LENGTH_LONG).show(); + BaseMainActivity.currentToken = account.token; + BaseMainActivity.currentUserID = account.user_id; + BaseMainActivity.currentInstance = account.instance; + currentAccount = account; + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(PREF_USER_TOKEN, account.token); + editor.putString(PREF_USER_INSTANCE, account.instance); + editor.putString(PREF_USER_ID, account.user_id); + editor.commit(); + Intent mainActivity = new Intent(context, MainActivity.class); + mainActivity.putExtra(Helper.INTENT_ACTION, Helper.OPEN_WITH_ANOTHER_ACCOUNT); + mainActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + mainActivity.putExtra(Helper.PREF_MESSAGE_URL, statusToDeal.url); + context.startActivity(mainActivity); + ((Activity) context).finish(); + }; + mainHandler.post(myRunnable); } } catch (DBException e) { @@ -1966,7 +2036,7 @@ public class StatusAdapter extends RecyclerView.Adapter private static void loadAndAddAttachment(Context context, LayoutMediaBinding layoutMediaBinding, StatusViewHolder holder, RecyclerView.Adapter adapter, - int mediaPosition, float mediaH, float ratio, + int mediaPosition, float viewWidth, float mediaH, float ratio, Status statusToDeal, Attachment attachment, boolean singleImage) { SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); final int timeout = sharedpreferences.getInt(context.getString(R.string.SET_NSFW_TIMEOUT), 5); @@ -2037,6 +2107,7 @@ public class StatusAdapter extends RecyclerView.Adapter requestBuilder = requestBuilder.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY))); } else { requestBuilder = requestBuilder.placeholder(R.color.transparent_grey); + requestBuilder = requestBuilder.apply(new RequestOptions().override((int) viewWidth, (int) mediaH)); requestBuilder = requestBuilder.fitCenter(); } requestBuilder.into(layoutMediaBinding.media); diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonAccount.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonAccount.java index afef6168..b71ef24c 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonAccount.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonAccount.java @@ -56,6 +56,7 @@ public class FragmentMastodonAccount extends Fragment { private boolean flagLoading; private List accounts; private String max_id; + private Integer offset; private AccountAdapter accountAdapter; private String search; private Account accountTimeline; @@ -84,6 +85,11 @@ public class FragmentMastodonAccount extends Fragment { binding.recyclerView.setVisibility(View.GONE); accountsVM = new ViewModelProvider(FragmentMastodonAccount.this).get(viewModelKey, AccountsVM.class); max_id = null; + offset = 0; + if (search != null) { + binding.swipeContainer.setRefreshing(false); + binding.swipeContainer.setEnabled(false); + } router(true); } @@ -109,18 +115,31 @@ public class FragmentMastodonAccount extends Fragment { } } else if (search != null) { SearchVM searchVM = new ViewModelProvider(FragmentMastodonAccount.this).get(viewModelKey, SearchVM.class); - searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, search.trim(), null, "accounts", false, true, false, 0, null, null, MastodonHelper.STATUSES_PER_CALL) - .observe(getViewLifecycleOwner(), results -> { - if (results != null) { - Accounts accounts = new Accounts(); - Pagination pagination = new Pagination(); - accounts.accounts = results.accounts; - accounts.pagination = pagination; - initializeAccountCommonView(accounts); - } else { - Toasty.error(requireActivity(), getString(R.string.toast_error), Toasty.LENGTH_SHORT).show(); - } - }); + if (firstLoad) { + searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, search.trim(), null, "accounts", false, true, false, 0, null, null, MastodonHelper.SEARCH_PER_CALL) + .observe(getViewLifecycleOwner(), results -> { + if (results != null) { + Accounts accounts = new Accounts(); + Pagination pagination = new Pagination(); + accounts.accounts = results.accounts; + accounts.pagination = pagination; + initializeAccountCommonView(accounts); + } else { + Toasty.error(requireActivity(), getString(R.string.toast_error), Toasty.LENGTH_SHORT).show(); + } + }); + } else { + searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, search.trim(), null, "accounts", false, true, false, offset, null, null, MastodonHelper.SEARCH_PER_CALL) + .observe(getViewLifecycleOwner(), results -> { + if (results != null) { + Accounts accounts = new Accounts(); + Pagination pagination = new Pagination(); + accounts.accounts = results.accounts; + accounts.pagination = pagination; + dealWithPagination(accounts); + } + }); + } } else if (timelineType == Timeline.TimeLineEnum.MUTED_TIMELINE) { if (firstLoad) { accountsVM.getMutes(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, String.valueOf(MastodonHelper.accountsPerCall(requireActivity())), null, null) @@ -204,7 +223,11 @@ public class FragmentMastodonAccount extends Fragment { this.accounts = accounts.accounts; accountAdapter = new AccountAdapter(this.accounts, timelineType == Timeline.TimeLineEnum.MUTED_TIMELINE_HOME); - flagLoading = accounts.pagination.max_id == null; + if (search == null) { + flagLoading = accounts.pagination.max_id == null; + } else { + offset += MastodonHelper.SEARCH_PER_CALL; + } LinearLayoutManager mLayoutManager = new LinearLayoutManager(requireActivity()); binding.recyclerView.setLayoutManager(mLayoutManager); binding.recyclerView.setAdapter(accountAdapter); @@ -263,6 +286,9 @@ public class FragmentMastodonAccount extends Fragment { //Fetch the relationship fetchRelationShip(fetched_accounts.accounts, position); max_id = fetched_accounts.pagination.max_id; + if (search != null) { + offset += MastodonHelper.SEARCH_PER_CALL; + } accountAdapter.notifyItemRangeInserted(startId, fetched_accounts.accounts.size()); } else { flagLoading = true; diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTag.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTag.java index 45f9d33d..b6bf6b18 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTag.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTag.java @@ -25,6 +25,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.Collections; @@ -49,6 +50,9 @@ public class FragmentMastodonTag extends Fragment { private TagAdapter tagAdapter; private String search; private Timeline.TimeLineEnum timelineType; + private Integer offset; + private boolean flagLoading; + private List tagList; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -66,6 +70,10 @@ public class FragmentMastodonTag extends Fragment { super.onViewCreated(view, savedInstanceState); binding.loader.setVisibility(View.VISIBLE); binding.recyclerView.setVisibility(View.GONE); + offset = 0; + flagLoading = false; + binding.swipeContainer.setRefreshing(false); + binding.swipeContainer.setEnabled(false); router(); } @@ -75,16 +83,24 @@ public class FragmentMastodonTag extends Fragment { private void router() { if (search != null && timelineType == null) { SearchVM searchVM = new ViewModelProvider(FragmentMastodonTag.this).get(SearchVM.class); - searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, search.trim(), null, "hashtags", false, true, false, 0, null, null, MastodonHelper.STATUSES_PER_CALL) + searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, search.trim(), null, "hashtags", false, true, false, offset, null, null, MastodonHelper.SEARCH_PER_CALL) .observe(getViewLifecycleOwner(), results -> { - if (results != null && results.hashtags != null) { + if (results != null && results.hashtags != null && offset == 0) { initializeTagCommonView(results.hashtags); + } else if (results != null && results.hashtags != null) { + dealWithPaginationTag(results.hashtags); } }); } else if (timelineType == Timeline.TimeLineEnum.TREND_TAG) { TimelinesVM timelinesVM = new ViewModelProvider(FragmentMastodonTag.this).get(TimelinesVM.class); - timelinesVM.getTagsTrends(BaseMainActivity.currentToken, BaseMainActivity.currentInstance) - .observe(getViewLifecycleOwner(), this::initializeTagCommonView); + timelinesVM.getTagsTrends(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, offset, MastodonHelper.SEARCH_PER_CALL) + .observe(getViewLifecycleOwner(), tags -> { + if (tags != null && offset == 0) { + initializeTagCommonView(tags); + } else if (tags != null) { + dealWithPaginationTag(tags); + } + }); } } @@ -92,6 +108,24 @@ public class FragmentMastodonTag extends Fragment { binding.recyclerView.setAdapter(tagAdapter); } + private void dealWithPaginationTag(final List tags) { + if (binding == null || !isAdded() || getActivity() == null) { + return; + } + if (tags == null || tags.size() == 0) { + flagLoading = true; + binding.loadingNextElements.setVisibility(View.GONE); + return; + } + offset += MastodonHelper.SEARCH_PER_CALL; + binding.swipeContainer.setRefreshing(false); + binding.loadingNextElements.setVisibility(View.GONE); + flagLoading = false; + int start = tagList.size(); + tagList.addAll(tags); + tagAdapter.notifyItemRangeInserted(start, tags.size()); + } + /** * Intialize the view for tags * @@ -101,6 +135,7 @@ public class FragmentMastodonTag extends Fragment { if (binding == null || !isAdded() || getActivity() == null) { return; } + tagList = new ArrayList<>(); binding.loader.setVisibility(View.GONE); binding.noAction.setVisibility(View.GONE); binding.swipeContainer.setRefreshing(false); @@ -130,12 +165,35 @@ public class FragmentMastodonTag extends Fragment { tags.add(0, tag); } } + offset += MastodonHelper.SEARCH_PER_CALL; binding.recyclerView.setVisibility(View.VISIBLE); binding.noAction.setVisibility(View.GONE); - tagAdapter = new TagAdapter(tags); + tagList.addAll(tags); + tagAdapter = new TagAdapter(tagList); LinearLayoutManager mLayoutManager = new LinearLayoutManager(requireActivity()); binding.recyclerView.setLayoutManager(mLayoutManager); binding.recyclerView.setAdapter(tagAdapter); + binding.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if (dy > 0) { + int visibleItemCount = mLayoutManager.getChildCount(); + int totalItemCount = mLayoutManager.getItemCount(); + + if (firstVisibleItem + visibleItemCount == totalItemCount) { + if (!flagLoading) { + flagLoading = true; + binding.loadingNextElements.setVisibility(View.VISIBLE); + router(); + } + } else { + binding.loadingNextElements.setVisibility(View.GONE); + } + } + } + }); } } \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index cdc3462a..82d2aeff 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -80,6 +80,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. private String search, searchCache; private Status statusReport; private String max_id, min_id, min_id_fetch_more, max_id_fetch_more; + private Integer offset; private StatusAdapter statusAdapter; private Timeline.TimeLineEnum timelineType; private List timelineStatuses; @@ -188,6 +189,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (statusAdapter != null) { statusAdapter.notifyItemRangeRemoved(0, count); max_id = statusReport != null ? statusReport.id : null; + offset = 0; SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity()); rememberPosition = sharedpreferences.getBoolean(getString(R.string.SET_REMEMBER_POSITION), true); //Inner marker are only for pinned timelines and main timelines, they have isViewInitialized set to false @@ -264,7 +266,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } public void scrollToTop() { - if (binding != null) { + if (binding != null && search == null) { binding.swipeContainer.setRefreshing(true); flagLoading = false; route(DIRECTION.SCROLL_TOP, true); @@ -281,12 +283,17 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. binding.loader.setVisibility(View.VISIBLE); binding.recyclerView.setVisibility(View.GONE); max_id = statusReport != null ? statusReport.id : null; + offset = 0; SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity()); rememberPosition = sharedpreferences.getBoolean(getString(R.string.SET_REMEMBER_POSITION), true); //Inner marker are only for pinned timelines and main timelines, they have isViewInitialized set to false if (max_id == null && !isViewInitialized && rememberPosition) { max_id = sharedpreferences.getString(getString(R.string.SET_INNER_MARKER) + BaseMainActivity.currentUserID + BaseMainActivity.currentInstance + slug, null); } + if (search != null) { + binding.swipeContainer.setRefreshing(false); + binding.swipeContainer.setEnabled(false); + } //Only fragment in main view pager should not have the view initialized //AND Only the first fragment will initialize its view flagLoading = false; @@ -428,7 +435,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } //Update the timeline with new statuses int insertedStatus; - if (timelineType != Timeline.TimeLineEnum.TREND_MESSAGE_PUBLIC && timelineType != Timeline.TimeLineEnum.TREND_MESSAGE) { + if (timelineType != Timeline.TimeLineEnum.TREND_MESSAGE_PUBLIC && timelineType != Timeline.TimeLineEnum.TREND_MESSAGE && search == null) { insertedStatus = updateStatusListWith(fetched_statuses.statuses); } else { //Trends cannot be ordered by id insertedStatus = fetched_statuses.statuses.size(); @@ -455,6 +462,9 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. min_id = fetched_statuses.pagination.min_id; } } + if (search != null) { + offset += MastodonHelper.SEARCH_PER_CALL; + } int sizeBeforeFilter = 0; int filteredMessage = 0; int requestedMessages = MastodonHelper.statusesPerCall(requireActivity()); @@ -479,10 +489,9 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. flagLoading = true; } if (direction == DIRECTION.SCROLL_TOP) { - binding.recyclerView.scrollToPosition(0); + new Handler().postDelayed(() -> binding.recyclerView.scrollToPosition(0), 200); } - } /** @@ -501,6 +510,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } return; } + binding.loader.setVisibility(View.GONE); binding.noAction.setVisibility(View.GONE); binding.swipeContainer.setRefreshing(false); @@ -557,6 +567,9 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (min_id == null || (statuses.pagination.min_id != null && Helper.compareTo(statuses.pagination.min_id, min_id) > 0)) { min_id = statuses.pagination.min_id; } + if (search != null) { + offset += MastodonHelper.SEARCH_PER_CALL; + } statusAdapter = new StatusAdapter(timelineStatuses, timelineType, minified, canBeFederated, checkRemotely); statusAdapter.fetchMoreCallBack = this; if (statusReport != null) { @@ -570,8 +583,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); binding.recyclerView.setLayoutManager(mLayoutManager); binding.recyclerView.setAdapter(statusAdapter); - - if (searchCache == null && timelineType != Timeline.TimeLineEnum.TREND_MESSAGE) { + if (timelineType != Timeline.TimeLineEnum.TREND_MESSAGE) { binding.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { @@ -1033,17 +1045,31 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } } else if (search != null) { SearchVM searchVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, SearchVM.class); - searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, search.trim(), null, null, false, true, false, 0, null, null, MastodonHelper.STATUSES_PER_CALL) - .observe(getViewLifecycleOwner(), results -> { - if (results != null) { - Statuses statuses = new Statuses(); - statuses.statuses = results.statuses; - statuses.pagination = new Pagination(); - initializeStatusesCommonView(statuses); - } else { - Toasty.error(requireActivity(), getString(R.string.toast_error), Toasty.LENGTH_LONG).show(); - } - }); + if (direction == null) { + searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, search.trim(), null, null, false, true, false, 0, null, null, MastodonHelper.SEARCH_PER_CALL) + .observe(getViewLifecycleOwner(), results -> { + if (results != null) { + Statuses statuses = new Statuses(); + statuses.statuses = results.statuses; + statuses.pagination = new Pagination(); + initializeStatusesCommonView(statuses); + } else { + Toasty.error(requireActivity(), getString(R.string.toast_error), Toasty.LENGTH_LONG).show(); + } + }); + } else if (direction == DIRECTION.BOTTOM) { + searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, search.trim(), null, null, false, true, false, offset, null, null, MastodonHelper.SEARCH_PER_CALL) + .observe(getViewLifecycleOwner(), results -> { + if (results != null) { + Statuses statuses = new Statuses(); + statuses.statuses = results.statuses; + statuses.pagination = new Pagination(); + dealWithPagination(statuses, direction, false); + } + }); + } else { + flagLoading = false; + } } else if (searchCache != null) { SearchVM searchVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, SearchVM.class); searchVM.searchCache(BaseMainActivity.currentInstance, BaseMainActivity.currentUserID, searchCache.trim()) diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java index cd55af29..fbf37746 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java @@ -1347,7 +1347,7 @@ public class AccountsVM extends AndroidViewModel { if (acceptFollowResponse.isSuccessful()) { relationShip = acceptFollowResponse.body(); } - new StatusCache(getApplication().getApplicationContext()).deleteStatus(instance, id); + new StatusCache(getApplication().getApplicationContext()).deleteNotifications(MainActivity.currentUserID, instance); } catch (Exception e) { e.printStackTrace(); } @@ -1378,7 +1378,7 @@ public class AccountsVM extends AndroidViewModel { if (rejectFollowResponse.isSuccessful()) { relationShip = rejectFollowResponse.body(); } - new StatusCache(getApplication().getApplicationContext()).deleteStatus(instance, id); + new StatusCache(getApplication().getApplicationContext()).deleteNotifications(MainActivity.currentUserID, instance); } catch (Exception e) { e.printStackTrace(); } diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/SearchVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/SearchVM.java index e52c973b..5e259a50 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/SearchVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/SearchVM.java @@ -99,10 +99,15 @@ public class SearchVM extends AndroidViewModel { MastodonSearchService mastodonSearchService = init(instance); resultsMutableLiveData = new MutableLiveData<>(); new Thread(() -> { + int finalLimit = 40; + if (limit != null && limit < 40) { + finalLimit = limit; + } Call resultsCall = mastodonSearchService.search( token, q, account_id, type, exclude_unreviewed, - resolve, following, offset, max_id, min_id, limit); + resolve, following, offset, max_id, min_id, finalLimit); Results results = null; + if (resultsCall != null) { try { Response resultsResponse = resultsCall.execute(); diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java index be870a9f..82628377 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java @@ -127,7 +127,11 @@ public class StatusesVM extends AndroidViewModel { if (description != null && description.trim().length() > 0) { descriptionBody = RequestBody.create(MediaType.parse("text/plain"), description); } - Call attachmentCall = mastodonStatusesService.postMedia(token, fileMultipartBody, thumbnailMultipartBody, descriptionBody, focus); + RequestBody focusBody = null; + if (focus != null && focus.trim().length() > 0) { + focusBody = RequestBody.create(MediaType.parse("text/plain"), focus); + } + Call attachmentCall = mastodonStatusesService.postMedia(token, fileMultipartBody, thumbnailMultipartBody, descriptionBody, focusBody); Attachment attachment = null; if (attachmentCall != null) { try { diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java index a40ddaa1..ec3eccaa 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java @@ -198,11 +198,11 @@ public class TimelinesVM extends AndroidViewModel { return statusesMutableLiveData; } - public LiveData> getTagsTrends(String token, @NonNull String instance) { + public LiveData> getTagsTrends(String token, @NonNull String instance, Integer offset, Integer limit) { MastodonTimelinesService mastodonTimelinesService = init(instance); tagListMutableLiveData = new MutableLiveData<>(); new Thread(() -> { - Call> publicTlCall = mastodonTimelinesService.getTagTrends(token); + Call> publicTlCall = mastodonTimelinesService.getTagTrends(token, offset, limit); List tagList = null; if (publicTlCall != null) { try { diff --git a/app/src/main/res/drawable/bg_compose_panels.xml b/app/src/main/res/drawable/bg_compose_panels.xml new file mode 100644 index 00000000..ada4a62c --- /dev/null +++ b/app/src/main/res/drawable/bg_compose_panels.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable/ic_compose_attachment_play.xml b/app/src/main/res/drawable/ic_compose_attachment_play.xml index 9b7ecb7f..cabd5d80 100644 --- a/app/src/main/res/drawable/ic_compose_attachment_play.xml +++ b/app/src/main/res/drawable/ic_compose_attachment_play.xml @@ -4,9 +4,9 @@ android:viewportWidth="24" android:viewportHeight="24"> + android:fillColor="?attr/colorOnTertiary" + android:pathData="M10,15.5v-7c0,-0.41 0.47,-0.65 0.8,-0.4l4.67,3.5c0.27,0.2 0.27,0.6 0,0.8l-4.67,3.5c-0.33,0.25 -0.8,0.01 -0.8,-0.4z" /> diff --git a/app/src/main/res/drawable/ic_eraser.xml b/app/src/main/res/drawable/ic_eraser.xml index 212d2ae1..08b7074c 100644 --- a/app/src/main/res/drawable/ic_eraser.xml +++ b/app/src/main/res/drawable/ic_eraser.xml @@ -1,6 +1,7 @@ diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index 7f3b6ac4..f98dcda6 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -32,7 +32,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" - app:contentScrim="?colorPrimary" app:expandedTitleGravity="top" app:expandedTitleMarginEnd="64dp" app:expandedTitleMarginStart="48dp" diff --git a/app/src/main/res/layout/compose_attachment_item.xml b/app/src/main/res/layout/compose_attachment_item.xml index 77b32b69..4beca2ea 100644 --- a/app/src/main/res/layout/compose_attachment_item.xml +++ b/app/src/main/res/layout/compose_attachment_item.xml @@ -15,7 +15,7 @@ - - + - - + app:layout_constraintTop_toBottomOf="@id/preview" + app:textEndPadding="0dp" /> diff --git a/app/src/main/res/layout/drawer_status.xml b/app/src/main/res/layout/drawer_status.xml index 4cdd044a..a265701a 100644 --- a/app/src/main/res/layout/drawer_status.xml +++ b/app/src/main/res/layout/drawer_status.xml @@ -561,11 +561,15 @@ android:clipChildren="false" android:clipToPadding="false" android:gravity="end" - android:visibility="gone"> + android:visibility="gone" + tools:visibility="visible"> + android:clipToPadding="false"> - - + android:orientation="vertical"> + app:layout_constraintEnd_toStartOf="@id/button_emoji" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:visibility="visible" /> + + - - - + app:layout_constraintTop_toBottomOf="@id/add_remove_status" /> - - + - - - - - + app:layout_constraintTop_toBottomOf="@id/text_area_divider" /> - + - - + + @@ -219,16 +201,18 @@ android:layout_height="12dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/button_post" - app:layout_constraintStart_toEndOf="@id/action_container" + app:layout_constraintStart_toEndOf="@id/button_language" app:layout_constraintTop_toBottomOf="@id/character_count" /> @@ -236,9 +220,8 @@ android:id="@+id/attachment_choices_panel" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="6dp" - android:elevation="2dp" - android:background="?colorSurface" + android:background="@drawable/bg_compose_panels" + android:padding="6dp" android:visibility="gone" app:constraint_referenced_ids="button_attach_image,button_attach_audio,button_attach_video,button_close_attachment_panel,button_poll,button_attach_manual" app:flow_maxElementsWrap="3" @@ -246,177 +229,125 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" /> - + style="@style/Widget.Material3.Button.IconButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:icon="@drawable/ic_compose_attach_image" /> - + style="@style/Widget.Material3.Button.IconButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:icon="@drawable/ic_compose_attach_audio" /> - - - + style="@style/Widget.Material3.Button.IconButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:icon="@drawable/ic_compose_attach_video" /> - + style="@style/Widget.Material3.Button.IconButton.Outlined" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:icon="@drawable/ic_baseline_close_24" /> - + style="@style/Widget.Material3.Button.IconButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:icon="@drawable/ic_compose_poll" /> + + - + android:orientation="vertical" + android:padding="6dp" + app:singleSelection="true"> - - - - - - - - - - - - - - - - - + + - - + android:textAlignment="textStart" + app:icon="@drawable/ic_compose_visibility_private" /> - - - - - - - + android:textAlignment="textStart" + app:icon="@drawable/ic_compose_visibility_unlisted" /> - - - - - + android:textAlignment="textStart" + app:icon="@drawable/ic_compose_visibility_public" /> + + - + diff --git a/app/src/main/res/menu/option_nitter_timeline.xml b/app/src/main/res/menu/option_nitter_timeline.xml new file mode 100644 index 00000000..cbfc4cc6 --- /dev/null +++ b/app/src/main/res/menu/option_nitter_timeline.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 385929bb..e42adef7 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -550,7 +550,7 @@ القيام بإجراء الترجمة لون النص - تغيير لون النص في البقع + تغيير لون النص في الرسائل استخدم قالبا مخصصا المظهر تم تصدير القالب @@ -750,4 +750,65 @@ تشويش اسم النطاق المظهر الداكن الافتراضي تعليق للعامة + إعلان · %1$s - %2$s + الشكل + اختر ما إذا كان يجب أن تكون قاعدة الحُلة داكنة أو فاتحة + اختر حُلة أنشأها المساهمون + لغة الرسائل + إرسال الرسالة %d / %d + إزالة المنشور + ألا تريد رؤية هذا؟ + أنت تتابع هذا الحساب. لكي لا ترى منشوراته في خيطك الرئيسي بعد الآن ، قم بإلغاء متابعته. + هل هناك أي شيء آخر تعتقد أننا يجب أن نعرفه؟ + نتائج الاستطلاع + محو كافة الإشعارات + عرض جميع الفئات + خط + جلب المزيد من الرسائل… + شاركه أيضا: + عرض زر الترجمة دائما + مؤكّد + عرض + بيضاوي + افتح المسودة + انضم + أحدث عنوان إيبي + غير مؤكد + روابط ضارة أو مشاركة مزيفة أو ردود متكررة + الإشارات + المفضلة + مسح ذاكرة التخزين المؤقت + استخدم لغة النظام الافتراضية + فشل التطبيق في الحصول على رمز مميز + إحضار الإشعارات كل: + تصدير الإعدادات + شريط إجراءات واحد + أي قواعد تم انتهاكها؟ + أهلاً! ندعوك للانضمام إلى الـ Fediverse. + عرض زر الفاصلة المرجعية دائما + وضع علامة مقروءة على جميع الإشعارات + "يفضله أيضًا: " + مستطيل + وضع الممحاة + هل تريد الخروج دون حفظ الصورة؟ + اضغط هنا لتحديث استطلاع الرأي + الخيوط الزمنية في قائمة + هل أنت متأكد من أنك تريد إلغاء متابعة هذا الوسم؟ + إلغاء متابعة الوسم + أنت مدرك أنه يخالف قواعد محددة + تعليقات إضافية + الحساب من خادم آخر. هل تريد إرسال نسخة مجهولة من التقرير هناك أيضًا؟ + إعادة التوجيه إلى %1$s + تم إرسال التقرير! + لا تملك حسابا؟ + انضم إلى الفديفرس + إعادة التدوين + عامل التصفية + حذف ذاكرة التخزين المؤقت + ملاحظات الإصدار + تحميل الصور المصغرة للوسائط + عرض الوسائط + استيراد الإعدادت + لا يمكن تحميل الوسائط! + أصل الحساب المبلغ عنه \ No newline at end of file diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 64c9420c..f15e3f93 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -49,7 +49,7 @@ Otevřít v prohlížeči Přeložit - Domů + Domov Místní časová osa Ztlumení uživatelé Blokovaní uživatelé @@ -59,8 +59,8 @@ Poslat e-mail Naplánované zprávy Níže uvedené informace mohou popisovat uživatelský profil neúplně. - Vložit smajlík - Aplikace prozatím nenačetla uživatelské smajlíky. + Vložit emoji + Aplikace prozatím nenasbírala uživatelské emoji. Opravdu se chcete odhlásit od @%1$s@%2$s\? Žádné zprávy k zobrazení @@ -341,7 +341,7 @@ Hlavička profilu Kontaktovat administrátora instance Logo MastoHost - Výběr emotikonů + Výběr emoji Ukázat celou konverzaci Uživatelský výběr emoji Favicon @@ -367,7 +367,7 @@ Žádný Kterékoliv slovo (odělené mezerami) Všechna slova (oddělená mezerami) - Add some words to filter (space-separated) + Přidejte do filtru nějaká slova (oddělená mezerami) Změnit název sloupce Instance Misskey Populární @@ -478,7 +478,7 @@ Zrušit pozastavení Zvuk Hlasová zpráva - Během časového úseku budu aplikace posílat upozornění. Můžete to pro tento úsek změnit (tzn. ztišit) pomocí ovládacího prvku vpravo. + Během časového úseku bude aplikace posílat upozornění. Můžete to pro tento úsek změnit (tzn. ztišit) pomocí ovládacího prvku vpravo. Náhledy nebudou v časových osách oříznuty Automaticky vkládat zalomení řádku za zmínku, aby bylo první písmeno velké Umožňuje tvůrcům obsahu sdílet statusy do jejich kanálů RSS @@ -492,7 +492,7 @@ \n \nMůžete přidat dodatečný obsah. Děkuji! Viditelnost - Disable custom animated emojis + Vypnout vlastní animované emoji Nahlásit účet %d hlasující @@ -794,7 +794,7 @@ Návrhy Zapamatovat pozici v časových osách Zpráva byla připnuta - Přeložit zprávy + Překládat zprávy Moderátor Administrátor Potvrzeno @@ -910,7 +910,7 @@ Umožňuje omezit seznam jazyků ve výběru při vytváření zprávy. Změnit logo aplikace na vašem zařízení Přizpůsobuje tonalitu barevného schématu podle vaší osobní tapety. - Zprávy v cache pro domovskou časovou osu + Zprávy v cache pro domov Distributor pro push Upravil(a) zprávu Vyberte, kterou akci provést, pokud bude příspěvek vyhovovat filtru @@ -935,7 +935,11 @@ Ztlumit všechny Domácí ztlumení uživatelé Účet ztišen - Ztlumit pro domovskou časovou osu - Zrušit ztlumení pro domovskou časovou osu + Ztlumit pro domov + Zrušit ztlumení pro domov Všechny účtu budou na domovské časové ose ztlumeny. + Importovat data + Přidat všechny uživatele pro ztlumený domov + Zobrazit + Seskupovat reblogy v domovské časové ose \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 97f817f7..35dd56bb 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -532,7 +532,7 @@ Aktion ausführen Übersetzung Textfarbe - Ändern Du die Textfarbe in posts + Ändere die Textfarbe in Nachrichten Verwenden Du ein benutzerdefiniertes Design Farbschema Das Theme wurde exportiert @@ -904,4 +904,34 @@ Standard dunkles Design Wähle den Modus für das Design Farben anpassen + Wenn aktiviert, sind die Beiträge in der Timeline schattiert und erhöht. + Helles Thema anpassen + Gestattet, einige Elemente des hellen Themas zu personalisieren. + Dunkles Thema anpassen + Gestattet, einige Elemente des dunklen Themas zu personalisieren. + Eigene Farben auswählen + Hell - Eigene Farben + Dunkel - Eigene Farben + Entfernte Konversation anzeigen + Die Konversation begann auf Deiner Instanz! + Die Anwendung hat keine entfernten Nachrichten gefunden. + Tag stummschalten + Anpinnen des Tags aufheben + Stummschaltung des Tags aufheben + Bitte später nochmal versuchen. + Tag anpinnen + Alle Konten werden in der Timeline der Startseite stumm geschaltet. + Alle Benutzer auf der Startseite stummschalten + Daten importieren + Gruppiere geteilte Nachrichten in der Timeline der Startseite + Alle stummschalten + Konten verwalten + Auf Startseite stummgeschaltete Nutzer + Tag entfolgen + Für Startseite stummschalten + Stummschaltung auf der Startseite aufheben + Entfernt den linken Rand in den Timelines, um die Nachricht kompakter zu machen + Übersetzungs-Knopf immer anzeigen + Kartenansicht + Entferne linken Rand \ No newline at end of file diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 21cd5d07..0830836c 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -35,8 +35,8 @@ Malfermi per Validigu Aŭdovidaĵoj - Konigi kun - Komuna tra Fedilab + Konigi per + Konigita per Fedilab Respondoj Uzantnomo Malnetoj @@ -45,7 +45,7 @@ Mencioj Diskonigoj Montri diskonigojn - Montri la respondojn + Montri respondojn Malfermu en retumilo Traduku @@ -56,12 +56,12 @@ Sciigoj Petoj de sekvado Agordoj - Sendi per retmesaĝo + Sendi retpoŝton Planitaj hupoj Subaj informoj povas nekomplete prezenti la profilon de la uzanto. Enmeti emoĝion - The app did not collect custom emojis for the moment. - Are you sure you want to logout @%1$s@%2$s? + La apo ne havas adaptitajn emoĝiojn ĉi-okaze. + Ĉu vi certas ke vi volas elsaluti\? @%1$s@%2$s\? Neniu hupo por montri Aldoni hupon al viajn stelumajn\? @@ -75,7 +75,7 @@ Kopii Konigi Mencii - Timed mute + Tempumita silentigo Forigi kaj reskribi Silentigi ĉi-tiun konton? @@ -125,95 +125,99 @@ Via hupo estas malplena! La hupo estis sendita! Tikla enhavo? - Neniu malnetoj! - Elekti kontojn - Elekti kelkaj kontoj - Forigi malneto? - Describe for the visually impaired + Neniu malneto! + Elekti konton + Elektu kelkajn kontojn + Forigi malneton\? + Priskribu por vidhandikapitoj Neniu priskribo havebla! - Release %1$s + Eldono %1$s Programistoj: Permesilo: GNU GPL V3 Kodo: - Serĉi instencoj: + Serĉi instancojn: Neniu konto por montri - Ne sekva peton + Neniu peto pri sekvado Hupoj \n %1$s - Sekvante \n %1$s - Sekvante \n %1$s + Sekvas +\n %1$s + Sekvantoj +\n %1$s Malakcepti Neniu planitaj hupoj por montri! Forigi planita mesaĝon? La mesaĝo estis planita! - La planita dato devas pli granda ol la nunhoro! + La planita dato devas pli malfrua ol la nuna horo! - The time for muting should be greater than one minute. - %1$s has been muted until %2$s.\n You can unmute this account from their profile page. - %1$s is muted until %2$s.\n Tap here to unmute the account. + La tempo por silentigo devas esti pli longa ol unu minuto. + %1$s silentigita ĝis %2$s. +\nVi povas malsilentigi ĉi tiun konton en ĝia profilpaĝo. + %1$s silentigita ĝis %2$s. +\nKlaku ĉi tie por malsilentigi la konton. - Neniun sciigon por montri + Neniu sciigo por montri menciis vin - wrote a new message - {name} diskonigis vian mesaĝon - {name} stelumis vian mesaĝon + verkis novan mesaĝon + diskonigis vian mesaĝon + stelumis vian mesaĝon eksekvis vin - asked to follow you - Forigi sciigoj? - All notifications have been deleted! + petis sekvi vin + Forigi ĉiujn sciigojn\? + Ĉiuj sciigoj forigitaj! - Sekvitaj + Sekvantoj - Unable to get client id! + Ne eblas ricevi la klientan identigilon! La konto estis blokita! La konto ne plu estas blokita! La konto estis silentigita! La konto ne plu silentigita! - La konto estis sekvita! - La konto estas ne plu sekvas! + La konto estas eksekvita! + La konto estas ne plu estas sekvata! The toot was boosted! The toot is no longer boosted! La hup estis aldonita al stelumoj! The toot was removed from your favourites! Ups ! Eraro okazis! - An error occurred! The instance did not return an authorisation code! - The instance domain does not seem to be valid! - An error occurred while switching between accounts! - An error occurred while searching! - No action can be taken - Eraro okazis dum traduktas! + Eraro okazis! La instanco ne donis rajtigan kodon! + La adreso de la instanco ne ŝajnas valida! + Okazis eraro dum ŝanĝado de kontoj! + Okazis eraro dum serĉado! + Neniu ago eblas + Eraro okazis dum tradukado! Number of toots per load - Disable GIF avatars - Notify when someone follows you - Notify when someone boosts your status - Notify when someone favourites your status - Notify when someone mentions you - Notify when a poll ended - Notify for new posts - Show confirmation dialog before boosting - Show confirmation dialog before adding to favourites + Malŝalti GIF-profilbildojn + Sciigu kiam iu eksekvas vin + Sciigu kiam iu diskonigas vian afiŝon + Sciigu kiam iu stelumas vian statuson + Sciigu kiam iu mencias vin + Sciigu kiam enketo finiĝas + Sciigu pri novaj afiŝoj + Montru konfirman dialogon antaŭ diskonigo + Montru konfirman dialogon antaŭ aldono al legosignoj Sciigi? - Silent Notifications - NSFW view timeout (seconds, 0 means off) - Media Description timeout (seconds, 0 means off) - Custom sharing - Your custom sharing URL… + Silentaj sciigoj + Tempolimo de NSFW-vido (sekundoj, 0 estas malŝalto) + Tempolimo de aŭdvida priskribo (sekundoj, 0 estas malŝalto) + Adaptita kundivido + URL por via adaptita kundivido… Ŝlosi konton Konservi ŝanĝojn - Fit preview images + Adapti antaŭvidajn bildojn Inter kaj - Use the built-in browser + Uzu la enkonstruitan retumilon Propra langetoj - Automatically expand cw - Set LED colour: + Aŭtomate montri enhavon sub averto + Agordi koloron de LED: Blua Cejana @@ -229,8 +233,8 @@ Malsilentigu Peto sendita Sekvas vin - First letter in capital for replies - Resize pictures + Unua litero majuskle por respondoj + Adaptu fotojn Regrandigi videoj diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9b11eedb..d92b41d0 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -440,7 +440,7 @@ J\'accepte les %1$s et les %2$s règles du serveur conditions de service - S\'inscrire + S’inscrire Cette instance fonctionne avec des invitations. Votre compte devra être approuvé manuellement par un·e administrateur·rice pour qu\'il devienne utilisable. Les mots de passe ne sont pas identiques ! L\'adresse ne semble pas être valide ! @@ -864,7 +864,7 @@ Nouveau signalement Un message que vous avez partagé a été édité Un⋅e utilisateur⋅ice s\'est abonné⋅e - Politique de confidentialité + Politique de vie privée Vous n’avez pas bloqué de domaines Supprimer le fil épinglé \? Supprimer les fils épinglés \? @@ -877,7 +877,7 @@ Commentaire public Les modifications ont été enregistrées ! Créer un bloquage de domaine - Êtes-vous sûr de vouloir débloquer %1$s \? + Êtes-vous certain de débloquer %1$s \? a envoyé un rapport Domaines bloqués Rejeter les rapports @@ -887,17 +887,17 @@ Voulez-vous vraiment désépingler ce fil \? Nouvelle inscription (modérateurs) Ignorer tous les rapports provenant de ce domaine. Non pertinent pour les suspensions - Rejeter les médias + Rejeter le média Rejeter les rapports Voulez-vous vraiment masquer le tag %1$s \? Suggestions Pas intéressé - Avertir des mises à jour + Notifier les mises à jour Supprimer le fil chronologique Inscrit·e Thème sombre par défaut L\'app n\'a pas trouvé le message distant. - Ordonner les listes + Ré-arranger les listes Sévérité Le blocage de domaine n\'empêchera pas la création d\'entrées de compte dans la base de données, mais appliquera rétroactivement et automatiquement des méthodes de modération spécifiques à ces comptes. Rejeter les fichiers médias @@ -933,4 +933,9 @@ utilisateur·ices silencé·es sur l\'accueil Soumettre un rapport Masquer partiellement le nom de domaine dans la liste si l\'option de publication restreinte de la liste de domaine est activée + Importer des données + Gérer les comptes + Commentaire à propos de la limitation de ce domaine au public, si l\'annonce de la liste de limitation de domaines est activée. + Re-blog de groupe dans la timeline d’accueil + Ajouter tout les utilisateurs masqués à l’accueil \ No newline at end of file diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index d23d3869..9d8a9181 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -916,4 +916,19 @@ A conversa comezou na túa instancia! Escuro - Cores personais Tarxetas elevadas + Importar datos + Mostrar sempre botón de tradución + Acalar cancelo + Restablecer cancelo + Non seguir cancelo + Fixar cancelo + Desafixar cancelo + Acalar para Inicio + Non acalar para Inicio + Engadir tódolas usuarias ao inicio acalado + Tódalas contas serán acaladas para a cronoloxía de Inicio. + Acalalas todas + Usuarias acalas en Inicio + Comparticións para o grupo no Inicio + Xestionar contas \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index c514e968..c35d9b4a 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -915,4 +915,15 @@ Non seguire etichetta Selettore lingua Mostra conversazione remota + Link malevoli, siti ingannevoli, o risposte ripetitive + Importa dati + Tempo online: %,.2f %% + Seleziona tutto + Ci sono dei post a supporto di questa segnalazione\? + Dominio frontend YouTube + Dominio frontend Twitter + Dominio frontend Instagram + Dominio frontend Reddit + Ricondiviso da + Offusca parzialmente il nome di dominio nella lista se mostra le limitazioni di dominio é abilitato \ No newline at end of file diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 2bc08d3a..cb127f48 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -13,19 +13,19 @@ Baixar Baixar %1$s Mídia salva - Ficheiro: %1$s + Arquivo: %1$s Senha E-mail Contas Mensagens - Tags + Etiquetas Salvar Instância Instância: mastodon.social Usando a conta %1$s agora - Adicionar conta + Adicionar uma conta O conteúdo da mensagem foi copiado para a área de transferência - O link da mensagem foi copiado para a área de transferência + A URL da mensagem foi copiada para a área de transferência Câmera Excluir tudo Agendar @@ -33,7 +33,7 @@ Próximo Anterior Abrir com - Ok + Validar Mídia Compartilhar com Compartilhado via Fedilab @@ -58,14 +58,14 @@ Configurações Mandar um e-mail Mensagens agendadas - As informações abaixo podem refletir incompletamente o perfil do usuário. + As informações abaixo podem refletir o perfil do usuário de forma incompleta. Inserir emoji O aplicativo não achou emojis personalizados no momento. - Tem a certeza que quer sair @%1$s@%2$s? + Você tem certeza que deseja sair de @%1$s@%2$s\? - Sem mensagens para mostrar - Favoritar essa mensagem\? - Desfavoritar essa mensagem\? + Nenhuma mensagem para exibir + Adicionar esta mensagem aos seus favoritos\? + Remover esta mensagem dos seus favoritos\? Dar boost\? Desfazer boost\? Silenciar @@ -75,7 +75,7 @@ Copiar Compartilhar Mencionar - Silenciar até... + Silenciar temporariamente Excluir & rascunhar Silenciar esta conta? @@ -93,9 +93,9 @@ Excluir este toot? Excluir & rascunhar este toot? - Salvos - Salvar - Remover dos Salvos + Favoritos + Adicionar aos favoritos + Remover dos favoritos Toot foi salvo! Toot foi removido dos Salvos! @@ -125,9 +125,9 @@ Ocorreu um erro ao selecionar a mídia! - Remover mídia? + Remover esta mídia\? Sua mensagem está vazia! - Mensagem enviada! + A mensagem foi enviada! Conteúdo sensível? Sem rascunhos! Escolha uma conta @@ -135,7 +135,7 @@ Excluir rascunho? Descreva para os deficientes visuais - Sem descrição! + Nenhuma descrição disponível! Versão %1$s Desenvolvedor: @@ -145,7 +145,7 @@ Procure instâncias: - Sem conta + Nenhuma conta para exibir Sem seguidores pendentes Mensagens \n %1$s @@ -153,13 +153,14 @@ Seguidores \n %1$s Recusar - Sem mensagens agendadas! + Nenhuma mensagem agendada para exibir! Excluir mensagem agendada\? - Mensagem agendada! + A mensagem foi agendada! A data de agendamento deve ser após o horário atual! - O tempo de silêncio deve ser maior do que um minuto. - %1$s foi silenciado até %2$s. \n Você pode desativar no perfil do usuário. + O tempo de silenciamento deve ser maior que um minuto. + %1$s foi silenciado até %2$s. +\n Você pode anular o silenciar desta conta na página de perfil dela. %1$s está silenciado até %2$s. \n Toque aqui para desativar o silêncio. Sem notificações @@ -418,12 +419,12 @@ Cancelar Salvando… Imagem salva! - Falha ao salvar imagem. + Falha ao salvar imagem Adicionar um item Silenciar conversa Desativar silêncio Silêncio desativado! - Silêncio ativado! + A conversa está silenciada Geral Regional Arte @@ -489,6 +490,7 @@ Denunciar conta %d votante + %d votantes %d votantes @@ -506,11 +508,11 @@ A sua votação não pode ter opções duplicadas! Limpar cache ao sair - The cache (media, cached messages, data from the built-in browser) will be automatically cleared when leaving the application. + O cache (mídia, mensagens em cache, dados do navegador integrado) será limpo automaticamente ao sair do aplicativo. Quer deixar de seguir esta conta? Mostrar diálogo de confirmação antes de deixar de seguir uma conta Replace Medium links - Replace medium.com links with an open source alternative front-end focused on privacy. + Use um frontend alternativo para o Medium Default: scribe.rip Use um sistema notificações instantâneas para ter notificações em tempo real. Adicionar notas @@ -530,53 +532,57 @@ Toque aqui para repor todas as suas cores personalizadas Reset Icons - Color of bottom icons in timelines - Logo of the instance - Edit profile - Make an action - Translation + Cor dos ícones inferiores nas linhas do tempo + Logo da instância + Editar Perfil + Faça uma ação + Tradução Text color - Change the text color in messages - Use a custom theme - Theming - The theme was exported - The theme has been successfully exported in CSV + Alterar a cor do texto nas mensagens + Use um tema personalizado + Personalização + O tema foi exportado + O tema foi exportado com sucesso em CSV Import a theme - Tap here to import a theme from a previous export + Toque aqui para importar um tema exportado previamente Export the theme - Tap here to export the current theme - An error occurred when selecting the theme file - User count - Status count - Instance count + Toque aqui para exportar o tema atual + Ocorreu um erro ao selecionar o arquivo do tema + Número de usuários + Número de status + Número de instâncias End in %s - This instance is not available on https://instances.social + Esta instância não está disponível em https://instances.social Exibir link completo Partilhar link Abrir noutra aplicação - Check redirect - This URL does not redirect - %1$s \n\nredirects to\n\n %2$s - Remove UTM parameters - The app will automatically remove UTM parameters from URLs before visiting a link. - %d people talking - Twitter accounts (via Nitter) - Twitter usernames space separated - Identity proofs - Verified identity - Verified by %1$s (%2$s) - Action disabled - Unfollow - Something went wrong, please check your download directory in settings. - Announcements - No announcements! - Add a reaction - Video cache in MB, zero means no cache. - Watermarks - Automatically add a watermark at the bottom of pictures. The text can be customized for each account. - No distributors found! + Verifique o redirecionamento + Este URL não redireciona + %1$s +\n +\nredireciona para +\n +\n %2$s + Remover parâmetros UTM + O aplicativo removerá automaticamente os parâmetros UTM das URLs antes de visitar um link. + %d pessoas conversando + Contas do Twitter (via Nitter) + Nomes de usuários do Twitter separados por espaço + Provas de identidade + Identidade verificada + Verificado por %1$s (%2$s) + Ação desativada + Deixar de seguir + Algo deu errado, verifique seu diretório de download nas configurações. + Anúncios + Sem anúncios! + Adicionar uma reação + Cache de vídeo em MB, zero significa sem cache. + Marcas d\'água + Adicione automaticamente uma marca d\'água na parte inferior das fotos. O texto pode ser personalizado para cada conta. + Nenhum distribuidor encontrado! Necessita de um distribuidor para receber notificações instantâneas. \nVai encontrar mais detalhes em %1$s.\n\nPode desactivar as mensagens instantâneas nas configurações para ignorar esta mensagem. - Select a distributor + Selecione um distribuidor Sons de notificação Usar um frontend alternativo para Twitter Twitter @@ -638,4 +644,24 @@ Adicionar status Enviando mensagem %d/%d Nova atualização + Nova inscrição + Uma mensagem que você compartilhou foi editada + Um usuário fez uma denúncia + Um usuário se inscreveu + Inscrições + Personalizar tema escuro + Personalizar tema claro + Escuro - Cores personalizadas + Por favor, tente novamente mais tarde. + A conversa começou na sua instância! + Eu não gosto disso + Claro - Cores personalizadas + Gerenciar contas + Importar dados + Quando ativado, os itens nas linhas do tempo terão uma sombra e uma elevação. + Tema claro padrão + Tema escuro padrão + Nova denúncia + Mostrar mesmo assim + Personalizar cores \ No newline at end of file diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index 09fbd0db..3a4733e8 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -926,4 +926,7 @@ Torra a ativare pro sa pàgina printzipale Totu is contos ant a abarrare a sa muda in sa lìnia de tempus printzipale. Pone·los totus a sa muda + Importa datos + Agrupa is cumpartziduras in sa lìnia de tempus printzipale + Amministra is contos \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index dd7ccea5..c3caf14e 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -932,4 +932,7 @@ Ana sayfa için susturmaktan vazgeç Tüm kullanıcıları ana sayfada susturmaya ekle Ana sayfa için sustur + Verileri içe aktar + Ana sayfa zaman çizelgesinde yeniden blogları gruplandır + Hesapları yönet \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a6f5edb4..8644912b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1402,6 +1402,8 @@ SET_DISPLAY_TRANSLATE SET_NOTIF_VALIDATION_FAV SET_DISPLAY_COUNTER_FAV_BOOST + SET_REMOVE_LEFT_MARGIN + SET_INNER_MARKER SET_NOTIF_SILENT SET_REMEMBER_POSITION @@ -1409,6 +1411,8 @@ SET_DISPLAY_ALL_NOTIFICATIONS_TYPE SET_EXCLUDED_NOTIFICATIONS_TYPE SET_EXPAND_MEDIA + SET_GROUP_REBLOGS + SET_LIVE_TRANSLATE SET_TRUNCATE_TOOTS_SIZE SET_ART_WITH_NSFW @@ -2108,4 +2112,8 @@ All accounts will be muted for the Home timeline. Mute them all Import data + Group reblogs in home timeline + Manage accounts + Remove left margin + Remove the left margin in timelines to make messages more compact \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 3235b549..d13d71d9 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -240,4 +240,9 @@ @color/solarized_md_theme_light_inversePrimary + diff --git a/app/src/main/res/xml/pref_interface.xml b/app/src/main/res/xml/pref_interface.xml index 1799a2ed..f00bf82e 100644 --- a/app/src/main/res/xml/pref_interface.xml +++ b/app/src/main/res/xml/pref_interface.xml @@ -20,6 +20,14 @@ app:summary="@string/set_timelines_in_a_list" app:title="@string/set_timelines_in_a_list_title" /> + + - + - - diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapCroppingWorkerTask.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapCroppingWorkerTask.java deleted file mode 100644 index 54d33df4..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapCroppingWorkerTask.java +++ /dev/null @@ -1,354 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth, -// inexhaustible as the great rivers. -// When they come to an end, -// they begin again, -// like the days and months; -// they die and are reborn, -// like the four seasons." -// -// - Sun Tsu, -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.content.Context; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.AsyncTask; - -import java.lang.ref.WeakReference; - -/** - * Task to crop bitmap asynchronously from the UI thread. - */ -final class BitmapCroppingWorkerTask - extends AsyncTask { - - // region: Fields and Consts - - /** - * Use a WeakReference to ensure the ImageView can be garbage collected - */ - private final WeakReference mCropImageViewReference; - - /** - * the bitmap to crop - */ - private final Bitmap mBitmap; - - /** - * The Android URI of the image to load - */ - private final Uri mUri; - - /** - * The context of the crop image view widget used for loading of bitmap by Android URI - */ - private final Context mContext; - - /** - * Required cropping 4 points (x0,y0,x1,y1,x2,y2,x3,y3) - */ - private final float[] mCropPoints; - - /** - * Degrees the image was rotated after loading - */ - private final int mDegreesRotated; - - /** - * the original width of the image to be cropped (for image loaded from URI) - */ - private final int mOrgWidth; - - /** - * the original height of the image to be cropped (for image loaded from URI) - */ - private final int mOrgHeight; - - /** - * is there is fixed aspect ratio for the crop rectangle - */ - private final boolean mFixAspectRatio; - - /** - * the X aspect ration of the crop rectangle - */ - private final int mAspectRatioX; - - /** - * the Y aspect ration of the crop rectangle - */ - private final int mAspectRatioY; - - /** - * required width of the cropping image - */ - private final int mReqWidth; - - /** - * required height of the cropping image - */ - private final int mReqHeight; - - /** - * is the image flipped horizontally - */ - private final boolean mFlipHorizontally; - - /** - * is the image flipped vertically - */ - private final boolean mFlipVertically; - - /** - * The option to handle requested width/height - */ - private final CropImageView.RequestSizeOptions mReqSizeOptions; - - /** - * the Android Uri to save the cropped image to - */ - private final Uri mSaveUri; - - /** - * the compression format to use when writing the image - */ - private final Bitmap.CompressFormat mSaveCompressFormat; - - /** - * the quality (if applicable) to use when writing the image (0 - 100) - */ - private final int mSaveCompressQuality; - // endregion - - BitmapCroppingWorkerTask( - CropImageView cropImageView, - Bitmap bitmap, - float[] cropPoints, - int degreesRotated, - boolean fixAspectRatio, - int aspectRatioX, - int aspectRatioY, - int reqWidth, - int reqHeight, - boolean flipHorizontally, - boolean flipVertically, - CropImageView.RequestSizeOptions options, - Uri saveUri, - Bitmap.CompressFormat saveCompressFormat, - int saveCompressQuality) { - - mCropImageViewReference = new WeakReference<>(cropImageView); - mContext = cropImageView.getContext(); - mBitmap = bitmap; - mCropPoints = cropPoints; - mUri = null; - mDegreesRotated = degreesRotated; - mFixAspectRatio = fixAspectRatio; - mAspectRatioX = aspectRatioX; - mAspectRatioY = aspectRatioY; - mReqWidth = reqWidth; - mReqHeight = reqHeight; - mFlipHorizontally = flipHorizontally; - mFlipVertically = flipVertically; - mReqSizeOptions = options; - mSaveUri = saveUri; - mSaveCompressFormat = saveCompressFormat; - mSaveCompressQuality = saveCompressQuality; - mOrgWidth = 0; - mOrgHeight = 0; - } - - BitmapCroppingWorkerTask( - CropImageView cropImageView, - Uri uri, - float[] cropPoints, - int degreesRotated, - int orgWidth, - int orgHeight, - boolean fixAspectRatio, - int aspectRatioX, - int aspectRatioY, - int reqWidth, - int reqHeight, - boolean flipHorizontally, - boolean flipVertically, - CropImageView.RequestSizeOptions options, - Uri saveUri, - Bitmap.CompressFormat saveCompressFormat, - int saveCompressQuality) { - - mCropImageViewReference = new WeakReference<>(cropImageView); - mContext = cropImageView.getContext(); - mUri = uri; - mCropPoints = cropPoints; - mDegreesRotated = degreesRotated; - mFixAspectRatio = fixAspectRatio; - mAspectRatioX = aspectRatioX; - mAspectRatioY = aspectRatioY; - mOrgWidth = orgWidth; - mOrgHeight = orgHeight; - mReqWidth = reqWidth; - mReqHeight = reqHeight; - mFlipHorizontally = flipHorizontally; - mFlipVertically = flipVertically; - mReqSizeOptions = options; - mSaveUri = saveUri; - mSaveCompressFormat = saveCompressFormat; - mSaveCompressQuality = saveCompressQuality; - mBitmap = null; - } - - /** - * The Android URI that this task is currently loading. - */ - public Uri getUri() { - return mUri; - } - - /** - * Crop image in background. - * - * @param params ignored - * @return the decoded bitmap data - */ - @Override - protected BitmapCroppingWorkerTask.Result doInBackground(Void... params) { - try { - if (!isCancelled()) { - - BitmapUtils.BitmapSampled bitmapSampled; - if (mUri != null) { - bitmapSampled = - BitmapUtils.cropBitmap( - mContext, - mUri, - mCropPoints, - mDegreesRotated, - mOrgWidth, - mOrgHeight, - mFixAspectRatio, - mAspectRatioX, - mAspectRatioY, - mReqWidth, - mReqHeight, - mFlipHorizontally, - mFlipVertically); - } else if (mBitmap != null) { - bitmapSampled = - BitmapUtils.cropBitmapObjectHandleOOM( - mBitmap, - mCropPoints, - mDegreesRotated, - mFixAspectRatio, - mAspectRatioX, - mAspectRatioY, - mFlipHorizontally, - mFlipVertically); - } else { - return new Result((Bitmap) null, 1); - } - - Bitmap bitmap = - BitmapUtils.resizeBitmap(bitmapSampled.bitmap, mReqWidth, mReqHeight, mReqSizeOptions); - - if (mSaveUri == null) { - return new Result(bitmap, bitmapSampled.sampleSize); - } else { - BitmapUtils.writeBitmapToUri( - mContext, bitmap, mSaveUri, mSaveCompressFormat, mSaveCompressQuality); - if (bitmap != null) { - bitmap.recycle(); - } - return new Result(mSaveUri, bitmapSampled.sampleSize); - } - } - return null; - } catch (Exception e) { - return new Result(e, mSaveUri != null); - } - } - - /** - * Once complete, see if ImageView is still around and set bitmap. - * - * @param result the result of bitmap cropping - */ - @Override - protected void onPostExecute(Result result) { - if (result != null) { - boolean completeCalled = false; - if (!isCancelled()) { - CropImageView cropImageView = mCropImageViewReference.get(); - if (cropImageView != null) { - completeCalled = true; - cropImageView.onImageCroppingAsyncComplete(result); - } - } - if (!completeCalled && result.bitmap != null) { - // fast release of unused bitmap - result.bitmap.recycle(); - } - } - } - - // region: Inner class: Result - - /** - * The result of BitmapCroppingWorkerTask async loading. - */ - static final class Result { - - /** - * The cropped bitmap - */ - public final Bitmap bitmap; - - /** - * The saved cropped bitmap uri - */ - public final Uri uri; - - /** - * The error that occurred during async bitmap cropping. - */ - final Exception error; - - /** - * is the cropping request was to get a bitmap or to save it to uri - */ - final boolean isSave; - - /** - * sample size used creating the crop bitmap to lower its size - */ - final int sampleSize; - - Result(Bitmap bitmap, int sampleSize) { - this.bitmap = bitmap; - this.uri = null; - this.error = null; - this.isSave = false; - this.sampleSize = sampleSize; - } - - Result(Uri uri, int sampleSize) { - this.bitmap = null; - this.uri = uri; - this.error = null; - this.isSave = true; - this.sampleSize = sampleSize; - } - - Result(Exception error, boolean isSave) { - this.bitmap = null; - this.uri = null; - this.error = error; - this.isSave = isSave; - this.sampleSize = 1; - } - } - // endregion -} diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapLoadingWorkerTask.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapLoadingWorkerTask.java deleted file mode 100644 index a6ecf939..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapLoadingWorkerTask.java +++ /dev/null @@ -1,176 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth, -// inexhaustible as the great rivers. -// When they come to an end, -// they begin again, -// like the days and months; -// they die and are reborn, -// like the four seasons." -// -// - Sun Tsu, -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.content.Context; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.AsyncTask; -import android.util.DisplayMetrics; - -import java.lang.ref.WeakReference; - -/** - * Task to load bitmap asynchronously from the UI thread. - */ -final class BitmapLoadingWorkerTask extends AsyncTask { - - // region: Fields and Consts - - /** - * Use a WeakReference to ensure the ImageView can be garbage collected - */ - private final WeakReference mCropImageViewReference; - - /** - * The Android URI of the image to load - */ - private final Uri mUri; - - /** - * The context of the crop image view widget used for loading of bitmap by Android URI - */ - private final Context mContext; - - /** - * required width of the cropping image after density adjustment - */ - private final int mWidth; - - /** - * required height of the cropping image after density adjustment - */ - private final int mHeight; - // endregion - - public BitmapLoadingWorkerTask(CropImageView cropImageView, Uri uri) { - mUri = uri; - mCropImageViewReference = new WeakReference<>(cropImageView); - - mContext = cropImageView.getContext(); - - DisplayMetrics metrics = cropImageView.getResources().getDisplayMetrics(); - double densityAdj = metrics.density > 1 ? 1 / metrics.density : 1; - mWidth = (int) (metrics.widthPixels * densityAdj); - mHeight = (int) (metrics.heightPixels * densityAdj); - } - - /** - * The Android URI that this task is currently loading. - */ - public Uri getUri() { - return mUri; - } - - /** - * Decode image in background. - * - * @param params ignored - * @return the decoded bitmap data - */ - @Override - protected Result doInBackground(Void... params) { - try { - if (!isCancelled()) { - - BitmapUtils.BitmapSampled decodeResult = - BitmapUtils.decodeSampledBitmap(mContext, mUri, mWidth, mHeight); - - if (!isCancelled()) { - - BitmapUtils.RotateBitmapResult rotateResult = - BitmapUtils.rotateBitmapByExif(decodeResult.bitmap, mContext, mUri); - - return new Result( - mUri, rotateResult.bitmap, decodeResult.sampleSize, rotateResult.degrees); - } - } - return null; - } catch (Exception e) { - return new Result(mUri, e); - } - } - - /** - * Once complete, see if ImageView is still around and set bitmap. - * - * @param result the result of bitmap loading - */ - @Override - protected void onPostExecute(Result result) { - if (result != null) { - boolean completeCalled = false; - if (!isCancelled()) { - CropImageView cropImageView = mCropImageViewReference.get(); - if (cropImageView != null) { - completeCalled = true; - cropImageView.onSetImageUriAsyncComplete(result); - } - } - if (!completeCalled && result.bitmap != null) { - // fast release of unused bitmap - result.bitmap.recycle(); - } - } - } - - // region: Inner class: Result - - /** - * The result of BitmapLoadingWorkerTask async loading. - */ - public static final class Result { - - /** - * The Android URI of the image to load - */ - public final Uri uri; - - /** - * The loaded bitmap - */ - public final Bitmap bitmap; - - /** - * The sample size used to load the given bitmap - */ - public final int loadSampleSize; - - /** - * The degrees the image was rotated - */ - public final int degreesRotated; - - /** - * The error that occurred during async bitmap loading. - */ - public final Exception error; - - Result(Uri uri, Bitmap bitmap, int loadSampleSize, int degreesRotated) { - this.uri = uri; - this.bitmap = bitmap; - this.loadSampleSize = loadSampleSize; - this.degreesRotated = degreesRotated; - this.error = null; - } - - Result(Uri uri, Exception error) { - this.uri = uri; - this.bitmap = null; - this.loadSampleSize = 0; - this.degreesRotated = 0; - this.error = error; - } - } - // endregion -} diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapUtils.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapUtils.java deleted file mode 100644 index 7190bd42..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/BitmapUtils.java +++ /dev/null @@ -1,923 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth, -// inexhaustible as the great rivers. -// When they come to an end, -// they begin again, -// like the days and months; -// they die and are reborn, -// like the four seasons." -// -// - Sun Tsu, -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.content.ContentResolver; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.BitmapRegionDecoder; -import android.graphics.Matrix; -import android.graphics.Rect; -import android.graphics.RectF; -import android.net.Uri; -import android.util.Log; -import android.util.Pair; - -import androidx.exifinterface.media.ExifInterface; - -import java.io.Closeable; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.ref.WeakReference; - -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; - -/** - * Utility class that deals with operations with an ImageView. - */ -final class BitmapUtils { - - static final Rect EMPTY_RECT = new Rect(); - - static final RectF EMPTY_RECT_F = new RectF(); - - /** - * Reusable rectangle for general internal usage - */ - static final RectF RECT = new RectF(); - - /** - * Reusable point for general internal usage - */ - static final float[] POINTS = new float[6]; - - /** - * Reusable point for general internal usage - */ - static final float[] POINTS2 = new float[6]; - /** - * used to save bitmaps during state save and restore so not to reload them. - */ - static Pair> mStateBitmap; - /** - * Used to know the max texture size allowed to be rendered - */ - private static int mMaxTextureSize; - - /** - * Rotate the given image by reading the Exif value of the image (uri).
- * If no rotation is required the image will not be rotated.
- * New bitmap is created and the old one is recycled. - */ - static RotateBitmapResult rotateBitmapByExif(Bitmap bitmap, Context context, Uri uri) { - ExifInterface ei = null; - try { - InputStream is = context.getContentResolver().openInputStream(uri); - if (is != null) { - ei = new ExifInterface(is); - is.close(); - } - } catch (Exception ignored) { - } - return ei != null ? rotateBitmapByExif(bitmap, ei) : new RotateBitmapResult(bitmap, 0); - } - - /** - * Rotate the given image by given Exif value.
- * If no rotation is required the image will not be rotated.
- * New bitmap is created and the old one is recycled. - */ - static RotateBitmapResult rotateBitmapByExif(Bitmap bitmap, ExifInterface exif) { - int degrees; - int orientation = - exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); - switch (orientation) { - case ExifInterface.ORIENTATION_ROTATE_90: - degrees = 90; - break; - case ExifInterface.ORIENTATION_ROTATE_180: - degrees = 180; - break; - case ExifInterface.ORIENTATION_ROTATE_270: - degrees = 270; - break; - default: - degrees = 0; - break; - } - return new RotateBitmapResult(bitmap, degrees); - } - - /** - * Decode bitmap from stream using sampling to get bitmap with the requested limit. - */ - static BitmapSampled decodeSampledBitmap(Context context, Uri uri, int reqWidth, int reqHeight) { - - try { - ContentResolver resolver = context.getContentResolver(); - - // First decode with inJustDecodeBounds=true to check dimensions - BitmapFactory.Options options = decodeImageForOption(resolver, uri); - - if (options.outWidth == -1 && options.outHeight == -1) - throw new RuntimeException("File is not a picture"); - - // Calculate inSampleSize - options.inSampleSize = - Math.max( - calculateInSampleSizeByReqestedSize( - options.outWidth, options.outHeight, reqWidth, reqHeight), - calculateInSampleSizeByMaxTextureSize(options.outWidth, options.outHeight)); - - // Decode bitmap with inSampleSize set - Bitmap bitmap = decodeImage(resolver, uri, options); - - return new BitmapSampled(bitmap, options.inSampleSize); - - } catch (Exception e) { - throw new RuntimeException( - "Failed to load sampled bitmap: " + uri + "\r\n" + e.getMessage(), e); - } - } - - /** - * Crop image bitmap from given bitmap using the given points in the original bitmap and the given - * rotation.
- * if the rotation is not 0,90,180 or 270 degrees then we must first crop a larger area of the - * image that contains the requires rectangle, rotate and then crop again a sub rectangle.
- * If crop fails due to OOM we scale the cropping image by 0.5 every time it fails until it is - * small enough. - */ - static BitmapSampled cropBitmapObjectHandleOOM( - Bitmap bitmap, - float[] points, - int degreesRotated, - boolean fixAspectRatio, - int aspectRatioX, - int aspectRatioY, - boolean flipHorizontally, - boolean flipVertically) { - int scale = 1; - while (true) { - try { - Bitmap cropBitmap = - cropBitmapObjectWithScale( - bitmap, - points, - degreesRotated, - fixAspectRatio, - aspectRatioX, - aspectRatioY, - 1 / (float) scale, - flipHorizontally, - flipVertically); - return new BitmapSampled(cropBitmap, scale); - } catch (OutOfMemoryError e) { - scale *= 2; - if (scale > 8) { - throw e; - } - } - } - } - - /** - * Crop image bitmap from given bitmap using the given points in the original bitmap and the given - * rotation.
- * if the rotation is not 0,90,180 or 270 degrees then we must first crop a larger area of the - * image that contains the requires rectangle, rotate and then crop again a sub rectangle. - * - * @param scale how much to scale the cropped image part, use 0.5 to lower the image by half (OOM - * handling) - */ - private static Bitmap cropBitmapObjectWithScale( - Bitmap bitmap, - float[] points, - int degreesRotated, - boolean fixAspectRatio, - int aspectRatioX, - int aspectRatioY, - float scale, - boolean flipHorizontally, - boolean flipVertically) { - - // get the rectangle in original image that contains the required cropped area (larger for non - // rectangular crop) - Rect rect = - getRectFromPoints( - points, - bitmap.getWidth(), - bitmap.getHeight(), - fixAspectRatio, - aspectRatioX, - aspectRatioY); - - // crop and rotate the cropped image in one operation - Matrix matrix = new Matrix(); - matrix.setRotate(degreesRotated, bitmap.getWidth() / 2, bitmap.getHeight() / 2); - matrix.postScale(flipHorizontally ? -scale : scale, flipVertically ? -scale : scale); - Bitmap result = - Bitmap.createBitmap(bitmap, rect.left, rect.top, rect.width(), rect.height(), matrix, true); - - if (result == bitmap) { - // corner case when all bitmap is selected, no worth optimizing for it - result = bitmap.copy(bitmap.getConfig(), false); - } - - // rotating by 0, 90, 180 or 270 degrees doesn't require extra cropping - if (degreesRotated % 90 != 0) { - - // extra crop because non rectangular crop cannot be done directly on the image without - // rotating first - result = - cropForRotatedImage( - result, points, rect, degreesRotated, fixAspectRatio, aspectRatioX, aspectRatioY); - } - - return result; - } - - /** - * Crop image bitmap from URI by decoding it with specific width and height to down-sample if - * required.
- * Additionally if OOM is thrown try to increase the sampling (2,4,8). - */ - static BitmapSampled cropBitmap( - Context context, - Uri loadedImageUri, - float[] points, - int degreesRotated, - int orgWidth, - int orgHeight, - boolean fixAspectRatio, - int aspectRatioX, - int aspectRatioY, - int reqWidth, - int reqHeight, - boolean flipHorizontally, - boolean flipVertically) { - int sampleMulti = 1; - while (true) { - try { - // if successful, just return the resulting bitmap - return cropBitmap( - context, - loadedImageUri, - points, - degreesRotated, - orgWidth, - orgHeight, - fixAspectRatio, - aspectRatioX, - aspectRatioY, - reqWidth, - reqHeight, - flipHorizontally, - flipVertically, - sampleMulti); - } catch (OutOfMemoryError e) { - // if OOM try to increase the sampling to lower the memory usage - sampleMulti *= 2; - if (sampleMulti > 16) { - throw new RuntimeException( - "Failed to handle OOM by sampling (" - + sampleMulti - + "): " - + loadedImageUri - + "\r\n" - + e.getMessage(), - e); - } - } - } - } - - /** - * Get left value of the bounding rectangle of the given points. - */ - static float getRectLeft(float[] points) { - return Math.min(Math.min(Math.min(points[0], points[2]), points[4]), points[6]); - } - - /** - * Get top value of the bounding rectangle of the given points. - */ - static float getRectTop(float[] points) { - return Math.min(Math.min(Math.min(points[1], points[3]), points[5]), points[7]); - } - - /** - * Get right value of the bounding rectangle of the given points. - */ - static float getRectRight(float[] points) { - return Math.max(Math.max(Math.max(points[0], points[2]), points[4]), points[6]); - } - - /** - * Get bottom value of the bounding rectangle of the given points. - */ - static float getRectBottom(float[] points) { - return Math.max(Math.max(Math.max(points[1], points[3]), points[5]), points[7]); - } - - /** - * Get width of the bounding rectangle of the given points. - */ - static float getRectWidth(float[] points) { - return getRectRight(points) - getRectLeft(points); - } - - /** - * Get height of the bounding rectangle of the given points. - */ - static float getRectHeight(float[] points) { - return getRectBottom(points) - getRectTop(points); - } - - /** - * Get horizontal center value of the bounding rectangle of the given points. - */ - static float getRectCenterX(float[] points) { - return (getRectRight(points) + getRectLeft(points)) / 2f; - } - - /** - * Get vertical center value of the bounding rectangle of the given points. - */ - static float getRectCenterY(float[] points) { - return (getRectBottom(points) + getRectTop(points)) / 2f; - } - - /** - * Get a rectangle for the given 4 points (x0,y0,x1,y1,x2,y2,x3,y3) by finding the min/max 2 - * points that contains the given 4 points and is a straight rectangle. - */ - static Rect getRectFromPoints( - float[] points, - int imageWidth, - int imageHeight, - boolean fixAspectRatio, - int aspectRatioX, - int aspectRatioY) { - int left = Math.round(Math.max(0, getRectLeft(points))); - int top = Math.round(Math.max(0, getRectTop(points))); - int right = Math.round(Math.min(imageWidth, getRectRight(points))); - int bottom = Math.round(Math.min(imageHeight, getRectBottom(points))); - - Rect rect = new Rect(left, top, right, bottom); - if (fixAspectRatio) { - fixRectForAspectRatio(rect, aspectRatioX, aspectRatioY); - } - - return rect; - } - - /** - * Fix the given rectangle if it doesn't confirm to aspect ration rule.
- * Make sure that width and height are equal if 1:1 fixed aspect ratio is requested. - */ - private static void fixRectForAspectRatio(Rect rect, int aspectRatioX, int aspectRatioY) { - if (aspectRatioX == aspectRatioY && rect.width() != rect.height()) { - if (rect.height() > rect.width()) { - rect.bottom -= rect.height() - rect.width(); - } else { - rect.right -= rect.width() - rect.height(); - } - } - } - - /** - * Write given bitmap to a temp file. If file already exists no-op as we already saved the file in - * this session. Uses JPEG 95% compression. - * - * @param uri the uri to write the bitmap to, if null - * @return the uri where the image was saved in, either the given uri or new pointing to temp - * file. - */ - static Uri writeTempStateStoreBitmap(Context context, Bitmap bitmap, Uri uri) { - try { - boolean needSave = true; - if (uri == null) { - uri = - Uri.fromFile( - File.createTempFile("aic_state_store_temp", ".jpg", context.getCacheDir())); - } else if (new File(uri.getPath()).exists()) { - needSave = false; - } - if (needSave) { - writeBitmapToUri(context, bitmap, uri, Bitmap.CompressFormat.JPEG, 95); - } - return uri; - } catch (Exception e) { - Log.w("AIC", "Failed to write bitmap to temp file for image-cropper save instance state", e); - return null; - } - } - - /** - * Write the given bitmap to the given uri using the given compression. - */ - static void writeBitmapToUri( - Context context, - Bitmap bitmap, - Uri uri, - Bitmap.CompressFormat compressFormat, - int compressQuality) - throws FileNotFoundException { - OutputStream outputStream = null; - try { - outputStream = context.getContentResolver().openOutputStream(uri); - bitmap.compress(compressFormat, compressQuality, outputStream); - } finally { - closeSafe(outputStream); - } - } - - /** - * Resize the given bitmap to the given width/height by the given option.
- */ - static Bitmap resizeBitmap( - Bitmap bitmap, int reqWidth, int reqHeight, CropImageView.RequestSizeOptions options) { - try { - if (reqWidth > 0 - && reqHeight > 0 - && (options == CropImageView.RequestSizeOptions.RESIZE_FIT - || options == CropImageView.RequestSizeOptions.RESIZE_INSIDE - || options == CropImageView.RequestSizeOptions.RESIZE_EXACT)) { - - Bitmap resized = null; - if (options == CropImageView.RequestSizeOptions.RESIZE_EXACT) { - resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false); - } else { - int width = bitmap.getWidth(); - int height = bitmap.getHeight(); - float scale = Math.max(width / (float) reqWidth, height / (float) reqHeight); - if (scale > 1 || options == CropImageView.RequestSizeOptions.RESIZE_FIT) { - resized = - Bitmap.createScaledBitmap( - bitmap, (int) (width / scale), (int) (height / scale), false); - } - } - if (resized != null) { - if (resized != bitmap) { - bitmap.recycle(); - } - return resized; - } - } - } catch (Exception e) { - Log.w("AIC", "Failed to resize cropped image, return bitmap before resize", e); - } - return bitmap; - } - - // region: Private methods - - /** - * Crop image bitmap from URI by decoding it with specific width and height to down-sample if - * required. - * - * @param orgWidth used to get rectangle from points (handle edge cases to limit rectangle) - * @param orgHeight used to get rectangle from points (handle edge cases to limit rectangle) - * @param sampleMulti used to increase the sampling of the image to handle memory issues. - */ - private static BitmapSampled cropBitmap( - Context context, - Uri loadedImageUri, - float[] points, - int degreesRotated, - int orgWidth, - int orgHeight, - boolean fixAspectRatio, - int aspectRatioX, - int aspectRatioY, - int reqWidth, - int reqHeight, - boolean flipHorizontally, - boolean flipVertically, - int sampleMulti) { - - // get the rectangle in original image that contains the required cropped area (larger for non - // rectangular crop) - Rect rect = - getRectFromPoints(points, orgWidth, orgHeight, fixAspectRatio, aspectRatioX, aspectRatioY); - - int width = reqWidth > 0 ? reqWidth : rect.width(); - int height = reqHeight > 0 ? reqHeight : rect.height(); - - Bitmap result = null; - int sampleSize = 1; - try { - // decode only the required image from URI, optionally sub-sampling if reqWidth/reqHeight is - // given. - BitmapSampled bitmapSampled = - decodeSampledBitmapRegion(context, loadedImageUri, rect, width, height, sampleMulti); - result = bitmapSampled.bitmap; - sampleSize = bitmapSampled.sampleSize; - } catch (Exception ignored) { - } - - if (result != null) { - try { - // rotate the decoded region by the required amount - result = rotateAndFlipBitmapInt(result, degreesRotated, flipHorizontally, flipVertically); - - // rotating by 0, 90, 180 or 270 degrees doesn't require extra cropping - if (degreesRotated % 90 != 0) { - - // extra crop because non rectangular crop cannot be done directly on the image without - // rotating first - result = - cropForRotatedImage( - result, points, rect, degreesRotated, fixAspectRatio, aspectRatioX, aspectRatioY); - } - } catch (OutOfMemoryError e) { - if (result != null) { - result.recycle(); - } - throw e; - } - return new BitmapSampled(result, sampleSize); - } else { - // failed to decode region, may be skia issue, try full decode and then crop - return cropBitmap( - context, - loadedImageUri, - points, - degreesRotated, - fixAspectRatio, - aspectRatioX, - aspectRatioY, - sampleMulti, - rect, - width, - height, - flipHorizontally, - flipVertically); - } - } - - /** - * Crop bitmap by fully loading the original and then cropping it, fallback in case cropping - * region failed. - */ - private static BitmapSampled cropBitmap( - Context context, - Uri loadedImageUri, - float[] points, - int degreesRotated, - boolean fixAspectRatio, - int aspectRatioX, - int aspectRatioY, - int sampleMulti, - Rect rect, - int width, - int height, - boolean flipHorizontally, - boolean flipVertically) { - Bitmap result = null; - int sampleSize; - try { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inSampleSize = - sampleSize = - sampleMulti - * calculateInSampleSizeByReqestedSize(rect.width(), rect.height(), width, height); - - Bitmap fullBitmap = decodeImage(context.getContentResolver(), loadedImageUri, options); - if (fullBitmap != null) { - try { - // adjust crop points by the sampling because the image is smaller - float[] points2 = new float[points.length]; - System.arraycopy(points, 0, points2, 0, points.length); - for (int i = 0; i < points2.length; i++) { - points2[i] = points2[i] / options.inSampleSize; - } - - result = - cropBitmapObjectWithScale( - fullBitmap, - points2, - degreesRotated, - fixAspectRatio, - aspectRatioX, - aspectRatioY, - 1, - flipHorizontally, - flipVertically); - } finally { - if (result != fullBitmap) { - fullBitmap.recycle(); - } - } - } - } catch (OutOfMemoryError e) { - if (result != null) { - result.recycle(); - } - throw e; - } catch (Exception e) { - throw new RuntimeException( - "Failed to load sampled bitmap: " + loadedImageUri + "\r\n" + e.getMessage(), e); - } - return new BitmapSampled(result, sampleSize); - } - - /** - * Decode image from uri using "inJustDecodeBounds" to get the image dimensions. - */ - private static BitmapFactory.Options decodeImageForOption(ContentResolver resolver, Uri uri) - throws FileNotFoundException { - InputStream stream = null; - try { - stream = resolver.openInputStream(uri); - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeStream(stream, EMPTY_RECT, options); - options.inJustDecodeBounds = false; - return options; - } finally { - closeSafe(stream); - } - } - - /** - * Decode image from uri using given "inSampleSize", but if failed due to out-of-memory then raise - * the inSampleSize until success. - */ - private static Bitmap decodeImage( - ContentResolver resolver, Uri uri, BitmapFactory.Options options) - throws FileNotFoundException { - do { - InputStream stream = null; - try { - stream = resolver.openInputStream(uri); - return BitmapFactory.decodeStream(stream, EMPTY_RECT, options); - } catch (OutOfMemoryError e) { - options.inSampleSize *= 2; - } finally { - closeSafe(stream); - } - } while (options.inSampleSize <= 512); - throw new RuntimeException("Failed to decode image: " + uri); - } - - /** - * Decode specific rectangle bitmap from stream using sampling to get bitmap with the requested - * limit. - * - * @param sampleMulti used to increase the sampling of the image to handle memory issues. - */ - private static BitmapSampled decodeSampledBitmapRegion( - Context context, Uri uri, Rect rect, int reqWidth, int reqHeight, int sampleMulti) { - InputStream stream = null; - BitmapRegionDecoder decoder = null; - try { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inSampleSize = - sampleMulti - * calculateInSampleSizeByReqestedSize( - rect.width(), rect.height(), reqWidth, reqHeight); - - stream = context.getContentResolver().openInputStream(uri); - decoder = BitmapRegionDecoder.newInstance(stream, false); - do { - try { - return new BitmapSampled(decoder.decodeRegion(rect, options), options.inSampleSize); - } catch (OutOfMemoryError e) { - options.inSampleSize *= 2; - } - } while (options.inSampleSize <= 512); - } catch (Exception e) { - throw new RuntimeException( - "Failed to load sampled bitmap: " + uri + "\r\n" + e.getMessage(), e); - } finally { - closeSafe(stream); - if (decoder != null) { - decoder.recycle(); - } - } - return new BitmapSampled(null, 1); - } - - /** - * Special crop of bitmap rotated by not stright angle, in this case the original crop bitmap - * contains parts beyond the required crop area, this method crops the already cropped and rotated - * bitmap to the final rectangle.
- * Note: rotating by 0, 90, 180 or 270 degrees doesn't require extra cropping. - */ - private static Bitmap cropForRotatedImage( - Bitmap bitmap, - float[] points, - Rect rect, - int degreesRotated, - boolean fixAspectRatio, - int aspectRatioX, - int aspectRatioY) { - if (degreesRotated % 90 != 0) { - - int adjLeft = 0, adjTop = 0, width = 0, height = 0; - double rads = Math.toRadians(degreesRotated); - int compareTo = - degreesRotated < 90 || (degreesRotated > 180 && degreesRotated < 270) - ? rect.left - : rect.right; - for (int i = 0; i < points.length; i += 2) { - if (points[i] >= compareTo - 1 && points[i] <= compareTo + 1) { - adjLeft = (int) Math.abs(Math.sin(rads) * (rect.bottom - points[i + 1])); - adjTop = (int) Math.abs(Math.cos(rads) * (points[i + 1] - rect.top)); - width = (int) Math.abs((points[i + 1] - rect.top) / Math.sin(rads)); - height = (int) Math.abs((rect.bottom - points[i + 1]) / Math.cos(rads)); - break; - } - } - - rect.set(adjLeft, adjTop, adjLeft + width, adjTop + height); - if (fixAspectRatio) { - fixRectForAspectRatio(rect, aspectRatioX, aspectRatioY); - } - - Bitmap bitmapTmp = bitmap; - bitmap = Bitmap.createBitmap(bitmap, rect.left, rect.top, rect.width(), rect.height()); - if (bitmapTmp != bitmap) { - bitmapTmp.recycle(); - } - } - return bitmap; - } - - /** - * Calculate the largest inSampleSize value that is a power of 2 and keeps both height and width - * larger than the requested height and width. - */ - private static int calculateInSampleSizeByReqestedSize( - int width, int height, int reqWidth, int reqHeight) { - int inSampleSize = 1; - if (height > reqHeight || width > reqWidth) { - while ((height / 2 / inSampleSize) > reqHeight && (width / 2 / inSampleSize) > reqWidth) { - inSampleSize *= 2; - } - } - return inSampleSize; - } - - /** - * Calculate the largest inSampleSize value that is a power of 2 and keeps both height and width - * smaller than max texture size allowed for the device. - */ - private static int calculateInSampleSizeByMaxTextureSize(int width, int height) { - int inSampleSize = 1; - if (mMaxTextureSize == 0) { - mMaxTextureSize = getMaxTextureSize(); - } - if (mMaxTextureSize > 0) { - while ((height / inSampleSize) > mMaxTextureSize - || (width / inSampleSize) > mMaxTextureSize) { - inSampleSize *= 2; - } - } - return inSampleSize; - } - - /** - * Rotate the given bitmap by the given degrees.
- * New bitmap is created and the old one is recycled. - */ - private static Bitmap rotateAndFlipBitmapInt( - Bitmap bitmap, int degrees, boolean flipHorizontally, boolean flipVertically) { - if (degrees > 0 || flipHorizontally || flipVertically) { - Matrix matrix = new Matrix(); - matrix.setRotate(degrees); - matrix.postScale(flipHorizontally ? -1 : 1, flipVertically ? -1 : 1); - Bitmap newBitmap = - Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); - if (newBitmap != bitmap) { - bitmap.recycle(); - } - return newBitmap; - } else { - return bitmap; - } - } - - /** - * Get the max size of bitmap allowed to be rendered on the device.
- * http://stackoverflow.com/questions/7428996/hw-accelerated-activity-how-to-get-opengl-texture-size-limit. - */ - private static int getMaxTextureSize() { - // Safe minimum default size - final int IMAGE_MAX_BITMAP_DIMENSION = 2048; - - try { - // Get EGL Display - EGL10 egl = (EGL10) EGLContext.getEGL(); - EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - - // Initialise - int[] version = new int[2]; - egl.eglInitialize(display, version); - - // Query total number of configurations - int[] totalConfigurations = new int[1]; - egl.eglGetConfigs(display, null, 0, totalConfigurations); - - // Query actual list configurations - EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]]; - egl.eglGetConfigs(display, configurationsList, totalConfigurations[0], totalConfigurations); - - int[] textureSize = new int[1]; - int maximumTextureSize = 0; - - // Iterate through all the configurations to located the maximum texture size - for (int i = 0; i < totalConfigurations[0]; i++) { - // Only need to check for width since opengl textures are always squared - egl.eglGetConfigAttrib( - display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize); - - // Keep track of the maximum texture size - if (maximumTextureSize < textureSize[0]) { - maximumTextureSize = textureSize[0]; - } - } - - // Release - egl.eglTerminate(display); - - // Return largest texture size found, or default - return Math.max(maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION); - } catch (Exception e) { - return IMAGE_MAX_BITMAP_DIMENSION; - } - } - - /** - * Close the given closeable object (Stream) in a safe way: check if it is null and catch-log - * exception thrown. - * - * @param closeable the closable object to close - */ - private static void closeSafe(Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (IOException ignored) { - } - } - } - // endregion - - // region: Inner class: BitmapSampled - - /** - * Holds bitmap instance and the sample size that the bitmap was loaded/cropped with. - */ - static final class BitmapSampled { - - /** - * The bitmap instance - */ - public final Bitmap bitmap; - - /** - * The sample size used to lower the size of the bitmap (1,2,4,8,...) - */ - final int sampleSize; - - BitmapSampled(Bitmap bitmap, int sampleSize) { - this.bitmap = bitmap; - this.sampleSize = sampleSize; - } - } - // endregion - - // region: Inner class: RotateBitmapResult - - /** - * The result of {@link #rotateBitmapByExif(android.graphics.Bitmap, ExifInterface)}. - */ - static final class RotateBitmapResult { - - /** - * The loaded bitmap - */ - public final Bitmap bitmap; - - /** - * The degrees the image was rotated - */ - final int degrees; - - RotateBitmapResult(Bitmap bitmap, int degrees) { - this.bitmap = bitmap; - this.degrees = degrees; - } - } - // endregion -} diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImage.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImage.java deleted file mode 100644 index 07d36ea0..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImage.java +++ /dev/null @@ -1,1048 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth, -// inexhaustible as the great rivers. -// When they come to an end, -// they begin again, -// like the days and months; -// they die and are reborn, -// like the four seasons." -// -// - Sun Tsu, -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.Manifest; -import android.app.Activity; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.graphics.RectF; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.provider.MediaStore; - -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.fragment.app.Fragment; - -import java.io.File; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * Helper to simplify crop image work like starting pick-image acitvity and handling camera/gallery - * intents.
- * The goal of the helper is to simplify the starting and most-common usage of image cropping and - * not all porpose all possible scenario one-to-rule-them-all code base. So feel free to use it as - * is and as a wiki to make your own.
- * Added value you get out-of-the-box is some edge case handling that you may miss otherwise, like - * the stupid-ass Android camera result URI that may differ from version to version and from device - * to device. - */ -@SuppressWarnings("WeakerAccess, unused") -public final class CropImage { - - // region: Fields and Consts - - /** - * The key used to pass crop image source URI to {@link CropImageActivity}. - */ - public static final String CROP_IMAGE_EXTRA_SOURCE = "CROP_IMAGE_EXTRA_SOURCE"; - - /** - * The key used to pass crop image options to {@link CropImageActivity}. - */ - public static final String CROP_IMAGE_EXTRA_OPTIONS = "CROP_IMAGE_EXTRA_OPTIONS"; - - /** - * The key used to pass crop image bundle data to {@link CropImageActivity}. - */ - public static final String CROP_IMAGE_EXTRA_BUNDLE = "CROP_IMAGE_EXTRA_BUNDLE"; - - /** - * The key used to pass crop image result data back from {@link CropImageActivity}. - */ - public static final String CROP_IMAGE_EXTRA_RESULT = "CROP_IMAGE_EXTRA_RESULT"; - - /** - * The request code used to start pick image activity to be used on result to identify the this - * specific request. - */ - public static final int PICK_IMAGE_CHOOSER_REQUEST_CODE = 200; - - /** - * The request code used to request permission to pick image from external storage. - */ - public static final int PICK_IMAGE_PERMISSIONS_REQUEST_CODE = 201; - - /** - * The request code used to request permission to capture image from camera. - */ - public static final int CAMERA_CAPTURE_PERMISSIONS_REQUEST_CODE = 2011; - - /** - * The request code used to start {@link CropImageActivity} to be used on result to identify the - * this specific request. - */ - public static final int CROP_IMAGE_ACTIVITY_REQUEST_CODE = 203; - - /** - * The result code used to return error from {@link CropImageActivity}. - */ - public static final int CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE = 204; - // endregion - - private CropImage() { - } - - /** - * Create a new bitmap that has all pixels beyond the oval shape transparent. Old bitmap is - * recycled. - */ - public static Bitmap toOvalBitmap(@NonNull Bitmap bitmap) { - int width = bitmap.getWidth(); - int height = bitmap.getHeight(); - Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - - Canvas canvas = new Canvas(output); - - int color = 0xff424242; - Paint paint = new Paint(); - - paint.setAntiAlias(true); - canvas.drawARGB(0, 0, 0, 0); - paint.setColor(color); - - RectF rect = new RectF(0, 0, width, height); - canvas.drawOval(rect, paint); - paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - canvas.drawBitmap(bitmap, 0, 0, paint); - - bitmap.recycle(); - - return output; - } - - /** - * Start an activity to get image for cropping using chooser intent that will have all the - * available applications for the device like camera (MyCamera), galery (Photos), store apps - * (Dropbox), etc.
- * Use "pick_image_intent_chooser_title" string resource to override pick chooser title. - * - * @param activity the activity to be used to start activity from - */ - public static void startPickImageActivity(@NonNull Activity activity) { - activity.startActivityForResult( - getPickImageChooserIntent(activity), PICK_IMAGE_CHOOSER_REQUEST_CODE); - } - - /** - * Same as {@link #startPickImageActivity(Activity) startPickImageActivity} method but instead of - * being called and returning to an Activity, this method can be called and return to a Fragment. - * - * @param context The Fragments context. Use getContext() - * @param fragment The calling Fragment to start and return the image to - */ - public static void startPickImageActivity(@NonNull Context context, @NonNull Fragment fragment) { - fragment.startActivityForResult( - getPickImageChooserIntent(context), PICK_IMAGE_CHOOSER_REQUEST_CODE); - } - - /** - * Create a chooser intent to select the source to get image from.
- * The source can be camera's (ACTION_IMAGE_CAPTURE) or gallery's (ACTION_GET_CONTENT).
- * All possible sources are added to the intent chooser.
- * Use "pick_image_intent_chooser_title" string resource to override chooser title. - * - * @param context used to access Android APIs, like content resolve, it is your - * activity/fragment/widget. - */ - public static Intent getPickImageChooserIntent(@NonNull Context context) { - return getPickImageChooserIntent( - context, context.getString(R.string.pick_image_intent_chooser_title), false, true); - } - - /** - * Create a chooser intent to select the source to get image from.
- * The source can be camera's (ACTION_IMAGE_CAPTURE) or gallery's (ACTION_GET_CONTENT).
- * All possible sources are added to the intent chooser. - * - * @param context used to access Android APIs, like content resolve, it is your - * activity/fragment/widget. - * @param title the title to use for the chooser UI - * @param includeDocuments if to include KitKat documents activity containing all sources - * @param includeCamera if to include camera intents - */ - public static Intent getPickImageChooserIntent( - @NonNull Context context, - CharSequence title, - boolean includeDocuments, - boolean includeCamera) { - - List allIntents = new ArrayList<>(); - PackageManager packageManager = context.getPackageManager(); - - // collect all camera intents if Camera permission is available - if (!isExplicitCameraPermissionRequired(context) && includeCamera) { - allIntents.addAll(getCameraIntents(context, packageManager)); - } - - List galleryIntents = - getGalleryIntents(packageManager, Intent.ACTION_GET_CONTENT, includeDocuments); - if (galleryIntents.size() == 0) { - // if no intents found for get-content try pick intent action (Huawei P9). - galleryIntents = getGalleryIntents(packageManager, Intent.ACTION_PICK, includeDocuments); - } - allIntents.addAll(galleryIntents); - - Intent target; - if (allIntents.isEmpty()) { - target = new Intent(); - } else { - target = allIntents.get(allIntents.size() - 1); - allIntents.remove(allIntents.size() - 1); - } - - // Create a chooser from the main intent - Intent chooserIntent = Intent.createChooser(target, title); - - // Add all other intents - chooserIntent.putExtra( - Intent.EXTRA_INITIAL_INTENTS, allIntents.toArray(new Parcelable[allIntents.size()])); - - return chooserIntent; - } - - /** - * Get the main Camera intent for capturing image using device camera app. If the outputFileUri is - * null, a default Uri will be created with {@link #getCaptureImageOutputUri(Context)}, so then - * you will be able to get the pictureUri using {@link #getPickImageResultUri(Context, Intent)}. - * Otherwise, it is just you use the Uri passed to this method. - * - * @param context used to access Android APIs, like content resolve, it is your - * activity/fragment/widget. - * @param outputFileUri the Uri where the picture will be placed. - */ - public static Intent getCameraIntent(@NonNull Context context, Uri outputFileUri) { - Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - if (outputFileUri == null) { - outputFileUri = getCaptureImageOutputUri(context); - } - intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); - return intent; - } - - /** - * Get all Camera intents for capturing image using device camera apps. - */ - public static List getCameraIntents( - @NonNull Context context, @NonNull PackageManager packageManager) { - - List allIntents = new ArrayList<>(); - - // Determine Uri of camera image to save. - Uri outputFileUri = getCaptureImageOutputUri(context); - - Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - List listCam = packageManager.queryIntentActivities(captureIntent, 0); - for (ResolveInfo res : listCam) { - Intent intent = new Intent(captureIntent); - intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); - intent.setPackage(res.activityInfo.packageName); - if (outputFileUri != null) { - intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); - } - allIntents.add(intent); - } - - return allIntents; - } - - /** - * Get all Gallery intents for getting image from one of the apps of the device that handle - * images. - */ - public static List getGalleryIntents( - @NonNull PackageManager packageManager, String action, boolean includeDocuments) { - List intents = new ArrayList<>(); - Intent galleryIntent = - action == Intent.ACTION_GET_CONTENT - ? new Intent(action) - : new Intent(action, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); - galleryIntent.setType("image/*"); - List listGallery = packageManager.queryIntentActivities(galleryIntent, 0); - for (ResolveInfo res : listGallery) { - Intent intent = new Intent(galleryIntent); - intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); - intent.setPackage(res.activityInfo.packageName); - intents.add(intent); - } - - // remove documents intent - if (!includeDocuments) { - for (Intent intent : intents) { - if (intent - .getComponent() - .getClassName() - .equals("com.android.documentsui.DocumentsActivity")) { - intents.remove(intent); - break; - } - } - } - return intents; - } - - /** - * Check if explicetly requesting camera permission is required.
- * It is required in Android Marshmellow and above if "CAMERA" permission is requested in the - * manifest.
- * See StackOverflow - * question. - */ - public static boolean isExplicitCameraPermissionRequired(@NonNull Context context) { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && hasPermissionInManifest(context, "android.permission.CAMERA") - && context.checkSelfPermission(Manifest.permission.CAMERA) - != PackageManager.PERMISSION_GRANTED; - } - - /** - * Check if the app requests a specific permission in the manifest. - * - * @param permissionName the permission to check - * @return true - the permission in requested in manifest, false - not. - */ - public static boolean hasPermissionInManifest( - @NonNull Context context, @NonNull String permissionName) { - String packageName = context.getPackageName(); - try { - PackageInfo packageInfo = - context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); - final String[] declaredPermisisons = packageInfo.requestedPermissions; - if (declaredPermisisons != null && declaredPermisisons.length > 0) { - for (String p : declaredPermisisons) { - if (p.equalsIgnoreCase(permissionName)) { - return true; - } - } - } - } catch (PackageManager.NameNotFoundException e) { - } - return false; - } - - /** - * Get URI to image received from capture by camera. - * - * @param context used to access Android APIs, like content resolve, it is your - * activity/fragment/widget. - */ - public static Uri getCaptureImageOutputUri(@NonNull Context context) { - Uri outputFileUri = null; - File getImage = context.getExternalCacheDir(); - if (getImage != null) { - outputFileUri = Uri.fromFile(new File(getImage.getPath(), "pickImageResult.jpeg")); - } - return outputFileUri; - } - - /** - * Get the URI of the selected image from {@link #getPickImageChooserIntent(Context)}.
- * Will return the correct URI for camera and gallery image. - * - * @param context used to access Android APIs, like content resolve, it is your - * activity/fragment/widget. - * @param data the returned data of the activity result - */ - public static Uri getPickImageResultUri(@NonNull Context context, @Nullable Intent data) { - boolean isCamera = true; - if (data != null && data.getData() != null) { - String action = data.getAction(); - isCamera = action != null && action.equals(MediaStore.ACTION_IMAGE_CAPTURE); - } - return isCamera || data.getData() == null ? getCaptureImageOutputUri(context) : data.getData(); - } - - /** - * Check if the given picked image URI requires READ_EXTERNAL_STORAGE permissions.
- * Only relevant for API version 23 and above and not required for all URI's depends on the - * implementation of the app that was used for picking the image. So we just test if we can open - * the stream or do we get an exception when we try, Android is awesome. - * - * @param context used to access Android APIs, like content resolve, it is your - * activity/fragment/widget. - * @param uri the result URI of image pick. - * @return true - required permission are not granted, false - either no need for permissions or - * they are granted - */ - public static boolean isReadExternalStoragePermissionsRequired( - @NonNull Context context, @NonNull Uri uri) { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED - && isUriRequiresPermissions(context, uri); - } - - /** - * Test if we can open the given Android URI to test if permission required error is thrown.
- * Only relevant for API version 23 and above. - * - * @param context used to access Android APIs, like content resolve, it is your - * activity/fragment/widget. - * @param uri the result URI of image pick. - */ - public static boolean isUriRequiresPermissions(@NonNull Context context, @NonNull Uri uri) { - try { - ContentResolver resolver = context.getContentResolver(); - InputStream stream = resolver.openInputStream(uri); - if (stream != null) { - stream.close(); - } - return false; - } catch (Exception e) { - return true; - } - } - - /** - * Create {@link ActivityBuilder} instance to open image picker for cropping and then start {@link - * CropImageActivity} to crop the selected image.
- * Result will be received in {@link Activity#onActivityResult(int, int, Intent)} and can be - * retrieved using {@link #getActivityResult(Intent)}. - * - * @return builder for Crop Image Activity - */ - public static ActivityBuilder activity() { - return new ActivityBuilder(null); - } - - /** - * Create {@link ActivityBuilder} instance to start {@link CropImageActivity} to crop the given - * image.
- * Result will be received in {@link Activity#onActivityResult(int, int, Intent)} and can be - * retrieved using {@link #getActivityResult(Intent)}. - * - * @param uri the image Android uri source to crop or null to start a picker - * @return builder for Crop Image Activity - */ - public static ActivityBuilder activity(@Nullable Uri uri) { - return new ActivityBuilder(uri); - } - - /** - * Get {@link CropImageActivity} result data object for crop image activity started using {@link - * #activity(Uri)}. - * - * @param data result data intent as received in {@link Activity#onActivityResult(int, int, - * Intent)}. - * @return Crop Image Activity Result object or null if none exists - */ - public static ActivityResult getActivityResult(@Nullable Intent data) { - return data != null ? (ActivityResult) data.getParcelableExtra(CROP_IMAGE_EXTRA_RESULT) : null; - } - - // region: Inner class: ActivityBuilder - - /** - * Builder used for creating Image Crop Activity by user request. - */ - public static final class ActivityBuilder { - - /** - * The image to crop source Android uri. - */ - @Nullable - private final Uri mSource; - - /** - * Options for image crop UX - */ - private final CropImageOptions mOptions; - - private ActivityBuilder(@Nullable Uri source) { - mSource = source; - mOptions = new CropImageOptions(); - } - - /** - * Get {@link CropImageActivity} intent to start the activity. - */ - public Intent getIntent(@NonNull Context context) { - return getIntent(context, CropImageActivity.class); - } - - /** - * Get {@link CropImageActivity} intent to start the activity. - */ - public Intent getIntent(@NonNull Context context, @Nullable Class cls) { - mOptions.validate(); - - Intent intent = new Intent(); - intent.setClass(context, cls); - Bundle bundle = new Bundle(); - bundle.putParcelable(CROP_IMAGE_EXTRA_SOURCE, mSource); - bundle.putParcelable(CROP_IMAGE_EXTRA_OPTIONS, mOptions); - intent.putExtra(CropImage.CROP_IMAGE_EXTRA_BUNDLE, bundle); - return intent; - } - - /** - * Start {@link CropImageActivity}. - * - * @param activity activity to receive result - */ - public void start(@NonNull Activity activity) { - mOptions.validate(); - activity.startActivityForResult(getIntent(activity), CROP_IMAGE_ACTIVITY_REQUEST_CODE); - } - - /** - * Start {@link CropImageActivity}. - * - * @param activity activity to receive result - */ - public void start(@NonNull Activity activity, @Nullable Class cls) { - mOptions.validate(); - activity.startActivityForResult(getIntent(activity, cls), CROP_IMAGE_ACTIVITY_REQUEST_CODE); - } - - /** - * Start {@link CropImageActivity}. - * - * @param fragment fragment to receive result - */ - public void start(@NonNull Context context, @NonNull Fragment fragment) { - fragment.startActivityForResult(getIntent(context), CROP_IMAGE_ACTIVITY_REQUEST_CODE); - } - - /** - * Start {@link CropImageActivity}. - * - * @param fragment fragment to receive result - */ - @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) - public void start(@NonNull Context context, @NonNull android.app.Fragment fragment) { - fragment.startActivityForResult(getIntent(context), CROP_IMAGE_ACTIVITY_REQUEST_CODE); - } - - /** - * Start {@link CropImageActivity}. - * - * @param fragment fragment to receive result - */ - public void start( - @NonNull Context context, @NonNull Fragment fragment, @Nullable Class cls) { - fragment.startActivityForResult(getIntent(context, cls), CROP_IMAGE_ACTIVITY_REQUEST_CODE); - } - - /** - * Start {@link CropImageActivity}. - * - * @param fragment fragment to receive result - */ - @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) - public void start( - @NonNull Context context, @NonNull android.app.Fragment fragment, @Nullable Class cls) { - fragment.startActivityForResult(getIntent(context, cls), CROP_IMAGE_ACTIVITY_REQUEST_CODE); - } - - /** - * The shape of the cropping window.
- * To set square/circle crop shape set aspect ratio to 1:1.
- * Default: RECTANGLE - */ - public ActivityBuilder setCropShape(@NonNull CropImageView.CropShape cropShape) { - mOptions.cropShape = cropShape; - return this; - } - - /** - * An edge of the crop window will snap to the corresponding edge of a specified bounding box - * when the crop window edge is less than or equal to this distance (in pixels) away from the - * bounding box edge (in pixels).
- * Default: 3dp - */ - public ActivityBuilder setSnapRadius(float snapRadius) { - mOptions.snapRadius = snapRadius; - return this; - } - - /** - * The radius of the touchable area around the handle (in pixels).
- * We are basing this value off of the recommended 48dp Rhythm.
- * See: http://developer.android.com/design/style/metrics-grids.html#48dp-rhythm
- * Default: 48dp - */ - public ActivityBuilder setTouchRadius(float touchRadius) { - mOptions.touchRadius = touchRadius; - return this; - } - - /** - * whether the guidelines should be on, off, or only showing when resizing.
- * Default: ON_TOUCH - */ - public ActivityBuilder setGuidelines(@NonNull CropImageView.Guidelines guidelines) { - mOptions.guidelines = guidelines; - return this; - } - - /** - * The initial scale type of the image in the crop image view
- * Default: FIT_CENTER - */ - public ActivityBuilder setScaleType(@NonNull CropImageView.ScaleType scaleType) { - mOptions.scaleType = scaleType; - return this; - } - - /** - * if to show crop overlay UI what contains the crop window UI surrounded by background over the - * cropping image.
- * default: true, may disable for animation or frame transition. - */ - public ActivityBuilder setShowCropOverlay(boolean showCropOverlay) { - mOptions.showCropOverlay = showCropOverlay; - return this; - } - - /** - * if auto-zoom functionality is enabled.
- * default: true. - */ - public ActivityBuilder setAutoZoomEnabled(boolean autoZoomEnabled) { - mOptions.autoZoomEnabled = autoZoomEnabled; - return this; - } - - /** - * if multi touch functionality is enabled.
- * default: true. - */ - public ActivityBuilder setMultiTouchEnabled(boolean multiTouchEnabled) { - mOptions.multiTouchEnabled = multiTouchEnabled; - return this; - } - - /** - * The max zoom allowed during cropping.
- * Default: 4 - */ - public ActivityBuilder setMaxZoom(int maxZoom) { - mOptions.maxZoom = maxZoom; - return this; - } - - /** - * The initial crop window padding from image borders in percentage of the cropping image - * dimensions.
- * Default: 0.1 - */ - public ActivityBuilder setInitialCropWindowPaddingRatio(float initialCropWindowPaddingRatio) { - mOptions.initialCropWindowPaddingRatio = initialCropWindowPaddingRatio; - return this; - } - - /** - * whether the width to height aspect ratio should be maintained or free to change.
- * Default: false - */ - public ActivityBuilder setFixAspectRatio(boolean fixAspectRatio) { - mOptions.fixAspectRatio = fixAspectRatio; - return this; - } - - /** - * the X,Y value of the aspect ratio.
- * Also sets fixes aspect ratio to TRUE.
- * Default: 1/1 - * - * @param aspectRatioX the width - * @param aspectRatioY the height - */ - public ActivityBuilder setAspectRatio(int aspectRatioX, int aspectRatioY) { - mOptions.aspectRatioX = aspectRatioX; - mOptions.aspectRatioY = aspectRatioY; - mOptions.fixAspectRatio = true; - return this; - } - - /** - * the thickness of the guidelines lines (in pixels).
- * Default: 3dp - */ - public ActivityBuilder setBorderLineThickness(float borderLineThickness) { - mOptions.borderLineThickness = borderLineThickness; - return this; - } - - /** - * the color of the guidelines lines.
- * Default: Color.argb(170, 255, 255, 255) - */ - public ActivityBuilder setBorderLineColor(int borderLineColor) { - mOptions.borderLineColor = borderLineColor; - return this; - } - - /** - * thickness of the corner line (in pixels).
- * Default: 2dp - */ - public ActivityBuilder setBorderCornerThickness(float borderCornerThickness) { - mOptions.borderCornerThickness = borderCornerThickness; - return this; - } - - /** - * the offset of corner line from crop window border (in pixels).
- * Default: 5dp - */ - public ActivityBuilder setBorderCornerOffset(float borderCornerOffset) { - mOptions.borderCornerOffset = borderCornerOffset; - return this; - } - - /** - * the length of the corner line away from the corner (in pixels).
- * Default: 14dp - */ - public ActivityBuilder setBorderCornerLength(float borderCornerLength) { - mOptions.borderCornerLength = borderCornerLength; - return this; - } - - /** - * the color of the corner line.
- * Default: WHITE - */ - public ActivityBuilder setBorderCornerColor(int borderCornerColor) { - mOptions.borderCornerColor = borderCornerColor; - return this; - } - - /** - * the thickness of the guidelines lines (in pixels).
- * Default: 1dp - */ - public ActivityBuilder setGuidelinesThickness(float guidelinesThickness) { - mOptions.guidelinesThickness = guidelinesThickness; - return this; - } - - /** - * the color of the guidelines lines.
- * Default: Color.argb(170, 255, 255, 255) - */ - public ActivityBuilder setGuidelinesColor(int guidelinesColor) { - mOptions.guidelinesColor = guidelinesColor; - return this; - } - - /** - * the color of the overlay background around the crop window cover the image parts not in the - * crop window.
- * Default: Color.argb(119, 0, 0, 0) - */ - public ActivityBuilder setBackgroundColor(int backgroundColor) { - mOptions.backgroundColor = backgroundColor; - return this; - } - - /** - * the min size the crop window is allowed to be (in pixels).
- * Default: 42dp, 42dp - */ - public ActivityBuilder setMinCropWindowSize(int minCropWindowWidth, int minCropWindowHeight) { - mOptions.minCropWindowWidth = minCropWindowWidth; - mOptions.minCropWindowHeight = minCropWindowHeight; - return this; - } - - /** - * the min size the resulting cropping image is allowed to be, affects the cropping window - * limits (in pixels).
- * Default: 40px, 40px - */ - public ActivityBuilder setMinCropResultSize(int minCropResultWidth, int minCropResultHeight) { - mOptions.minCropResultWidth = minCropResultWidth; - mOptions.minCropResultHeight = minCropResultHeight; - return this; - } - - /** - * the max size the resulting cropping image is allowed to be, affects the cropping window - * limits (in pixels).
- * Default: 99999, 99999 - */ - public ActivityBuilder setMaxCropResultSize(int maxCropResultWidth, int maxCropResultHeight) { - mOptions.maxCropResultWidth = maxCropResultWidth; - mOptions.maxCropResultHeight = maxCropResultHeight; - return this; - } - - /** - * the title of the {@link CropImageActivity}.
- * Default: "" - */ - public ActivityBuilder setActivityTitle(CharSequence activityTitle) { - mOptions.activityTitle = activityTitle; - return this; - } - - /** - * the color to use for action bar items icons.
- * Default: NONE - */ - public ActivityBuilder setActivityMenuIconColor(int activityMenuIconColor) { - mOptions.activityMenuIconColor = activityMenuIconColor; - return this; - } - - /** - * the Android Uri to save the cropped image to.
- * Default: NONE, will create a temp file - */ - public ActivityBuilder setOutputUri(Uri outputUri) { - mOptions.outputUri = outputUri; - return this; - } - - /** - * the compression format to use when writting the image.
- * Default: JPEG - */ - public ActivityBuilder setOutputCompressFormat(Bitmap.CompressFormat outputCompressFormat) { - mOptions.outputCompressFormat = outputCompressFormat; - return this; - } - - /** - * the quility (if applicable) to use when writting the image (0 - 100).
- * Default: 90 - */ - public ActivityBuilder setOutputCompressQuality(int outputCompressQuality) { - mOptions.outputCompressQuality = outputCompressQuality; - return this; - } - - /** - * the size to resize the cropped image to.
- * Uses {@link CropImageView.RequestSizeOptions#RESIZE_INSIDE} option.
- * Default: 0, 0 - not set, will not resize - */ - public ActivityBuilder setRequestedSize(int reqWidth, int reqHeight) { - return setRequestedSize(reqWidth, reqHeight, CropImageView.RequestSizeOptions.RESIZE_INSIDE); - } - - /** - * the size to resize the cropped image to.
- * Default: 0, 0 - not set, will not resize - */ - public ActivityBuilder setRequestedSize( - int reqWidth, int reqHeight, CropImageView.RequestSizeOptions options) { - mOptions.outputRequestWidth = reqWidth; - mOptions.outputRequestHeight = reqHeight; - mOptions.outputRequestSizeOptions = options; - return this; - } - - /** - * if the result of crop image activity should not save the cropped image bitmap.
- * Used if you want to crop the image manually and need only the crop rectangle and rotation - * data.
- * Default: false - */ - public ActivityBuilder setNoOutputImage(boolean noOutputImage) { - mOptions.noOutputImage = noOutputImage; - return this; - } - - /** - * the initial rectangle to set on the cropping image after loading.
- * Default: NONE - will initialize using initial crop window padding ratio - */ - public ActivityBuilder setInitialCropWindowRectangle(Rect initialCropWindowRectangle) { - mOptions.initialCropWindowRectangle = initialCropWindowRectangle; - return this; - } - - /** - * the initial rotation to set on the cropping image after loading (0-360 degrees clockwise). - *
- * Default: NONE - will read image exif data - */ - public ActivityBuilder setInitialRotation(int initialRotation) { - mOptions.initialRotation = (initialRotation + 360) % 360; - return this; - } - - /** - * if to allow rotation during cropping.
- * Default: true - */ - public ActivityBuilder setAllowRotation(boolean allowRotation) { - mOptions.allowRotation = allowRotation; - return this; - } - - /** - * if to allow flipping during cropping.
- * Default: true - */ - public ActivityBuilder setAllowFlipping(boolean allowFlipping) { - mOptions.allowFlipping = allowFlipping; - return this; - } - - /** - * if to allow counter-clockwise rotation during cropping.
- * Note: if rotation is disabled this option has no effect.
- * Default: false - */ - public ActivityBuilder setAllowCounterRotation(boolean allowCounterRotation) { - mOptions.allowCounterRotation = allowCounterRotation; - return this; - } - - /** - * The amount of degreees to rotate clockwise or counter-clockwise (0-360).
- * Default: 90 - */ - public ActivityBuilder setRotationDegrees(int rotationDegrees) { - mOptions.rotationDegrees = (rotationDegrees + 360) % 360; - return this; - } - - /** - * whether the image should be flipped horizontally.
- * Default: false - */ - public ActivityBuilder setFlipHorizontally(boolean flipHorizontally) { - mOptions.flipHorizontally = flipHorizontally; - return this; - } - - /** - * whether the image should be flipped vertically.
- * Default: false - */ - public ActivityBuilder setFlipVertically(boolean flipVertically) { - mOptions.flipVertically = flipVertically; - return this; - } - - /** - * optional, set crop menu crop button title.
- * Default: null, will use resource string: crop_image_menu_crop - */ - public ActivityBuilder setCropMenuCropButtonTitle(CharSequence title) { - mOptions.cropMenuCropButtonTitle = title; - return this; - } - - /** - * Image resource id to use for crop icon instead of text.
- * Default: 0 - */ - public ActivityBuilder setCropMenuCropButtonIcon(@DrawableRes int drawableResource) { - mOptions.cropMenuCropButtonIcon = drawableResource; - return this; - } - } - // endregion - - // region: Inner class: ActivityResult - - /** - * Result data of Crop Image Activity. - */ - public static final class ActivityResult extends CropImageView.CropResult implements Parcelable { - - public static final Creator CREATOR = - new Creator() { - @Override - public ActivityResult createFromParcel(Parcel in) { - return new ActivityResult(in); - } - - @Override - public ActivityResult[] newArray(int size) { - return new ActivityResult[size]; - } - }; - - public ActivityResult( - Uri originalUri, - Uri uri, - Exception error, - float[] cropPoints, - Rect cropRect, - int rotation, - Rect wholeImageRect, - int sampleSize) { - super( - null, - originalUri, - null, - uri, - error, - cropPoints, - cropRect, - wholeImageRect, - rotation, - sampleSize); - } - - protected ActivityResult(Parcel in) { - super( - null, - (Uri) in.readParcelable(Uri.class.getClassLoader()), - null, - (Uri) in.readParcelable(Uri.class.getClassLoader()), - (Exception) in.readSerializable(), - in.createFloatArray(), - (Rect) in.readParcelable(Rect.class.getClassLoader()), - (Rect) in.readParcelable(Rect.class.getClassLoader()), - in.readInt(), - in.readInt()); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(getOriginalUri(), flags); - dest.writeParcelable(getUri(), flags); - dest.writeSerializable(getError()); - dest.writeFloatArray(getCropPoints()); - dest.writeParcelable(getCropRect(), flags); - dest.writeParcelable(getWholeImageRect(), flags); - dest.writeInt(getRotation()); - dest.writeInt(getSampleSize()); - } - - @Override - public int describeContents() { - return 0; - } - } - // endregion -} diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageActivity.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageActivity.java deleted file mode 100644 index bd9d0afe..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageActivity.java +++ /dev/null @@ -1,367 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth, -// inexhaustible as the great rivers. -// When they come to an end, -// they begin again, -// like the days and months; -// they die and are reborn, -// like the four seasons." -// -// - Sun Tsu, -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.Manifest; -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.content.ContextCompat; - -import java.io.File; -import java.io.IOException; - -/** - * Built-in activity for image cropping.
- * Use {@link CropImage#activity(Uri)} to create a builder to start this activity. - */ -public class CropImageActivity extends AppCompatActivity - implements CropImageView.OnSetImageUriCompleteListener, - CropImageView.OnCropImageCompleteListener { - - /** - * The crop image view library widget used in the activity - */ - private CropImageView mCropImageView; - - /** - * Persist URI image to crop URI if specific permissions are required - */ - private Uri mCropImageUri; - - /** - * the options that were set for the crop image - */ - private CropImageOptions mOptions; - - @Override - @SuppressLint("NewApi") - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.crop_image_activity); - - mCropImageView = findViewById(R.id.cropImageView); - - Bundle bundle = getIntent().getBundleExtra(CropImage.CROP_IMAGE_EXTRA_BUNDLE); - mCropImageUri = bundle.getParcelable(CropImage.CROP_IMAGE_EXTRA_SOURCE); - mOptions = bundle.getParcelable(CropImage.CROP_IMAGE_EXTRA_OPTIONS); - - if (savedInstanceState == null) { - if (mCropImageUri == null || mCropImageUri.equals(Uri.EMPTY)) { - if (CropImage.isExplicitCameraPermissionRequired(this)) { - // request permissions and handle the result in onRequestPermissionsResult() - requestPermissions( - new String[]{Manifest.permission.CAMERA}, - CropImage.CAMERA_CAPTURE_PERMISSIONS_REQUEST_CODE); - } else { - CropImage.startPickImageActivity(this); - } - } else if (CropImage.isReadExternalStoragePermissionsRequired(this, mCropImageUri)) { - // request permissions and handle the result in onRequestPermissionsResult() - requestPermissions( - new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, - CropImage.PICK_IMAGE_PERMISSIONS_REQUEST_CODE); - } else { - // no permissions required or already grunted, can start crop image activity - mCropImageView.setImageUriAsync(mCropImageUri); - } - } - - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - CharSequence title = mOptions != null && - mOptions.activityTitle != null && mOptions.activityTitle.length() > 0 - ? mOptions.activityTitle - : getResources().getString(R.string.crop_image_activity_title); - actionBar.setTitle(title); - actionBar.setDisplayHomeAsUpEnabled(true); - } - } - - @Override - protected void onStart() { - super.onStart(); - mCropImageView.setOnSetImageUriCompleteListener(this); - mCropImageView.setOnCropImageCompleteListener(this); - } - - @Override - protected void onStop() { - super.onStop(); - mCropImageView.setOnSetImageUriCompleteListener(null); - mCropImageView.setOnCropImageCompleteListener(null); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.crop_image_menu, menu); - - if (!mOptions.allowRotation) { - menu.removeItem(R.id.crop_image_menu_rotate_left); - menu.removeItem(R.id.crop_image_menu_rotate_right); - } else if (mOptions.allowCounterRotation) { - menu.findItem(R.id.crop_image_menu_rotate_left).setVisible(true); - } - - if (!mOptions.allowFlipping) { - menu.removeItem(R.id.crop_image_menu_flip); - } - - if (mOptions.cropMenuCropButtonTitle != null) { - menu.findItem(R.id.crop_image_menu_crop).setTitle(mOptions.cropMenuCropButtonTitle); - } - - Drawable cropIcon = null; - try { - if (mOptions.cropMenuCropButtonIcon != 0) { - cropIcon = ContextCompat.getDrawable(this, mOptions.cropMenuCropButtonIcon); - menu.findItem(R.id.crop_image_menu_crop).setIcon(cropIcon); - } - } catch (Exception e) { - e.printStackTrace(); - } - - if (mOptions.activityMenuIconColor != 0) { - updateMenuItemIconColor( - menu, R.id.crop_image_menu_rotate_left, mOptions.activityMenuIconColor); - updateMenuItemIconColor( - menu, R.id.crop_image_menu_rotate_right, mOptions.activityMenuIconColor); - updateMenuItemIconColor(menu, R.id.crop_image_menu_flip, mOptions.activityMenuIconColor); - if (cropIcon != null) { - updateMenuItemIconColor(menu, R.id.crop_image_menu_crop, mOptions.activityMenuIconColor); - } - } - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.crop_image_menu_crop) { - cropImage(); - return true; - } - if (item.getItemId() == R.id.crop_image_menu_rotate_left) { - rotateImage(-mOptions.rotationDegrees); - return true; - } - if (item.getItemId() == R.id.crop_image_menu_rotate_right) { - rotateImage(mOptions.rotationDegrees); - return true; - } - if (item.getItemId() == R.id.crop_image_menu_flip_horizontally) { - mCropImageView.flipImageHorizontally(); - return true; - } - if (item.getItemId() == R.id.crop_image_menu_flip_vertically) { - mCropImageView.flipImageVertically(); - return true; - } - if (item.getItemId() == android.R.id.home) { - setResultCancel(); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onBackPressed() { - super.onBackPressed(); - setResultCancel(); - } - - @Override - @SuppressLint("NewApi") - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - - // handle result of pick image chooser - if (requestCode == CropImage.PICK_IMAGE_CHOOSER_REQUEST_CODE) { - if (resultCode == Activity.RESULT_CANCELED) { - // User cancelled the picker. We don't have anything to crop - setResultCancel(); - } - - if (resultCode == Activity.RESULT_OK) { - mCropImageUri = CropImage.getPickImageResultUri(this, data); - - // For API >= 23 we need to check specifically that we have permissions to read external - // storage. - if (CropImage.isReadExternalStoragePermissionsRequired(this, mCropImageUri)) { - // request permissions and handle the result in onRequestPermissionsResult() - requestPermissions( - new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, - CropImage.PICK_IMAGE_PERMISSIONS_REQUEST_CODE); - } else { - // no permissions required or already grunted, can start crop image activity - mCropImageView.setImageUriAsync(mCropImageUri); - } - } - } - } - - @Override - public void onRequestPermissionsResult( - int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (requestCode == CropImage.PICK_IMAGE_PERMISSIONS_REQUEST_CODE) { - if (mCropImageUri != null - && grantResults.length > 0 - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // required permissions granted, start crop image activity - mCropImageView.setImageUriAsync(mCropImageUri); - } else { - Toast.makeText(this, R.string.crop_image_activity_no_permissions, Toast.LENGTH_LONG).show(); - setResultCancel(); - } - } - - if (requestCode == CropImage.CAMERA_CAPTURE_PERMISSIONS_REQUEST_CODE) { - // Irrespective of whether camera permission was given or not, we show the picker - // The picker will not add the camera intent if permission is not available - CropImage.startPickImageActivity(this); - } - } - - @Override - public void onSetImageUriComplete(CropImageView view, Uri uri, Exception error) { - if (error == null) { - if (mOptions.initialCropWindowRectangle != null) { - mCropImageView.setCropRect(mOptions.initialCropWindowRectangle); - } - if (mOptions.initialRotation > -1) { - mCropImageView.setRotatedDegrees(mOptions.initialRotation); - } - } else { - setResult(null, error, 1); - } - } - - @Override - public void onCropImageComplete(CropImageView view, CropImageView.CropResult result) { - setResult(result.getUri(), result.getError(), result.getSampleSize()); - } - - // region: Private methods - - /** - * Execute crop image and save the result tou output uri. - */ - protected void cropImage() { - if (mOptions.noOutputImage) { - setResult(null, null, 1); - } else { - Uri outputUri = getOutputUri(); - mCropImageView.saveCroppedImageAsync( - outputUri, - mOptions.outputCompressFormat, - mOptions.outputCompressQuality, - mOptions.outputRequestWidth, - mOptions.outputRequestHeight, - mOptions.outputRequestSizeOptions); - } - } - - /** - * Rotate the image in the crop image view. - */ - protected void rotateImage(int degrees) { - mCropImageView.rotateImage(degrees); - } - - /** - * Get Android uri to save the cropped image into.
- * Use the given in options or create a temp file. - */ - protected Uri getOutputUri() { - Uri outputUri = mOptions.outputUri; - if (outputUri == null || outputUri.equals(Uri.EMPTY)) { - try { - String ext = - mOptions.outputCompressFormat == Bitmap.CompressFormat.JPEG - ? ".jpg" - : mOptions.outputCompressFormat == Bitmap.CompressFormat.PNG ? ".png" : ".webp"; - outputUri = Uri.fromFile(File.createTempFile("cropped", ext, getCacheDir())); - } catch (IOException e) { - throw new RuntimeException("Failed to create temp file for output image", e); - } - } - return outputUri; - } - - /** - * Result with cropped image data or error if failed. - */ - protected void setResult(Uri uri, Exception error, int sampleSize) { - int resultCode = error == null ? RESULT_OK : CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE; - setResult(resultCode, getResultIntent(uri, error, sampleSize)); - finish(); - } - - /** - * Cancel of cropping activity. - */ - protected void setResultCancel() { - setResult(RESULT_CANCELED); - finish(); - } - - /** - * Get intent instance to be used for the result of this activity. - */ - protected Intent getResultIntent(Uri uri, Exception error, int sampleSize) { - CropImage.ActivityResult result = - new CropImage.ActivityResult( - mCropImageView.getImageUri(), - uri, - error, - mCropImageView.getCropPoints(), - mCropImageView.getCropRect(), - mCropImageView.getRotatedDegrees(), - mCropImageView.getWholeImageRect(), - sampleSize); - Intent intent = new Intent(); - intent.putExtras(getIntent()); - intent.putExtra(CropImage.CROP_IMAGE_EXTRA_RESULT, result); - return intent; - } - - /** - * Update the color of a specific menu item to the given color. - */ - private void updateMenuItemIconColor(Menu menu, int itemId, int color) { - MenuItem menuItem = menu.findItem(itemId); - if (menuItem != null) { - Drawable menuItemIcon = menuItem.getIcon(); - if (menuItemIcon != null) { - try { - menuItemIcon.mutate(); - menuItemIcon.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); - menuItem.setIcon(menuItemIcon); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } -} diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageAnimation.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageAnimation.java deleted file mode 100644 index 2861b857..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageAnimation.java +++ /dev/null @@ -1,123 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth, -// inexhaustible as the great rivers. -// When they come to an end, -// they begin again, -// like the days and months; -// they die and are reborn, -// like the four seasons." -// -// - Sun Tsu, -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.graphics.Matrix; -import android.graphics.RectF; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.Animation; -import android.view.animation.Transformation; -import android.widget.ImageView; - -/** - * Animation to handle smooth cropping image matrix transformation change, specifically for - * zoom-in/out. - */ -final class CropImageAnimation extends Animation implements Animation.AnimationListener { - - // region: Fields and Consts - - private final ImageView mImageView; - - private final CropOverlayView mCropOverlayView; - - private final float[] mStartBoundPoints = new float[8]; - - private final float[] mEndBoundPoints = new float[8]; - - private final RectF mStartCropWindowRect = new RectF(); - - private final RectF mEndCropWindowRect = new RectF(); - - private final float[] mStartImageMatrix = new float[9]; - - private final float[] mEndImageMatrix = new float[9]; - - private final RectF mAnimRect = new RectF(); - - private final float[] mAnimPoints = new float[8]; - - private final float[] mAnimMatrix = new float[9]; - // endregion - - public CropImageAnimation(ImageView cropImageView, CropOverlayView cropOverlayView) { - mImageView = cropImageView; - mCropOverlayView = cropOverlayView; - - setDuration(300); - setFillAfter(true); - setInterpolator(new AccelerateDecelerateInterpolator()); - setAnimationListener(this); - } - - public void setStartState(float[] boundPoints, Matrix imageMatrix) { - reset(); - System.arraycopy(boundPoints, 0, mStartBoundPoints, 0, 8); - mStartCropWindowRect.set(mCropOverlayView.getCropWindowRect()); - imageMatrix.getValues(mStartImageMatrix); - } - - public void setEndState(float[] boundPoints, Matrix imageMatrix) { - System.arraycopy(boundPoints, 0, mEndBoundPoints, 0, 8); - mEndCropWindowRect.set(mCropOverlayView.getCropWindowRect()); - imageMatrix.getValues(mEndImageMatrix); - } - - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - - mAnimRect.left = - mStartCropWindowRect.left - + (mEndCropWindowRect.left - mStartCropWindowRect.left) * interpolatedTime; - mAnimRect.top = - mStartCropWindowRect.top - + (mEndCropWindowRect.top - mStartCropWindowRect.top) * interpolatedTime; - mAnimRect.right = - mStartCropWindowRect.right - + (mEndCropWindowRect.right - mStartCropWindowRect.right) * interpolatedTime; - mAnimRect.bottom = - mStartCropWindowRect.bottom - + (mEndCropWindowRect.bottom - mStartCropWindowRect.bottom) * interpolatedTime; - mCropOverlayView.setCropWindowRect(mAnimRect); - - for (int i = 0; i < mAnimPoints.length; i++) { - mAnimPoints[i] = - mStartBoundPoints[i] + (mEndBoundPoints[i] - mStartBoundPoints[i]) * interpolatedTime; - } - mCropOverlayView.setBounds(mAnimPoints, mImageView.getWidth(), mImageView.getHeight()); - - for (int i = 0; i < mAnimMatrix.length; i++) { - mAnimMatrix[i] = - mStartImageMatrix[i] + (mEndImageMatrix[i] - mStartImageMatrix[i]) * interpolatedTime; - } - Matrix m = mImageView.getImageMatrix(); - m.setValues(mAnimMatrix); - mImageView.setImageMatrix(m); - - mImageView.invalidate(); - mCropOverlayView.invalidate(); - } - - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - mImageView.clearAnimation(); - } - - @Override - public void onAnimationRepeat(Animation animation) { - } -} diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageOptions.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageOptions.java deleted file mode 100644 index 5a9256a8..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageOptions.java +++ /dev/null @@ -1,541 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth; -// inexhaustible as the great rivers. -// When they come to an end; -// they begin again; -// like the days and months; -// they die and are reborn; -// like the four seasons." -// -// - Sun Tsu; -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.Rect; -import android.net.Uri; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.DisplayMetrics; -import android.util.TypedValue; - -/** - * All the possible options that can be set to customize crop image.
- * Initialized with default values. - */ -public class CropImageOptions implements Parcelable { - - public static final Creator CREATOR = - new Creator() { - @Override - public CropImageOptions createFromParcel(Parcel in) { - return new CropImageOptions(in); - } - - @Override - public CropImageOptions[] newArray(int size) { - return new CropImageOptions[size]; - } - }; - - /** - * The shape of the cropping window. - */ - public CropImageView.CropShape cropShape; - - /** - * An edge of the crop window will snap to the corresponding edge of a specified bounding box when - * the crop window edge is less than or equal to this distance (in pixels) away from the bounding - * box edge. (in pixels) - */ - public float snapRadius; - - /** - * The radius of the touchable area around the handle. (in pixels)
- * We are basing this value off of the recommended 48dp Rhythm.
- * See: http://developer.android.com/design/style/metrics-grids.html#48dp-rhythm - */ - public float touchRadius; - - /** - * whether the guidelines should be on, off, or only showing when resizing. - */ - public CropImageView.Guidelines guidelines; - - /** - * The initial scale type of the image in the crop image view - */ - public CropImageView.ScaleType scaleType; - - /** - * if to show crop overlay UI what contains the crop window UI surrounded by background over the - * cropping image.
- * default: true, may disable for animation or frame transition. - */ - public boolean showCropOverlay; - - /** - * if to show progress bar when image async loading/cropping is in progress.
- * default: true, disable to provide custom progress bar UI. - */ - public boolean showProgressBar; - - /** - * if auto-zoom functionality is enabled.
- * default: true. - */ - public boolean autoZoomEnabled; - - /** - * if multi-touch should be enabled on the crop box default: false - */ - public boolean multiTouchEnabled; - - /** - * The max zoom allowed during cropping. - */ - public int maxZoom; - - /** - * The initial crop window padding from image borders in percentage of the cropping image - * dimensions. - */ - public float initialCropWindowPaddingRatio; - - /** - * whether the width to height aspect ratio should be maintained or free to change. - */ - public boolean fixAspectRatio; - - /** - * the X value of the aspect ratio. - */ - public int aspectRatioX; - - /** - * the Y value of the aspect ratio. - */ - public int aspectRatioY; - - /** - * the thickness of the guidelines lines in pixels. (in pixels) - */ - public float borderLineThickness; - - /** - * the color of the guidelines lines - */ - public int borderLineColor; - - /** - * thickness of the corner line. (in pixels) - */ - public float borderCornerThickness; - - /** - * the offset of corner line from crop window border. (in pixels) - */ - public float borderCornerOffset; - - /** - * the length of the corner line away from the corner. (in pixels) - */ - public float borderCornerLength; - - /** - * the color of the corner line - */ - public int borderCornerColor; - - /** - * the thickness of the guidelines lines. (in pixels) - */ - public float guidelinesThickness; - - /** - * the color of the guidelines lines - */ - public int guidelinesColor; - - /** - * the color of the overlay background around the crop window cover the image parts not in the - * crop window. - */ - public int backgroundColor; - - /** - * the min width the crop window is allowed to be. (in pixels) - */ - public int minCropWindowWidth; - - /** - * the min height the crop window is allowed to be. (in pixels) - */ - public int minCropWindowHeight; - - /** - * the min width the resulting cropping image is allowed to be, affects the cropping window - * limits. (in pixels) - */ - public int minCropResultWidth; - - /** - * the min height the resulting cropping image is allowed to be, affects the cropping window - * limits. (in pixels) - */ - public int minCropResultHeight; - - /** - * the max width the resulting cropping image is allowed to be, affects the cropping window - * limits. (in pixels) - */ - public int maxCropResultWidth; - - /** - * the max height the resulting cropping image is allowed to be, affects the cropping window - * limits. (in pixels) - */ - public int maxCropResultHeight; - - /** - * the title of the {@link CropImageActivity} - */ - public CharSequence activityTitle; - - /** - * the color to use for action bar items icons - */ - public int activityMenuIconColor; - - /** - * the Android Uri to save the cropped image to - */ - public Uri outputUri; - - /** - * the compression format to use when writing the image - */ - public Bitmap.CompressFormat outputCompressFormat; - - /** - * the quality (if applicable) to use when writing the image (0 - 100) - */ - public int outputCompressQuality; - - /** - * the width to resize the cropped image to (see options) - */ - public int outputRequestWidth; - - /** - * the height to resize the cropped image to (see options) - */ - public int outputRequestHeight; - - /** - * the resize method to use on the cropped bitmap (see options documentation) - */ - public CropImageView.RequestSizeOptions outputRequestSizeOptions; - - /** - * if the result of crop image activity should not save the cropped image bitmap - */ - public boolean noOutputImage; - - /** - * the initial rectangle to set on the cropping image after loading - */ - public Rect initialCropWindowRectangle; - - /** - * the initial rotation to set on the cropping image after loading (0-360 degrees clockwise) - */ - public int initialRotation; - - /** - * if to allow (all) rotation during cropping (activity) - */ - public boolean allowRotation; - - /** - * if to allow (all) flipping during cropping (activity) - */ - public boolean allowFlipping; - - /** - * if to allow counter-clockwise rotation during cropping (activity) - */ - public boolean allowCounterRotation; - - /** - * the amount of degrees to rotate clockwise or counter-clockwise - */ - public int rotationDegrees; - - /** - * whether the image should be flipped horizontally - */ - public boolean flipHorizontally; - - /** - * whether the image should be flipped vertically - */ - public boolean flipVertically; - - /** - * optional, the text of the crop menu crop button - */ - public CharSequence cropMenuCropButtonTitle; - - /** - * optional image resource to be used for crop menu crop icon instead of text - */ - public int cropMenuCropButtonIcon; - - /** - * Init options with defaults. - */ - public CropImageOptions() { - - DisplayMetrics dm = Resources.getSystem().getDisplayMetrics(); - - cropShape = CropImageView.CropShape.RECTANGLE; - snapRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, dm); - touchRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, dm); - guidelines = CropImageView.Guidelines.ON_TOUCH; - scaleType = CropImageView.ScaleType.FIT_CENTER; - showCropOverlay = true; - showProgressBar = true; - autoZoomEnabled = true; - multiTouchEnabled = false; - maxZoom = 4; - initialCropWindowPaddingRatio = 0.1f; - - fixAspectRatio = false; - aspectRatioX = 1; - aspectRatioY = 1; - - borderLineThickness = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, dm); - borderLineColor = Color.argb(170, 255, 255, 255); - borderCornerThickness = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, dm); - borderCornerOffset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, dm); - borderCornerLength = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, dm); - borderCornerColor = Color.WHITE; - - guidelinesThickness = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, dm); - guidelinesColor = Color.argb(170, 255, 255, 255); - backgroundColor = Color.argb(119, 0, 0, 0); - - minCropWindowWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 42, dm); - minCropWindowHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 42, dm); - minCropResultWidth = 40; - minCropResultHeight = 40; - maxCropResultWidth = 99999; - maxCropResultHeight = 99999; - - activityTitle = ""; - activityMenuIconColor = 0; - - outputUri = Uri.EMPTY; - outputCompressFormat = Bitmap.CompressFormat.JPEG; - outputCompressQuality = 90; - outputRequestWidth = 0; - outputRequestHeight = 0; - outputRequestSizeOptions = CropImageView.RequestSizeOptions.NONE; - noOutputImage = false; - - initialCropWindowRectangle = null; - initialRotation = -1; - allowRotation = true; - allowFlipping = true; - allowCounterRotation = false; - rotationDegrees = 90; - flipHorizontally = false; - flipVertically = false; - cropMenuCropButtonTitle = null; - - cropMenuCropButtonIcon = 0; - } - - /** - * Create object from parcel. - */ - protected CropImageOptions(Parcel in) { - cropShape = CropImageView.CropShape.values()[in.readInt()]; - snapRadius = in.readFloat(); - touchRadius = in.readFloat(); - guidelines = CropImageView.Guidelines.values()[in.readInt()]; - scaleType = CropImageView.ScaleType.values()[in.readInt()]; - showCropOverlay = in.readByte() != 0; - showProgressBar = in.readByte() != 0; - autoZoomEnabled = in.readByte() != 0; - multiTouchEnabled = in.readByte() != 0; - maxZoom = in.readInt(); - initialCropWindowPaddingRatio = in.readFloat(); - fixAspectRatio = in.readByte() != 0; - aspectRatioX = in.readInt(); - aspectRatioY = in.readInt(); - borderLineThickness = in.readFloat(); - borderLineColor = in.readInt(); - borderCornerThickness = in.readFloat(); - borderCornerOffset = in.readFloat(); - borderCornerLength = in.readFloat(); - borderCornerColor = in.readInt(); - guidelinesThickness = in.readFloat(); - guidelinesColor = in.readInt(); - backgroundColor = in.readInt(); - minCropWindowWidth = in.readInt(); - minCropWindowHeight = in.readInt(); - minCropResultWidth = in.readInt(); - minCropResultHeight = in.readInt(); - maxCropResultWidth = in.readInt(); - maxCropResultHeight = in.readInt(); - activityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); - activityMenuIconColor = in.readInt(); - outputUri = in.readParcelable(Uri.class.getClassLoader()); - outputCompressFormat = Bitmap.CompressFormat.valueOf(in.readString()); - outputCompressQuality = in.readInt(); - outputRequestWidth = in.readInt(); - outputRequestHeight = in.readInt(); - outputRequestSizeOptions = CropImageView.RequestSizeOptions.values()[in.readInt()]; - noOutputImage = in.readByte() != 0; - initialCropWindowRectangle = in.readParcelable(Rect.class.getClassLoader()); - initialRotation = in.readInt(); - allowRotation = in.readByte() != 0; - allowFlipping = in.readByte() != 0; - allowCounterRotation = in.readByte() != 0; - rotationDegrees = in.readInt(); - flipHorizontally = in.readByte() != 0; - flipVertically = in.readByte() != 0; - cropMenuCropButtonTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); - cropMenuCropButtonIcon = in.readInt(); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(cropShape.ordinal()); - dest.writeFloat(snapRadius); - dest.writeFloat(touchRadius); - dest.writeInt(guidelines.ordinal()); - dest.writeInt(scaleType.ordinal()); - dest.writeByte((byte) (showCropOverlay ? 1 : 0)); - dest.writeByte((byte) (showProgressBar ? 1 : 0)); - dest.writeByte((byte) (autoZoomEnabled ? 1 : 0)); - dest.writeByte((byte) (multiTouchEnabled ? 1 : 0)); - dest.writeInt(maxZoom); - dest.writeFloat(initialCropWindowPaddingRatio); - dest.writeByte((byte) (fixAspectRatio ? 1 : 0)); - dest.writeInt(aspectRatioX); - dest.writeInt(aspectRatioY); - dest.writeFloat(borderLineThickness); - dest.writeInt(borderLineColor); - dest.writeFloat(borderCornerThickness); - dest.writeFloat(borderCornerOffset); - dest.writeFloat(borderCornerLength); - dest.writeInt(borderCornerColor); - dest.writeFloat(guidelinesThickness); - dest.writeInt(guidelinesColor); - dest.writeInt(backgroundColor); - dest.writeInt(minCropWindowWidth); - dest.writeInt(minCropWindowHeight); - dest.writeInt(minCropResultWidth); - dest.writeInt(minCropResultHeight); - dest.writeInt(maxCropResultWidth); - dest.writeInt(maxCropResultHeight); - TextUtils.writeToParcel(activityTitle, dest, flags); - dest.writeInt(activityMenuIconColor); - dest.writeParcelable(outputUri, flags); - dest.writeString(outputCompressFormat.name()); - dest.writeInt(outputCompressQuality); - dest.writeInt(outputRequestWidth); - dest.writeInt(outputRequestHeight); - dest.writeInt(outputRequestSizeOptions.ordinal()); - dest.writeInt(noOutputImage ? 1 : 0); - dest.writeParcelable(initialCropWindowRectangle, flags); - dest.writeInt(initialRotation); - dest.writeByte((byte) (allowRotation ? 1 : 0)); - dest.writeByte((byte) (allowFlipping ? 1 : 0)); - dest.writeByte((byte) (allowCounterRotation ? 1 : 0)); - dest.writeInt(rotationDegrees); - dest.writeByte((byte) (flipHorizontally ? 1 : 0)); - dest.writeByte((byte) (flipVertically ? 1 : 0)); - TextUtils.writeToParcel(cropMenuCropButtonTitle, dest, flags); - dest.writeInt(cropMenuCropButtonIcon); - } - - @Override - public int describeContents() { - return 0; - } - - /** - * Validate all the options are withing valid range. - * - * @throws IllegalArgumentException if any of the options is not valid - */ - public void validate() { - if (maxZoom < 0) { - throw new IllegalArgumentException("Cannot set max zoom to a number < 1"); - } - if (touchRadius < 0) { - throw new IllegalArgumentException("Cannot set touch radius value to a number <= 0 "); - } - if (initialCropWindowPaddingRatio < 0 || initialCropWindowPaddingRatio >= 0.5) { - throw new IllegalArgumentException( - "Cannot set initial crop window padding value to a number < 0 or >= 0.5"); - } - if (aspectRatioX <= 0) { - throw new IllegalArgumentException( - "Cannot set aspect ratio value to a number less than or equal to 0."); - } - if (aspectRatioY <= 0) { - throw new IllegalArgumentException( - "Cannot set aspect ratio value to a number less than or equal to 0."); - } - if (borderLineThickness < 0) { - throw new IllegalArgumentException( - "Cannot set line thickness value to a number less than 0."); - } - if (borderCornerThickness < 0) { - throw new IllegalArgumentException( - "Cannot set corner thickness value to a number less than 0."); - } - if (guidelinesThickness < 0) { - throw new IllegalArgumentException( - "Cannot set guidelines thickness value to a number less than 0."); - } - if (minCropWindowHeight < 0) { - throw new IllegalArgumentException( - "Cannot set min crop window height value to a number < 0 "); - } - if (minCropResultWidth < 0) { - throw new IllegalArgumentException("Cannot set min crop result width value to a number < 0 "); - } - if (minCropResultHeight < 0) { - throw new IllegalArgumentException( - "Cannot set min crop result height value to a number < 0 "); - } - if (maxCropResultWidth < minCropResultWidth) { - throw new IllegalArgumentException( - "Cannot set max crop result width to smaller value than min crop result width"); - } - if (maxCropResultHeight < minCropResultHeight) { - throw new IllegalArgumentException( - "Cannot set max crop result height to smaller value than min crop result height"); - } - if (outputRequestWidth < 0) { - throw new IllegalArgumentException("Cannot set request width value to a number < 0 "); - } - if (outputRequestHeight < 0) { - throw new IllegalArgumentException("Cannot set request height value to a number < 0 "); - } - if (rotationDegrees < 0 || rotationDegrees > 360) { - throw new IllegalArgumentException( - "Cannot set rotation degrees value to a number < 0 or > 360"); - } - } -} diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageView.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageView.java deleted file mode 100644 index 2e835b07..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropImageView.java +++ /dev/null @@ -1,2296 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth, -// inexhaustible as the great rivers. -// When they come to an end, -// they begin again, -// like the days and months; -// they die and are reborn, -// like the four seasons." -// -// - Sun Tsu, -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Matrix; -import android.graphics.Rect; -import android.graphics.RectF; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Parcelable; -import android.util.AttributeSet; -import android.util.Pair; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.ProgressBar; - -import androidx.exifinterface.media.ExifInterface; - -import java.lang.ref.WeakReference; -import java.util.UUID; - -/** - * Custom view that provides cropping capabilities to an image. - */ -public class CropImageView extends FrameLayout { - - // region: Fields and Consts - - /** - * Image view widget used to show the image for cropping. - */ - private final ImageView mImageView; - - /** - * Overlay over the image view to show cropping UI. - */ - private final CropOverlayView mCropOverlayView; - - /** - * The matrix used to transform the cropping image in the image view - */ - private final Matrix mImageMatrix = new Matrix(); - - /** - * Reusing matrix instance for reverse matrix calculations. - */ - private final Matrix mImageInverseMatrix = new Matrix(); - - /** - * Progress bar widget to show progress bar on async image loading and cropping. - */ - private final ProgressBar mProgressBar; - - /** - * Rectangle used in image matrix transformation calculation (reusing rect instance) - */ - private final float[] mImagePoints = new float[8]; - - /** - * Rectangle used in image matrix transformation for scale calculation (reusing rect instance) - */ - private final float[] mScaleImagePoints = new float[8]; - - /** - * Animation class to smooth animate zoom-in/out - */ - private CropImageAnimation mAnimation; - - private Bitmap mBitmap; - - /** - * The image rotation value used during loading of the image so we can reset to it - */ - private int mInitialDegreesRotated; - - /** - * How much the image is rotated from original clockwise - */ - private int mDegreesRotated; - - /** - * if the image flipped horizontally - */ - private boolean mFlipHorizontally; - - /** - * if the image flipped vertically - */ - private boolean mFlipVertically; - - private int mLayoutWidth; - - private int mLayoutHeight; - - private int mImageResource; - - /** - * The initial scale type of the image in the crop image view - */ - private ScaleType mScaleType; - - /** - * if to save bitmap on save instance state.
- * It is best to avoid it by using URI in setting image for cropping.
- * If false the bitmap is not saved and if restore is required to view will be empty, storing the - * bitmap requires saving it to file which can be expensive. default: false. - */ - private boolean mSaveBitmapToInstanceState = false; - - /** - * if to show crop overlay UI what contains the crop window UI surrounded by background over the - * cropping image.
- * default: true, may disable for animation or frame transition. - */ - private boolean mShowCropOverlay = true; - - /** - * if to show progress bar when image async loading/cropping is in progress.
- * default: true, disable to provide custom progress bar UI. - */ - private boolean mShowProgressBar = true; - - /** - * if auto-zoom functionality is enabled.
- * default: true. - */ - private boolean mAutoZoomEnabled = true; - - /** - * The max zoom allowed during cropping - */ - private int mMaxZoom; - - /** - * callback to be invoked when crop overlay is released. - */ - private OnSetCropOverlayReleasedListener mOnCropOverlayReleasedListener; - - /** - * callback to be invoked when crop overlay is moved. - */ - private OnSetCropOverlayMovedListener mOnSetCropOverlayMovedListener; - - /** - * callback to be invoked when crop window is changed. - */ - private OnSetCropWindowChangeListener mOnSetCropWindowChangeListener; - - /** - * callback to be invoked when image async loading is complete. - */ - private OnSetImageUriCompleteListener mOnSetImageUriCompleteListener; - - /** - * callback to be invoked when image async cropping is complete. - */ - private OnCropImageCompleteListener mOnCropImageCompleteListener; - - /** - * The URI that the image was loaded from (if loaded from URI) - */ - private Uri mLoadedImageUri; - - /** - * The sample size the image was loaded by if was loaded by URI - */ - private int mLoadedSampleSize = 1; - - /** - * The current zoom level to to scale the cropping image - */ - private float mZoom = 1; - - /** - * The X offset that the cropping image was translated after zooming - */ - private float mZoomOffsetX; - - /** - * The Y offset that the cropping image was translated after zooming - */ - private float mZoomOffsetY; - - /** - * Used to restore the cropping windows rectangle after state restore - */ - private RectF mRestoreCropWindowRect; - - /** - * Used to restore image rotation after state restore - */ - private int mRestoreDegreesRotated; - - /** - * Used to detect size change to handle auto-zoom using {@link #handleCropWindowChanged(boolean, - * boolean)} in {@link #layout(int, int, int, int)}. - */ - private boolean mSizeChanged; - - /** - * Temp URI used to save bitmap image to disk to preserve for instance state in case cropped was - * set with bitmap - */ - private Uri mSaveInstanceStateBitmapUri; - - /** - * Task used to load bitmap async from UI thread - */ - private WeakReference mBitmapLoadingWorkerTask; - - /** - * Task used to crop bitmap async from UI thread - */ - private WeakReference mBitmapCroppingWorkerTask; - // endregion - - public CropImageView(Context context) { - this(context, null); - } - - public CropImageView(Context context, AttributeSet attrs) { - super(context, attrs); - - CropImageOptions options = null; - Intent intent = context instanceof Activity ? ((Activity) context).getIntent() : null; - if (intent != null) { - Bundle bundle = intent.getBundleExtra(CropImage.CROP_IMAGE_EXTRA_BUNDLE); - if (bundle != null) { - options = bundle.getParcelable(CropImage.CROP_IMAGE_EXTRA_OPTIONS); - } - } - - if (options == null) { - - options = new CropImageOptions(); - - if (attrs != null) { - TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CropImageView, 0, 0); - try { - options.fixAspectRatio = - ta.getBoolean(R.styleable.CropImageView_cropFixAspectRatio, options.fixAspectRatio); - options.aspectRatioX = - ta.getInteger(R.styleable.CropImageView_cropAspectRatioX, options.aspectRatioX); - options.aspectRatioY = - ta.getInteger(R.styleable.CropImageView_cropAspectRatioY, options.aspectRatioY); - options.scaleType = - ScaleType.values()[ - ta.getInt(R.styleable.CropImageView_cropScaleType, options.scaleType.ordinal())]; - options.autoZoomEnabled = - ta.getBoolean(R.styleable.CropImageView_cropAutoZoomEnabled, options.autoZoomEnabled); - options.multiTouchEnabled = - ta.getBoolean( - R.styleable.CropImageView_cropMultiTouchEnabled, options.multiTouchEnabled); - options.maxZoom = ta.getInteger(R.styleable.CropImageView_cropMaxZoom, options.maxZoom); - options.cropShape = - CropShape.values()[ - ta.getInt(R.styleable.CropImageView_cropShape, options.cropShape.ordinal())]; - options.guidelines = - Guidelines.values()[ - ta.getInt( - R.styleable.CropImageView_cropGuidelines, options.guidelines.ordinal())]; - options.snapRadius = - ta.getDimension(R.styleable.CropImageView_cropSnapRadius, options.snapRadius); - options.touchRadius = - ta.getDimension(R.styleable.CropImageView_cropTouchRadius, options.touchRadius); - options.initialCropWindowPaddingRatio = - ta.getFloat( - R.styleable.CropImageView_cropInitialCropWindowPaddingRatio, - options.initialCropWindowPaddingRatio); - options.borderLineThickness = - ta.getDimension( - R.styleable.CropImageView_cropBorderLineThickness, options.borderLineThickness); - options.borderLineColor = - ta.getInteger(R.styleable.CropImageView_cropBorderLineColor, options.borderLineColor); - options.borderCornerThickness = - ta.getDimension( - R.styleable.CropImageView_cropBorderCornerThickness, - options.borderCornerThickness); - options.borderCornerOffset = - ta.getDimension( - R.styleable.CropImageView_cropBorderCornerOffset, options.borderCornerOffset); - options.borderCornerLength = - ta.getDimension( - R.styleable.CropImageView_cropBorderCornerLength, options.borderCornerLength); - options.borderCornerColor = - ta.getInteger( - R.styleable.CropImageView_cropBorderCornerColor, options.borderCornerColor); - options.guidelinesThickness = - ta.getDimension( - R.styleable.CropImageView_cropGuidelinesThickness, options.guidelinesThickness); - options.guidelinesColor = - ta.getInteger(R.styleable.CropImageView_cropGuidelinesColor, options.guidelinesColor); - options.backgroundColor = - ta.getInteger(R.styleable.CropImageView_cropBackgroundColor, options.backgroundColor); - options.showCropOverlay = - ta.getBoolean(R.styleable.CropImageView_cropShowCropOverlay, mShowCropOverlay); - options.showProgressBar = - ta.getBoolean(R.styleable.CropImageView_cropShowProgressBar, mShowProgressBar); - options.borderCornerThickness = - ta.getDimension( - R.styleable.CropImageView_cropBorderCornerThickness, - options.borderCornerThickness); - options.minCropWindowWidth = - (int) - ta.getDimension( - R.styleable.CropImageView_cropMinCropWindowWidth, options.minCropWindowWidth); - options.minCropWindowHeight = - (int) - ta.getDimension( - R.styleable.CropImageView_cropMinCropWindowHeight, - options.minCropWindowHeight); - options.minCropResultWidth = - (int) - ta.getFloat( - R.styleable.CropImageView_cropMinCropResultWidthPX, - options.minCropResultWidth); - options.minCropResultHeight = - (int) - ta.getFloat( - R.styleable.CropImageView_cropMinCropResultHeightPX, - options.minCropResultHeight); - options.maxCropResultWidth = - (int) - ta.getFloat( - R.styleable.CropImageView_cropMaxCropResultWidthPX, - options.maxCropResultWidth); - options.maxCropResultHeight = - (int) - ta.getFloat( - R.styleable.CropImageView_cropMaxCropResultHeightPX, - options.maxCropResultHeight); - options.flipHorizontally = - ta.getBoolean( - R.styleable.CropImageView_cropFlipHorizontally, options.flipHorizontally); - options.flipVertically = - ta.getBoolean(R.styleable.CropImageView_cropFlipHorizontally, options.flipVertically); - - mSaveBitmapToInstanceState = - ta.getBoolean( - R.styleable.CropImageView_cropSaveBitmapToInstanceState, - mSaveBitmapToInstanceState); - - // if aspect ratio is set then set fixed to true - if (ta.hasValue(R.styleable.CropImageView_cropAspectRatioX) - && ta.hasValue(R.styleable.CropImageView_cropAspectRatioX) - && !ta.hasValue(R.styleable.CropImageView_cropFixAspectRatio)) { - options.fixAspectRatio = true; - } - } finally { - ta.recycle(); - } - } - } - - options.validate(); - - mScaleType = options.scaleType; - mAutoZoomEnabled = options.autoZoomEnabled; - mMaxZoom = options.maxZoom; - mShowCropOverlay = options.showCropOverlay; - mShowProgressBar = options.showProgressBar; - mFlipHorizontally = options.flipHorizontally; - mFlipVertically = options.flipVertically; - - LayoutInflater inflater = LayoutInflater.from(context); - View v = inflater.inflate(R.layout.crop_image_view, this, true); - - mImageView = v.findViewById(R.id.ImageView_image); - mImageView.setScaleType(ImageView.ScaleType.MATRIX); - - mCropOverlayView = v.findViewById(R.id.CropOverlayView); - mCropOverlayView.setCropWindowChangeListener( - new CropOverlayView.CropWindowChangeListener() { - @Override - public void onCropWindowChanged(boolean inProgress) { - handleCropWindowChanged(inProgress, true); - OnSetCropOverlayReleasedListener listener = mOnCropOverlayReleasedListener; - if (listener != null && !inProgress) { - listener.onCropOverlayReleased(getCropRect()); - } - OnSetCropOverlayMovedListener movedListener = mOnSetCropOverlayMovedListener; - if (movedListener != null && inProgress) { - movedListener.onCropOverlayMoved(getCropRect()); - } - } - }); - mCropOverlayView.setInitialAttributeValues(options); - - mProgressBar = v.findViewById(R.id.CropProgressBar); - setProgressBarVisibility(); - } - - /** - * Determines the specs for the onMeasure function. Calculates the width or height depending on - * the mode. - * - * @param measureSpecMode The mode of the measured width or height. - * @param measureSpecSize The size of the measured width or height. - * @param desiredSize The desired size of the measured width or height. - * @return The final size of the width or height. - */ - private static int getOnMeasureSpec(int measureSpecMode, int measureSpecSize, int desiredSize) { - - // Measure Width - int spec; - if (measureSpecMode == MeasureSpec.EXACTLY) { - // Must be this size - spec = measureSpecSize; - } else if (measureSpecMode == MeasureSpec.AT_MOST) { - // Can't be bigger than...; match_parent value - spec = Math.min(desiredSize, measureSpecSize); - } else { - // Be whatever you want; wrap_content - spec = desiredSize; - } - - return spec; - } - - /** - * Get the scale type of the image in the crop view. - */ - public ScaleType getScaleType() { - return mScaleType; - } - - /** - * Set the scale type of the image in the crop view - */ - public void setScaleType(ScaleType scaleType) { - if (scaleType != mScaleType) { - mScaleType = scaleType; - mZoom = 1; - mZoomOffsetX = mZoomOffsetY = 0; - mCropOverlayView.resetCropOverlayView(); - requestLayout(); - } - } - - /** - * The shape of the cropping area - rectangle/circular. - */ - public CropShape getCropShape() { - return mCropOverlayView.getCropShape(); - } - - /** - * The shape of the cropping area - rectangle/circular.
- * To set square/circle crop shape set aspect ratio to 1:1. - */ - public void setCropShape(CropShape cropShape) { - mCropOverlayView.setCropShape(cropShape); - } - - /** - * if auto-zoom functionality is enabled. default: true. - */ - public boolean isAutoZoomEnabled() { - return mAutoZoomEnabled; - } - - /** - * Set auto-zoom functionality to enabled/disabled. - */ - public void setAutoZoomEnabled(boolean autoZoomEnabled) { - if (mAutoZoomEnabled != autoZoomEnabled) { - mAutoZoomEnabled = autoZoomEnabled; - handleCropWindowChanged(false, false); - mCropOverlayView.invalidate(); - } - } - - /** - * Set multi touch functionality to enabled/disabled. - */ - public void setMultiTouchEnabled(boolean multiTouchEnabled) { - if (mCropOverlayView.setMultiTouchEnabled(multiTouchEnabled)) { - handleCropWindowChanged(false, false); - mCropOverlayView.invalidate(); - } - } - - /** - * The max zoom allowed during cropping. - */ - public int getMaxZoom() { - return mMaxZoom; - } - - /** - * The max zoom allowed during cropping. - */ - public void setMaxZoom(int maxZoom) { - if (mMaxZoom != maxZoom && maxZoom > 0) { - mMaxZoom = maxZoom; - handleCropWindowChanged(false, false); - mCropOverlayView.invalidate(); - } - } - - /** - * the min size the resulting cropping image is allowed to be, affects the cropping window limits - * (in pixels).
- */ - public void setMinCropResultSize(int minCropResultWidth, int minCropResultHeight) { - mCropOverlayView.setMinCropResultSize(minCropResultWidth, minCropResultHeight); - } - - /** - * the max size the resulting cropping image is allowed to be, affects the cropping window limits - * (in pixels).
- */ - public void setMaxCropResultSize(int maxCropResultWidth, int maxCropResultHeight) { - mCropOverlayView.setMaxCropResultSize(maxCropResultWidth, maxCropResultHeight); - } - - /** - * Get the amount of degrees the cropping image is rotated cloackwise.
- * - * @return 0-360 - */ - public int getRotatedDegrees() { - return mDegreesRotated; - } - - /** - * Set the amount of degrees the cropping image is rotated cloackwise.
- * - * @param degrees 0-360 - */ - public void setRotatedDegrees(int degrees) { - if (mDegreesRotated != degrees) { - rotateImage(degrees - mDegreesRotated); - } - } - - /** - * whether the aspect ratio is fixed or not; true fixes the aspect ratio, while false allows it to - * be changed. - */ - public boolean isFixAspectRatio() { - return mCropOverlayView.isFixAspectRatio(); - } - - /** - * Sets whether the aspect ratio is fixed or not; true fixes the aspect ratio, while false allows - * it to be changed. - */ - public void setFixedAspectRatio(boolean fixAspectRatio) { - mCropOverlayView.setFixedAspectRatio(fixAspectRatio); - } - - /** - * whether the image should be flipped horizontally - */ - public boolean isFlippedHorizontally() { - return mFlipHorizontally; - } - - /** - * Sets whether the image should be flipped horizontally - */ - public void setFlippedHorizontally(boolean flipHorizontally) { - if (mFlipHorizontally != flipHorizontally) { - mFlipHorizontally = flipHorizontally; - applyImageMatrix(getWidth(), getHeight(), true, false); - } - } - - /** - * whether the image should be flipped vertically - */ - public boolean isFlippedVertically() { - return mFlipVertically; - } - - /** - * Sets whether the image should be flipped vertically - */ - public void setFlippedVertically(boolean flipVertically) { - if (mFlipVertically != flipVertically) { - mFlipVertically = flipVertically; - applyImageMatrix(getWidth(), getHeight(), true, false); - } - } - - /** - * Get the current guidelines option set. - */ - public Guidelines getGuidelines() { - return mCropOverlayView.getGuidelines(); - } - - /** - * Sets the guidelines for the CropOverlayView to be either on, off, or to show when resizing the - * application. - */ - public void setGuidelines(Guidelines guidelines) { - mCropOverlayView.setGuidelines(guidelines); - } - - /** - * both the X and Y values of the aspectRatio. - */ - public Pair getAspectRatio() { - return new Pair<>(mCropOverlayView.getAspectRatioX(), mCropOverlayView.getAspectRatioY()); - } - - /** - * Sets the both the X and Y values of the aspectRatio.
- * Sets fixed aspect ratio to TRUE. - * - * @param aspectRatioX int that specifies the new X value of the aspect ratio - * @param aspectRatioY int that specifies the new Y value of the aspect ratio - */ - public void setAspectRatio(int aspectRatioX, int aspectRatioY) { - mCropOverlayView.setAspectRatioX(aspectRatioX); - mCropOverlayView.setAspectRatioY(aspectRatioY); - setFixedAspectRatio(true); - } - - /** - * Clears set aspect ratio values and sets fixed aspect ratio to FALSE. - */ - public void clearAspectRatio() { - mCropOverlayView.setAspectRatioX(1); - mCropOverlayView.setAspectRatioY(1); - setFixedAspectRatio(false); - } - - /** - * An edge of the crop window will snap to the corresponding edge of a specified bounding box when - * the crop window edge is less than or equal to this distance (in pixels) away from the bounding - * box edge. (default: 3dp) - */ - public void setSnapRadius(float snapRadius) { - if (snapRadius >= 0) { - mCropOverlayView.setSnapRadius(snapRadius); - } - } - - /** - * if to show progress bar when image async loading/cropping is in progress.
- * default: true, disable to provide custom progress bar UI. - */ - public boolean isShowProgressBar() { - return mShowProgressBar; - } - - /** - * if to show progress bar when image async loading/cropping is in progress.
- * default: true, disable to provide custom progress bar UI. - */ - public void setShowProgressBar(boolean showProgressBar) { - if (mShowProgressBar != showProgressBar) { - mShowProgressBar = showProgressBar; - setProgressBarVisibility(); - } - } - - /** - * if to show crop overlay UI what contains the crop window UI surrounded by background over the - * cropping image.
- * default: true, may disable for animation or frame transition. - */ - public boolean isShowCropOverlay() { - return mShowCropOverlay; - } - - /** - * if to show crop overlay UI what contains the crop window UI surrounded by background over the - * cropping image.
- * default: true, may disable for animation or frame transition. - */ - public void setShowCropOverlay(boolean showCropOverlay) { - if (mShowCropOverlay != showCropOverlay) { - mShowCropOverlay = showCropOverlay; - setCropOverlayVisibility(); - } - } - - /** - * if to save bitmap on save instance state.
- * It is best to avoid it by using URI in setting image for cropping.
- * If false the bitmap is not saved and if restore is required to view will be empty, storing the - * bitmap requires saving it to file which can be expensive. default: false. - */ - public boolean isSaveBitmapToInstanceState() { - return mSaveBitmapToInstanceState; - } - - /** - * if to save bitmap on save instance state.
- * It is best to avoid it by using URI in setting image for cropping.
- * If false the bitmap is not saved and if restore is required to view will be empty, storing the - * bitmap requires saving it to file which can be expensive. default: false. - */ - public void setSaveBitmapToInstanceState(boolean saveBitmapToInstanceState) { - mSaveBitmapToInstanceState = saveBitmapToInstanceState; - } - - /** - * Returns the integer of the imageResource - */ - public int getImageResource() { - return mImageResource; - } - - /** - * Sets a Drawable as the content of the CropImageView. - * - * @param resId the drawable resource ID to set - */ - public void setImageResource(int resId) { - if (resId != 0) { - mCropOverlayView.setInitialCropWindowRect(null); - Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId); - setBitmap(bitmap, resId, null, 1, 0); - } - } - - /** - * Get the URI of an image that was set by URI, null otherwise. - */ - public Uri getImageUri() { - return mLoadedImageUri; - } - - /** - * Gets the source Bitmap's dimensions. This represents the largest possible crop rectangle. - * - * @return a Rect instance dimensions of the source Bitmap - */ - public Rect getWholeImageRect() { - int loadedSampleSize = mLoadedSampleSize; - Bitmap bitmap = mBitmap; - if (bitmap == null) { - return null; - } - - int orgWidth = bitmap.getWidth() * loadedSampleSize; - int orgHeight = bitmap.getHeight() * loadedSampleSize; - return new Rect(0, 0, orgWidth, orgHeight); - } - - /** - * Gets the crop window's position relative to the source Bitmap (not the image displayed in the - * CropImageView) using the original image rotation. - * - * @return a Rect instance containing cropped area boundaries of the source Bitmap - */ - public Rect getCropRect() { - int loadedSampleSize = mLoadedSampleSize; - Bitmap bitmap = mBitmap; - if (bitmap == null) { - return null; - } - - // get the points of the crop rectangle adjusted to source bitmap - float[] points = getCropPoints(); - - int orgWidth = bitmap.getWidth() * loadedSampleSize; - int orgHeight = bitmap.getHeight() * loadedSampleSize; - - // get the rectangle for the points (it may be larger than original if rotation is not stright) - return BitmapUtils.getRectFromPoints( - points, - orgWidth, - orgHeight, - mCropOverlayView.isFixAspectRatio(), - mCropOverlayView.getAspectRatioX(), - mCropOverlayView.getAspectRatioY()); - } - - /** - * Set the crop window position and size to the given rectangle.
- * Image to crop must be first set before invoking this, for async - after complete callback. - * - * @param rect window rectangle (position and size) relative to source bitmap - */ - public void setCropRect(Rect rect) { - mCropOverlayView.setInitialCropWindowRect(rect); - } - - /** - * Gets the crop window's position relative to the parent's view at screen. - * - * @return a Rect instance containing cropped area boundaries of the source Bitmap - */ - public RectF getCropWindowRect() { - if (mCropOverlayView == null) { - return null; - } - return mCropOverlayView.getCropWindowRect(); - } - - /** - * Gets the 4 points of crop window's position relative to the source Bitmap (not the image - * displayed in the CropImageView) using the original image rotation.
- * Note: the 4 points may not be a rectangle if the image was rotates to NOT stright angle (!= - * 90/180/270). - * - * @return 4 points (x0,y0,x1,y1,x2,y2,x3,y3) of cropped area boundaries - */ - public float[] getCropPoints() { - - // Get crop window position relative to the displayed image. - RectF cropWindowRect = mCropOverlayView.getCropWindowRect(); - - float[] points = - new float[]{ - cropWindowRect.left, - cropWindowRect.top, - cropWindowRect.right, - cropWindowRect.top, - cropWindowRect.right, - cropWindowRect.bottom, - cropWindowRect.left, - cropWindowRect.bottom - }; - - mImageMatrix.invert(mImageInverseMatrix); - mImageInverseMatrix.mapPoints(points); - - for (int i = 0; i < points.length; i++) { - points[i] *= mLoadedSampleSize; - } - - return points; - } - - /** - * Reset crop window to initial rectangle. - */ - public void resetCropRect() { - mZoom = 1; - mZoomOffsetX = 0; - mZoomOffsetY = 0; - mDegreesRotated = mInitialDegreesRotated; - mFlipHorizontally = false; - mFlipVertically = false; - applyImageMatrix(getWidth(), getHeight(), false, false); - mCropOverlayView.resetCropWindowRect(); - } - - /** - * Gets the cropped image based on the current crop window. - * - * @return a new Bitmap representing the cropped image - */ - public Bitmap getCroppedImage() { - return getCroppedImage(0, 0, RequestSizeOptions.NONE); - } - - /** - * Gets the cropped image based on the current crop window.
- * Uses {@link RequestSizeOptions#RESIZE_INSIDE} option. - * - * @param reqWidth the width to resize the cropped image to - * @param reqHeight the height to resize the cropped image to - * @return a new Bitmap representing the cropped image - */ - public Bitmap getCroppedImage(int reqWidth, int reqHeight) { - return getCroppedImage(reqWidth, reqHeight, RequestSizeOptions.RESIZE_INSIDE); - } - - /** - * Gets the cropped image based on the current crop window.
- * - * @param reqWidth the width to resize the cropped image to (see options) - * @param reqHeight the height to resize the cropped image to (see options) - * @param options the resize method to use, see its documentation - * @return a new Bitmap representing the cropped image - */ - public Bitmap getCroppedImage(int reqWidth, int reqHeight, RequestSizeOptions options) { - Bitmap croppedBitmap = null; - if (mBitmap != null) { - mImageView.clearAnimation(); - - reqWidth = options != RequestSizeOptions.NONE ? reqWidth : 0; - reqHeight = options != RequestSizeOptions.NONE ? reqHeight : 0; - - if (mLoadedImageUri != null - && (mLoadedSampleSize > 1 || options == RequestSizeOptions.SAMPLING)) { - int orgWidth = mBitmap.getWidth() * mLoadedSampleSize; - int orgHeight = mBitmap.getHeight() * mLoadedSampleSize; - BitmapUtils.BitmapSampled bitmapSampled = - BitmapUtils.cropBitmap( - getContext(), - mLoadedImageUri, - getCropPoints(), - mDegreesRotated, - orgWidth, - orgHeight, - mCropOverlayView.isFixAspectRatio(), - mCropOverlayView.getAspectRatioX(), - mCropOverlayView.getAspectRatioY(), - reqWidth, - reqHeight, - mFlipHorizontally, - mFlipVertically); - croppedBitmap = bitmapSampled.bitmap; - } else { - croppedBitmap = - BitmapUtils.cropBitmapObjectHandleOOM( - mBitmap, - getCropPoints(), - mDegreesRotated, - mCropOverlayView.isFixAspectRatio(), - mCropOverlayView.getAspectRatioX(), - mCropOverlayView.getAspectRatioY(), - mFlipHorizontally, - mFlipVertically) - .bitmap; - } - - croppedBitmap = BitmapUtils.resizeBitmap(croppedBitmap, reqWidth, reqHeight, options); - } - - return croppedBitmap; - } - - /** - * Gets the cropped image based on the current crop window.
- * The result will be invoked to listener set by {@link - * #setOnCropImageCompleteListener(OnCropImageCompleteListener)}. - */ - public void getCroppedImageAsync() { - getCroppedImageAsync(0, 0, RequestSizeOptions.NONE); - } - - /** - * Gets the cropped image based on the current crop window.
- * Uses {@link RequestSizeOptions#RESIZE_INSIDE} option.
- * The result will be invoked to listener set by {@link - * #setOnCropImageCompleteListener(OnCropImageCompleteListener)}. - * - * @param reqWidth the width to resize the cropped image to - * @param reqHeight the height to resize the cropped image to - */ - public void getCroppedImageAsync(int reqWidth, int reqHeight) { - getCroppedImageAsync(reqWidth, reqHeight, RequestSizeOptions.RESIZE_INSIDE); - } - - /** - * Gets the cropped image based on the current crop window.
- * The result will be invoked to listener set by {@link - * #setOnCropImageCompleteListener(OnCropImageCompleteListener)}. - * - * @param reqWidth the width to resize the cropped image to (see options) - * @param reqHeight the height to resize the cropped image to (see options) - * @param options the resize method to use, see its documentation - */ - public void getCroppedImageAsync(int reqWidth, int reqHeight, RequestSizeOptions options) { - if (mOnCropImageCompleteListener == null) { - throw new IllegalArgumentException("mOnCropImageCompleteListener is not set"); - } - startCropWorkerTask(reqWidth, reqHeight, options, null, null, 0); - } - - /** - * Save the cropped image based on the current crop window to the given uri.
- * Uses JPEG image compression with 90 compression quality.
- * The result will be invoked to listener set by {@link - * #setOnCropImageCompleteListener(OnCropImageCompleteListener)}. - * - * @param saveUri the Android Uri to save the cropped image to - */ - public void saveCroppedImageAsync(Uri saveUri) { - saveCroppedImageAsync(saveUri, Bitmap.CompressFormat.JPEG, 90, 0, 0, RequestSizeOptions.NONE); - } - - /** - * Save the cropped image based on the current crop window to the given uri.
- * The result will be invoked to listener set by {@link - * #setOnCropImageCompleteListener(OnCropImageCompleteListener)}. - * - * @param saveUri the Android Uri to save the cropped image to - * @param saveCompressFormat the compression format to use when writing the image - * @param saveCompressQuality the quality (if applicable) to use when writing the image (0 - 100) - */ - public void saveCroppedImageAsync( - Uri saveUri, Bitmap.CompressFormat saveCompressFormat, int saveCompressQuality) { - saveCroppedImageAsync( - saveUri, saveCompressFormat, saveCompressQuality, 0, 0, RequestSizeOptions.NONE); - } - - /** - * Save the cropped image based on the current crop window to the given uri.
- * Uses {@link RequestSizeOptions#RESIZE_INSIDE} option.
- * The result will be invoked to listener set by {@link - * #setOnCropImageCompleteListener(OnCropImageCompleteListener)}. - * - * @param saveUri the Android Uri to save the cropped image to - * @param saveCompressFormat the compression format to use when writing the image - * @param saveCompressQuality the quality (if applicable) to use when writing the image (0 - 100) - * @param reqWidth the width to resize the cropped image to - * @param reqHeight the height to resize the cropped image to - */ - public void saveCroppedImageAsync( - Uri saveUri, - Bitmap.CompressFormat saveCompressFormat, - int saveCompressQuality, - int reqWidth, - int reqHeight) { - saveCroppedImageAsync( - saveUri, - saveCompressFormat, - saveCompressQuality, - reqWidth, - reqHeight, - RequestSizeOptions.RESIZE_INSIDE); - } - - /** - * Save the cropped image based on the current crop window to the given uri.
- * The result will be invoked to listener set by {@link - * #setOnCropImageCompleteListener(OnCropImageCompleteListener)}. - * - * @param saveUri the Android Uri to save the cropped image to - * @param saveCompressFormat the compression format to use when writing the image - * @param saveCompressQuality the quality (if applicable) to use when writing the image (0 - 100) - * @param reqWidth the width to resize the cropped image to (see options) - * @param reqHeight the height to resize the cropped image to (see options) - * @param options the resize method to use, see its documentation - */ - public void saveCroppedImageAsync( - Uri saveUri, - Bitmap.CompressFormat saveCompressFormat, - int saveCompressQuality, - int reqWidth, - int reqHeight, - RequestSizeOptions options) { - if (mOnCropImageCompleteListener == null) { - throw new IllegalArgumentException("mOnCropImageCompleteListener is not set"); - } - startCropWorkerTask( - reqWidth, reqHeight, options, saveUri, saveCompressFormat, saveCompressQuality); - } - - /** - * Set the callback t - */ - public void setOnSetCropOverlayReleasedListener(OnSetCropOverlayReleasedListener listener) { - mOnCropOverlayReleasedListener = listener; - } - - /** - * Set the callback when the cropping is moved - */ - public void setOnSetCropOverlayMovedListener(OnSetCropOverlayMovedListener listener) { - mOnSetCropOverlayMovedListener = listener; - } - - /** - * Set the callback when the crop window is changed - */ - public void setOnCropWindowChangedListener(OnSetCropWindowChangeListener listener) { - mOnSetCropWindowChangeListener = listener; - } - - /** - * Set the callback to be invoked when image async loading ({@link #setImageUriAsync(Uri)}) is - * complete (successful or failed). - */ - public void setOnSetImageUriCompleteListener(OnSetImageUriCompleteListener listener) { - mOnSetImageUriCompleteListener = listener; - } - - /** - * Set the callback to be invoked when image async cropping image ({@link #getCroppedImageAsync()} - * or {@link #saveCroppedImageAsync(Uri)}) is complete (successful or failed). - */ - public void setOnCropImageCompleteListener(OnCropImageCompleteListener listener) { - mOnCropImageCompleteListener = listener; - } - - /** - * Sets a Bitmap as the content of the CropImageView. - * - * @param bitmap the Bitmap to set - */ - public void setImageBitmap(Bitmap bitmap) { - mCropOverlayView.setInitialCropWindowRect(null); - setBitmap(bitmap, 0, null, 1, 0); - } - - /** - * Sets a Bitmap and initializes the image rotation according to the EXIT data.
- *
- * The EXIF can be retrieved by doing the following: - * ExifInterface exif = new ExifInterface(path); - * - * @param bitmap the original bitmap to set; if null, this - * @param exif the EXIF information about this bitmap; may be null - */ - public void setImageBitmap(Bitmap bitmap, ExifInterface exif) { - Bitmap setBitmap; - int degreesRotated = 0; - if (bitmap != null && exif != null) { - BitmapUtils.RotateBitmapResult result = BitmapUtils.rotateBitmapByExif(bitmap, exif); - setBitmap = result.bitmap; - degreesRotated = result.degrees; - mInitialDegreesRotated = result.degrees; - } else { - setBitmap = bitmap; - } - mCropOverlayView.setInitialCropWindowRect(null); - setBitmap(setBitmap, 0, null, 1, degreesRotated); - } - - /** - * Sets a bitmap loaded from the given Android URI as the content of the CropImageView.
- * Can be used with URI from gallery or camera source.
- * Will rotate the image by exif data.
- * - * @param uri the URI to load the image from - */ - public void setImageUriAsync(Uri uri) { - if (uri != null) { - BitmapLoadingWorkerTask currentTask = - mBitmapLoadingWorkerTask != null ? mBitmapLoadingWorkerTask.get() : null; - if (currentTask != null) { - // cancel previous loading (no check if the same URI because camera URI can be the same for - // different images) - currentTask.cancel(true); - } - - // either no existing task is working or we canceled it, need to load new URI - clearImageInt(); - mRestoreCropWindowRect = null; - mRestoreDegreesRotated = 0; - mCropOverlayView.setInitialCropWindowRect(null); - mBitmapLoadingWorkerTask = new WeakReference<>(new BitmapLoadingWorkerTask(this, uri)); - mBitmapLoadingWorkerTask.get().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - setProgressBarVisibility(); - } - } - - /** - * Clear the current image set for cropping. - */ - public void clearImage() { - clearImageInt(); - mCropOverlayView.setInitialCropWindowRect(null); - } - - /** - * Rotates image by the specified number of degrees clockwise.
- * Negative values represent counter-clockwise rotations. - * - * @param degrees Integer specifying the number of degrees to rotate. - */ - public void rotateImage(int degrees) { - if (mBitmap != null) { - // Force degrees to be a non-zero value between 0 and 360 (inclusive) - if (degrees < 0) { - degrees = (degrees % 360) + 360; - } else { - degrees = degrees % 360; - } - - boolean flipAxes = - !mCropOverlayView.isFixAspectRatio() - && ((degrees > 45 && degrees < 135) || (degrees > 215 && degrees < 305)); - BitmapUtils.RECT.set(mCropOverlayView.getCropWindowRect()); - float halfWidth = (flipAxes ? BitmapUtils.RECT.height() : BitmapUtils.RECT.width()) / 2f; - float halfHeight = (flipAxes ? BitmapUtils.RECT.width() : BitmapUtils.RECT.height()) / 2f; - if (flipAxes) { - boolean isFlippedHorizontally = mFlipHorizontally; - mFlipHorizontally = mFlipVertically; - mFlipVertically = isFlippedHorizontally; - } - - mImageMatrix.invert(mImageInverseMatrix); - - BitmapUtils.POINTS[0] = BitmapUtils.RECT.centerX(); - BitmapUtils.POINTS[1] = BitmapUtils.RECT.centerY(); - BitmapUtils.POINTS[2] = 0; - BitmapUtils.POINTS[3] = 0; - BitmapUtils.POINTS[4] = 1; - BitmapUtils.POINTS[5] = 0; - mImageInverseMatrix.mapPoints(BitmapUtils.POINTS); - - // This is valid because degrees is not negative. - mDegreesRotated = (mDegreesRotated + degrees) % 360; - - applyImageMatrix(getWidth(), getHeight(), true, false); - - // adjust the zoom so the crop window size remains the same even after image scale change - mImageMatrix.mapPoints(BitmapUtils.POINTS2, BitmapUtils.POINTS); - mZoom /= - Math.sqrt( - Math.pow(BitmapUtils.POINTS2[4] - BitmapUtils.POINTS2[2], 2) - + Math.pow(BitmapUtils.POINTS2[5] - BitmapUtils.POINTS2[3], 2)); - mZoom = Math.max(mZoom, 1); - - applyImageMatrix(getWidth(), getHeight(), true, false); - - mImageMatrix.mapPoints(BitmapUtils.POINTS2, BitmapUtils.POINTS); - - // adjust the width/height by the changes in scaling to the image - double change = - Math.sqrt( - Math.pow(BitmapUtils.POINTS2[4] - BitmapUtils.POINTS2[2], 2) - + Math.pow(BitmapUtils.POINTS2[5] - BitmapUtils.POINTS2[3], 2)); - halfWidth *= change; - halfHeight *= change; - - // calculate the new crop window rectangle to center in the same location and have proper - // width/height - BitmapUtils.RECT.set( - BitmapUtils.POINTS2[0] - halfWidth, - BitmapUtils.POINTS2[1] - halfHeight, - BitmapUtils.POINTS2[0] + halfWidth, - BitmapUtils.POINTS2[1] + halfHeight); - - mCropOverlayView.resetCropOverlayView(); - mCropOverlayView.setCropWindowRect(BitmapUtils.RECT); - applyImageMatrix(getWidth(), getHeight(), true, false); - handleCropWindowChanged(false, false); - - // make sure the crop window rectangle is within the cropping image bounds after all the - // changes - mCropOverlayView.fixCurrentCropWindowRect(); - } - } - - /** - * Flips the image horizontally. - */ - public void flipImageHorizontally() { - mFlipHorizontally = !mFlipHorizontally; - applyImageMatrix(getWidth(), getHeight(), true, false); - } - - // region: Private methods - - /** - * Flips the image vertically. - */ - public void flipImageVertically() { - mFlipVertically = !mFlipVertically; - applyImageMatrix(getWidth(), getHeight(), true, false); - } - - /** - * On complete of the async bitmap loading by {@link #setImageUriAsync(Uri)} set the result to the - * widget if still relevant and call listener if set. - * - * @param result the result of bitmap loading - */ - void onSetImageUriAsyncComplete(BitmapLoadingWorkerTask.Result result) { - - mBitmapLoadingWorkerTask = null; - setProgressBarVisibility(); - - if (result.error == null) { - mInitialDegreesRotated = result.degreesRotated; - setBitmap(result.bitmap, 0, result.uri, result.loadSampleSize, result.degreesRotated); - } - - OnSetImageUriCompleteListener listener = mOnSetImageUriCompleteListener; - if (listener != null) { - listener.onSetImageUriComplete(this, result.uri, result.error); - } - } - - /** - * On complete of the async bitmap cropping by {@link #getCroppedImageAsync()} call listener if - * set. - * - * @param result the result of bitmap cropping - */ - void onImageCroppingAsyncComplete(BitmapCroppingWorkerTask.Result result) { - - mBitmapCroppingWorkerTask = null; - setProgressBarVisibility(); - - OnCropImageCompleteListener listener = mOnCropImageCompleteListener; - if (listener != null) { - CropResult cropResult = - new CropResult( - mBitmap, - mLoadedImageUri, - result.bitmap, - result.uri, - result.error, - getCropPoints(), - getCropRect(), - getWholeImageRect(), - getRotatedDegrees(), - result.sampleSize); - listener.onCropImageComplete(this, cropResult); - } - } - - /** - * Set the given bitmap to be used in for cropping
- * Optionally clear full if the bitmap is new, or partial clear if the bitmap has been - * manipulated. - */ - private void setBitmap( - Bitmap bitmap, int imageResource, Uri imageUri, int loadSampleSize, int degreesRotated) { - if (mBitmap == null || !mBitmap.equals(bitmap)) { - - mImageView.clearAnimation(); - - clearImageInt(); - - mBitmap = bitmap; - mImageView.setImageBitmap(mBitmap); - - mLoadedImageUri = imageUri; - mImageResource = imageResource; - mLoadedSampleSize = loadSampleSize; - mDegreesRotated = degreesRotated; - - applyImageMatrix(getWidth(), getHeight(), true, false); - - if (mCropOverlayView != null) { - mCropOverlayView.resetCropOverlayView(); - setCropOverlayVisibility(); - } - } - } - - /** - * Clear the current image set for cropping.
- * Full clear will also clear the data of the set image like Uri or Resource id while partial - * clear will only clear the bitmap and recycle if required. - */ - private void clearImageInt() { - - // if we allocated the bitmap, release it as fast as possible - if (mBitmap != null && (mImageResource > 0 || mLoadedImageUri != null)) { - mBitmap.recycle(); - } - mBitmap = null; - - // clean the loaded image flags for new image - mImageResource = 0; - mLoadedImageUri = null; - mLoadedSampleSize = 1; - mDegreesRotated = 0; - mZoom = 1; - mZoomOffsetX = 0; - mZoomOffsetY = 0; - mImageMatrix.reset(); - mSaveInstanceStateBitmapUri = null; - - mImageView.setImageBitmap(null); - - setCropOverlayVisibility(); - } - - /** - * Gets the cropped image based on the current crop window.
- * If (reqWidth,reqHeight) is given AND image is loaded from URI cropping will try to use sample - * size to fit in the requested width and height down-sampling if possible - optimization to get - * best size to quality.
- * The result will be invoked to listener set by {@link - * #setOnCropImageCompleteListener(OnCropImageCompleteListener)}. - * - * @param reqWidth the width to resize the cropped image to (see options) - * @param reqHeight the height to resize the cropped image to (see options) - * @param options the resize method to use on the cropped bitmap - * @param saveUri optional: to save the cropped image to - * @param saveCompressFormat if saveUri is given, the given compression will be used for saving - * the image - * @param saveCompressQuality if saveUri is given, the given quality will be used for the - * compression. - */ - public void startCropWorkerTask( - int reqWidth, - int reqHeight, - RequestSizeOptions options, - Uri saveUri, - Bitmap.CompressFormat saveCompressFormat, - int saveCompressQuality) { - Bitmap bitmap = mBitmap; - if (bitmap != null) { - mImageView.clearAnimation(); - - BitmapCroppingWorkerTask currentTask = - mBitmapCroppingWorkerTask != null ? mBitmapCroppingWorkerTask.get() : null; - if (currentTask != null) { - // cancel previous cropping - currentTask.cancel(true); - } - - reqWidth = options != RequestSizeOptions.NONE ? reqWidth : 0; - reqHeight = options != RequestSizeOptions.NONE ? reqHeight : 0; - - int orgWidth = bitmap.getWidth() * mLoadedSampleSize; - int orgHeight = bitmap.getHeight() * mLoadedSampleSize; - if (mLoadedImageUri != null - && (mLoadedSampleSize > 1 || options == RequestSizeOptions.SAMPLING)) { - mBitmapCroppingWorkerTask = - new WeakReference<>( - new BitmapCroppingWorkerTask( - this, - mLoadedImageUri, - getCropPoints(), - mDegreesRotated, - orgWidth, - orgHeight, - mCropOverlayView.isFixAspectRatio(), - mCropOverlayView.getAspectRatioX(), - mCropOverlayView.getAspectRatioY(), - reqWidth, - reqHeight, - mFlipHorizontally, - mFlipVertically, - options, - saveUri, - saveCompressFormat, - saveCompressQuality)); - } else { - mBitmapCroppingWorkerTask = - new WeakReference<>( - new BitmapCroppingWorkerTask( - this, - bitmap, - getCropPoints(), - mDegreesRotated, - mCropOverlayView.isFixAspectRatio(), - mCropOverlayView.getAspectRatioX(), - mCropOverlayView.getAspectRatioY(), - reqWidth, - reqHeight, - mFlipHorizontally, - mFlipVertically, - options, - saveUri, - saveCompressFormat, - saveCompressQuality)); - } - mBitmapCroppingWorkerTask.get().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - setProgressBarVisibility(); - } - } - - @Override - public Parcelable onSaveInstanceState() { - if (mLoadedImageUri == null && mBitmap == null && mImageResource < 1) { - return super.onSaveInstanceState(); - } - - Bundle bundle = new Bundle(); - Uri imageUri = mLoadedImageUri; - if (mSaveBitmapToInstanceState && imageUri == null && mImageResource < 1) { - mSaveInstanceStateBitmapUri = - imageUri = - BitmapUtils.writeTempStateStoreBitmap( - getContext(), mBitmap, mSaveInstanceStateBitmapUri); - } - if (imageUri != null && mBitmap != null) { - String key = UUID.randomUUID().toString(); - BitmapUtils.mStateBitmap = new Pair<>(key, new WeakReference<>(mBitmap)); - bundle.putString("LOADED_IMAGE_STATE_BITMAP_KEY", key); - } - if (mBitmapLoadingWorkerTask != null) { - BitmapLoadingWorkerTask task = mBitmapLoadingWorkerTask.get(); - if (task != null) { - bundle.putParcelable("LOADING_IMAGE_URI", task.getUri()); - } - } - bundle.putParcelable("instanceState", super.onSaveInstanceState()); - bundle.putParcelable("LOADED_IMAGE_URI", imageUri); - bundle.putInt("LOADED_IMAGE_RESOURCE", mImageResource); - bundle.putInt("LOADED_SAMPLE_SIZE", mLoadedSampleSize); - bundle.putInt("DEGREES_ROTATED", mDegreesRotated); - bundle.putParcelable("INITIAL_CROP_RECT", mCropOverlayView.getInitialCropWindowRect()); - - BitmapUtils.RECT.set(mCropOverlayView.getCropWindowRect()); - - mImageMatrix.invert(mImageInverseMatrix); - mImageInverseMatrix.mapRect(BitmapUtils.RECT); - - bundle.putParcelable("CROP_WINDOW_RECT", BitmapUtils.RECT); - bundle.putString("CROP_SHAPE", mCropOverlayView.getCropShape().name()); - bundle.putBoolean("CROP_AUTO_ZOOM_ENABLED", mAutoZoomEnabled); - bundle.putInt("CROP_MAX_ZOOM", mMaxZoom); - bundle.putBoolean("CROP_FLIP_HORIZONTALLY", mFlipHorizontally); - bundle.putBoolean("CROP_FLIP_VERTICALLY", mFlipVertically); - - return bundle; - } - - @Override - public void onRestoreInstanceState(Parcelable state) { - - if (state instanceof Bundle) { - Bundle bundle = (Bundle) state; - - // prevent restoring state if already set by outside code - if (mBitmapLoadingWorkerTask == null - && mLoadedImageUri == null - && mBitmap == null - && mImageResource == 0) { - - Uri uri = bundle.getParcelable("LOADED_IMAGE_URI"); - if (uri != null) { - String key = bundle.getString("LOADED_IMAGE_STATE_BITMAP_KEY"); - if (key != null) { - Bitmap stateBitmap = - BitmapUtils.mStateBitmap != null && BitmapUtils.mStateBitmap.first.equals(key) - ? BitmapUtils.mStateBitmap.second.get() - : null; - BitmapUtils.mStateBitmap = null; - if (stateBitmap != null && !stateBitmap.isRecycled()) { - setBitmap(stateBitmap, 0, uri, bundle.getInt("LOADED_SAMPLE_SIZE"), 0); - } - } - if (mLoadedImageUri == null) { - setImageUriAsync(uri); - } - } else { - int resId = bundle.getInt("LOADED_IMAGE_RESOURCE"); - if (resId > 0) { - setImageResource(resId); - } else { - uri = bundle.getParcelable("LOADING_IMAGE_URI"); - if (uri != null) { - setImageUriAsync(uri); - } - } - } - - mDegreesRotated = mRestoreDegreesRotated = bundle.getInt("DEGREES_ROTATED"); - - Rect initialCropRect = bundle.getParcelable("INITIAL_CROP_RECT"); - if (initialCropRect != null - && (initialCropRect.width() > 0 || initialCropRect.height() > 0)) { - mCropOverlayView.setInitialCropWindowRect(initialCropRect); - } - - RectF cropWindowRect = bundle.getParcelable("CROP_WINDOW_RECT"); - if (cropWindowRect != null && (cropWindowRect.width() > 0 || cropWindowRect.height() > 0)) { - mRestoreCropWindowRect = cropWindowRect; - } - - mCropOverlayView.setCropShape(CropShape.valueOf(bundle.getString("CROP_SHAPE"))); - - mAutoZoomEnabled = bundle.getBoolean("CROP_AUTO_ZOOM_ENABLED"); - mMaxZoom = bundle.getInt("CROP_MAX_ZOOM"); - - mFlipHorizontally = bundle.getBoolean("CROP_FLIP_HORIZONTALLY"); - mFlipVertically = bundle.getBoolean("CROP_FLIP_VERTICALLY"); - } - - super.onRestoreInstanceState(bundle.getParcelable("instanceState")); - } else { - super.onRestoreInstanceState(state); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - if (mBitmap != null) { - - // Bypasses a baffling bug when used within a ScrollView, where heightSize is set to 0. - if (heightSize == 0) { - heightSize = mBitmap.getHeight(); - } - - int desiredWidth; - int desiredHeight; - - double viewToBitmapWidthRatio = Double.POSITIVE_INFINITY; - double viewToBitmapHeightRatio = Double.POSITIVE_INFINITY; - - // Checks if either width or height needs to be fixed - if (widthSize < mBitmap.getWidth()) { - viewToBitmapWidthRatio = (double) widthSize / (double) mBitmap.getWidth(); - } - if (heightSize < mBitmap.getHeight()) { - viewToBitmapHeightRatio = (double) heightSize / (double) mBitmap.getHeight(); - } - - // If either needs to be fixed, choose smallest ratio and calculate from there - if (viewToBitmapWidthRatio != Double.POSITIVE_INFINITY - || viewToBitmapHeightRatio != Double.POSITIVE_INFINITY) { - if (viewToBitmapWidthRatio <= viewToBitmapHeightRatio) { - desiredWidth = widthSize; - desiredHeight = (int) (mBitmap.getHeight() * viewToBitmapWidthRatio); - } else { - desiredHeight = heightSize; - desiredWidth = (int) (mBitmap.getWidth() * viewToBitmapHeightRatio); - } - } else { - // Otherwise, the picture is within frame layout bounds. Desired width is simply picture - // size - desiredWidth = mBitmap.getWidth(); - desiredHeight = mBitmap.getHeight(); - } - - int width = getOnMeasureSpec(widthMode, widthSize, desiredWidth); - int height = getOnMeasureSpec(heightMode, heightSize, desiredHeight); - - mLayoutWidth = width; - mLayoutHeight = height; - - setMeasuredDimension(mLayoutWidth, mLayoutHeight); - - } else { - setMeasuredDimension(widthSize, heightSize); - } - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - - super.onLayout(changed, l, t, r, b); - - if (mLayoutWidth > 0 && mLayoutHeight > 0) { - // Gets original parameters, and creates the new parameters - ViewGroup.LayoutParams origParams = this.getLayoutParams(); - origParams.width = mLayoutWidth; - origParams.height = mLayoutHeight; - setLayoutParams(origParams); - - if (mBitmap != null) { - applyImageMatrix(r - l, b - t, true, false); - - // after state restore we want to restore the window crop, possible only after widget size - // is known - if (mRestoreCropWindowRect != null) { - if (mRestoreDegreesRotated != mInitialDegreesRotated) { - mDegreesRotated = mRestoreDegreesRotated; - applyImageMatrix(r - l, b - t, true, false); - } - mImageMatrix.mapRect(mRestoreCropWindowRect); - mCropOverlayView.setCropWindowRect(mRestoreCropWindowRect); - handleCropWindowChanged(false, false); - mCropOverlayView.fixCurrentCropWindowRect(); - mRestoreCropWindowRect = null; - } else if (mSizeChanged) { - mSizeChanged = false; - handleCropWindowChanged(false, false); - } - } else { - updateImageBounds(true); - } - } else { - updateImageBounds(true); - } - } - - /** - * Detect size change to handle auto-zoom using {@link #handleCropWindowChanged(boolean, boolean)} - * in {@link #layout(int, int, int, int)}. - */ - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mSizeChanged = oldw > 0 && oldh > 0; - } - - /** - * Handle crop window change to:
- * 1. Execute auto-zoom-in/out depending on the area covered of cropping window relative to the - * available view area.
- * 2. Slide the zoomed sub-area if the cropping window is outside of the visible view sub-area. - *
- * - * @param inProgress is the crop window change is still in progress by the user - * @param animate if to animate the change to the image matrix, or set it directly - */ - private void handleCropWindowChanged(boolean inProgress, boolean animate) { - int width = getWidth(); - int height = getHeight(); - if (mBitmap != null && width > 0 && height > 0) { - - RectF cropRect = mCropOverlayView.getCropWindowRect(); - if (inProgress) { - if (cropRect.left < 0 - || cropRect.top < 0 - || cropRect.right > width - || cropRect.bottom > height) { - applyImageMatrix(width, height, false, false); - } - } else if (mAutoZoomEnabled || mZoom > 1) { - float newZoom = 0; - // keep the cropping window covered area to 50%-65% of zoomed sub-area - if (mZoom < mMaxZoom - && cropRect.width() < width * 0.5f - && cropRect.height() < height * 0.5f) { - newZoom = - Math.min( - mMaxZoom, - Math.min( - width / (cropRect.width() / mZoom / 0.64f), - height / (cropRect.height() / mZoom / 0.64f))); - } - if (mZoom > 1 && (cropRect.width() > width * 0.65f || cropRect.height() > height * 0.65f)) { - newZoom = - Math.max( - 1, - Math.min( - width / (cropRect.width() / mZoom / 0.51f), - height / (cropRect.height() / mZoom / 0.51f))); - } - if (!mAutoZoomEnabled) { - newZoom = 1; - } - - if (newZoom > 0 && newZoom != mZoom) { - if (animate) { - if (mAnimation == null) { - // lazy create animation single instance - mAnimation = new CropImageAnimation(mImageView, mCropOverlayView); - } - // set the state for animation to start from - mAnimation.setStartState(mImagePoints, mImageMatrix); - } - - mZoom = newZoom; - - applyImageMatrix(width, height, true, animate); - } - } - if (mOnSetCropWindowChangeListener != null && !inProgress) { - mOnSetCropWindowChangeListener.onCropWindowChanged(); - } - } - } - - /** - * Apply matrix to handle the image inside the image view. - * - * @param width the width of the image view - * @param height the height of the image view - */ - private void applyImageMatrix(float width, float height, boolean center, boolean animate) { - if (mBitmap != null && width > 0 && height > 0) { - - mImageMatrix.invert(mImageInverseMatrix); - RectF cropRect = mCropOverlayView.getCropWindowRect(); - mImageInverseMatrix.mapRect(cropRect); - - mImageMatrix.reset(); - - // move the image to the center of the image view first so we can manipulate it from there - mImageMatrix.postTranslate( - (width - mBitmap.getWidth()) / 2, (height - mBitmap.getHeight()) / 2); - mapImagePointsByImageMatrix(); - - // rotate the image the required degrees from center of image - if (mDegreesRotated > 0) { - mImageMatrix.postRotate( - mDegreesRotated, - BitmapUtils.getRectCenterX(mImagePoints), - BitmapUtils.getRectCenterY(mImagePoints)); - mapImagePointsByImageMatrix(); - } - - // scale the image to the image view, image rect transformed to know new width/height - float scale = - Math.min( - width / BitmapUtils.getRectWidth(mImagePoints), - height / BitmapUtils.getRectHeight(mImagePoints)); - if (mScaleType == ScaleType.FIT_CENTER - || (mScaleType == ScaleType.CENTER_INSIDE && scale < 1) - || (scale > 1 && mAutoZoomEnabled)) { - mImageMatrix.postScale( - scale, - scale, - BitmapUtils.getRectCenterX(mImagePoints), - BitmapUtils.getRectCenterY(mImagePoints)); - mapImagePointsByImageMatrix(); - } - - // scale by the current zoom level - float scaleX = mFlipHorizontally ? -mZoom : mZoom; - float scaleY = mFlipVertically ? -mZoom : mZoom; - mImageMatrix.postScale( - scaleX, - scaleY, - BitmapUtils.getRectCenterX(mImagePoints), - BitmapUtils.getRectCenterY(mImagePoints)); - mapImagePointsByImageMatrix(); - - mImageMatrix.mapRect(cropRect); - - if (center) { - // set the zoomed area to be as to the center of cropping window as possible - mZoomOffsetX = - width > BitmapUtils.getRectWidth(mImagePoints) - ? 0 - : Math.max( - Math.min( - width / 2 - cropRect.centerX(), -BitmapUtils.getRectLeft(mImagePoints)), - getWidth() - BitmapUtils.getRectRight(mImagePoints)) - / scaleX; - mZoomOffsetY = - height > BitmapUtils.getRectHeight(mImagePoints) - ? 0 - : Math.max( - Math.min( - height / 2 - cropRect.centerY(), -BitmapUtils.getRectTop(mImagePoints)), - getHeight() - BitmapUtils.getRectBottom(mImagePoints)) - / scaleY; - } else { - // adjust the zoomed area so the crop window rectangle will be inside the area in case it - // was moved outside - mZoomOffsetX = - Math.min(Math.max(mZoomOffsetX * scaleX, -cropRect.left), -cropRect.right + width) - / scaleX; - mZoomOffsetY = - Math.min(Math.max(mZoomOffsetY * scaleY, -cropRect.top), -cropRect.bottom + height) - / scaleY; - } - - // apply to zoom offset translate and update the crop rectangle to offset correctly - mImageMatrix.postTranslate(mZoomOffsetX * scaleX, mZoomOffsetY * scaleY); - cropRect.offset(mZoomOffsetX * scaleX, mZoomOffsetY * scaleY); - mCropOverlayView.setCropWindowRect(cropRect); - mapImagePointsByImageMatrix(); - mCropOverlayView.invalidate(); - - // set matrix to apply - if (animate) { - // set the state for animation to end in, start animation now - mAnimation.setEndState(mImagePoints, mImageMatrix); - mImageView.startAnimation(mAnimation); - } else { - mImageView.setImageMatrix(mImageMatrix); - } - - // update the image rectangle in the crop overlay - updateImageBounds(false); - } - } - - /** - * Adjust the given image rectangle by image transformation matrix to know the final rectangle of - * the image.
- * To get the proper rectangle it must be first reset to original image rectangle. - */ - private void mapImagePointsByImageMatrix() { - mImagePoints[0] = 0; - mImagePoints[1] = 0; - mImagePoints[2] = mBitmap.getWidth(); - mImagePoints[3] = 0; - mImagePoints[4] = mBitmap.getWidth(); - mImagePoints[5] = mBitmap.getHeight(); - mImagePoints[6] = 0; - mImagePoints[7] = mBitmap.getHeight(); - mImageMatrix.mapPoints(mImagePoints); - mScaleImagePoints[0] = 0; - mScaleImagePoints[1] = 0; - mScaleImagePoints[2] = 100; - mScaleImagePoints[3] = 0; - mScaleImagePoints[4] = 100; - mScaleImagePoints[5] = 100; - mScaleImagePoints[6] = 0; - mScaleImagePoints[7] = 100; - mImageMatrix.mapPoints(mScaleImagePoints); - } - - /** - * Set visibility of crop overlay to hide it when there is no image or specificly set by client. - */ - private void setCropOverlayVisibility() { - if (mCropOverlayView != null) { - mCropOverlayView.setVisibility(mShowCropOverlay && mBitmap != null ? VISIBLE : INVISIBLE); - } - } - - /** - * Set visibility of progress bar when async loading/cropping is in process and show is enabled. - */ - private void setProgressBarVisibility() { - boolean visible = - mShowProgressBar - && (mBitmap == null && mBitmapLoadingWorkerTask != null - || mBitmapCroppingWorkerTask != null); - mProgressBar.setVisibility(visible ? VISIBLE : INVISIBLE); - } - - /** - * Update the scale factor between the actual image bitmap and the shown image.
- */ - private void updateImageBounds(boolean clear) { - if (mBitmap != null && !clear) { - - // Get the scale factor between the actual Bitmap dimensions and the displayed dimensions for - // width/height. - float scaleFactorWidth = - 100f * mLoadedSampleSize / BitmapUtils.getRectWidth(mScaleImagePoints); - float scaleFactorHeight = - 100f * mLoadedSampleSize / BitmapUtils.getRectHeight(mScaleImagePoints); - mCropOverlayView.setCropWindowLimits( - getWidth(), getHeight(), scaleFactorWidth, scaleFactorHeight); - } - - // set the bitmap rectangle and update the crop window after scale factor is set - mCropOverlayView.setBounds(clear ? null : mImagePoints, getWidth(), getHeight()); - } - // endregion - - // region: Inner class: CropShape - - /** - * The possible cropping area shape.
- * To set square/circle crop shape set aspect ratio to 1:1. - */ - public enum CropShape { - RECTANGLE, - OVAL - } - // endregion - - // region: Inner class: ScaleType - - /** - * Options for scaling the bounds of cropping image to the bounds of Crop Image View.
- * Note: Some options are affected by auto-zoom, if enabled. - */ - public enum ScaleType { - - /** - * Scale the image uniformly (maintain the image's aspect ratio) to fit in crop image view.
- * The largest dimension will be equals to crop image view and the second dimension will be - * smaller. - */ - FIT_CENTER, - - /** - * Center the image in the view, but perform no scaling.
- * Note: If auto-zoom is enabled and the source image is smaller than crop image view then it - * will be scaled uniformly to fit the crop image view. - */ - CENTER, - - /** - * Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width - * and height) of the image will be equal to or larger than the corresponding dimension - * of the view (minus padding).
- * The image is then centered in the view. - */ - CENTER_CROP, - - /** - * Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width - * and height) of the image will be equal to or less than the corresponding dimension of - * the view (minus padding).
- * The image is then centered in the view.
- * Note: If auto-zoom is enabled and the source image is smaller than crop image view then it - * will be scaled uniformly to fit the crop image view. - */ - CENTER_INSIDE - } - // endregion - - // region: Inner class: Guidelines - - /** - * The possible guidelines showing types. - */ - public enum Guidelines { - /** - * Never show - */ - OFF, - - /** - * Show when crop move action is live - */ - ON_TOUCH, - - /** - * Always show - */ - ON - } - // endregion - - // region: Inner class: RequestSizeOptions - - /** - * Possible options for handling requested width/height for cropping. - */ - public enum RequestSizeOptions { - - /** - * No resize/sampling is done unless required for memory management (OOM). - */ - NONE, - - /** - * Only sample the image during loading (if image set using URI) so the smallest of the image - * dimensions will be between the requested size and x2 requested size.
- * NOTE: resulting image will not be exactly requested width/height see: Loading - * Large Bitmaps Efficiently. - */ - SAMPLING, - - /** - * Resize the image uniformly (maintain the image's aspect ratio) so that both dimensions (width - * and height) of the image will be equal to or less than the corresponding requested - * dimension.
- * If the image is smaller than the requested size it will NOT change. - */ - RESIZE_INSIDE, - - /** - * Resize the image uniformly (maintain the image's aspect ratio) to fit in the given - * width/height.
- * The largest dimension will be equals to the requested and the second dimension will be - * smaller.
- * If the image is smaller than the requested size it will enlarge it. - */ - RESIZE_FIT, - - /** - * Resize the image to fit exactly in the given width/height.
- * This resize method does NOT preserve aspect ratio.
- * If the image is smaller than the requested size it will enlarge it. - */ - RESIZE_EXACT - } - // endregion - - // region: Inner class: OnSetImageUriCompleteListener - - /** - * Interface definition for a callback to be invoked when the crop overlay is released. - */ - public interface OnSetCropOverlayReleasedListener { - - /** - * Called when the crop overlay changed listener is called and inProgress is false. - * - * @param rect The rect coordinates of the cropped overlay - */ - void onCropOverlayReleased(Rect rect); - } - - /** - * Interface definition for a callback to be invoked when the crop overlay is released. - */ - public interface OnSetCropOverlayMovedListener { - - /** - * Called when the crop overlay is moved - * - * @param rect The rect coordinates of the cropped overlay - */ - void onCropOverlayMoved(Rect rect); - } - - /** - * Interface definition for a callback to be invoked when the crop overlay is released. - */ - public interface OnSetCropWindowChangeListener { - - /** - * Called when the crop window is changed - */ - void onCropWindowChanged(); - } - - /** - * Interface definition for a callback to be invoked when image async loading is complete. - */ - public interface OnSetImageUriCompleteListener { - - /** - * Called when a crop image view has completed loading image for cropping.
- * If loading failed error parameter will contain the error. - * - * @param view The crop image view that loading of image was complete. - * @param uri the URI of the image that was loading - * @param error if error occurred during loading will contain the error, otherwise null. - */ - void onSetImageUriComplete(CropImageView view, Uri uri, Exception error); - } - // endregion - - // region: Inner class: OnGetCroppedImageCompleteListener - - /** - * Interface definition for a callback to be invoked when image async crop is complete. - */ - public interface OnCropImageCompleteListener { - - /** - * Called when a crop image view has completed cropping image.
- * Result object contains the cropped bitmap, saved cropped image uri, crop points data or the - * error occured during cropping. - * - * @param view The crop image view that cropping of image was complete. - * @param result the crop image result data (with cropped image or error) - */ - void onCropImageComplete(CropImageView view, CropResult result); - } - // endregion - - // region: Inner class: ActivityResult - - /** - * Result data of crop image. - */ - public static class CropResult { - - /** - * The image bitmap of the original image loaded for cropping.
- * Null if uri used to load image or activity result is used. - */ - private final Bitmap mOriginalBitmap; - - /** - * The Android uri of the original image loaded for cropping.
- * Null if bitmap was used to load image. - */ - private final Uri mOriginalUri; - - /** - * The cropped image bitmap result.
- * Null if save cropped image was executed, no output requested or failure. - */ - private final Bitmap mBitmap; - - /** - * The Android uri of the saved cropped image result.
- * Null if get cropped image was executed, no output requested or failure. - */ - private final Uri mUri; - - /** - * The error that failed the loading/cropping (null if successful) - */ - private final Exception mError; - - /** - * The 4 points of the cropping window in the source image - */ - private final float[] mCropPoints; - - /** - * The rectangle of the cropping window in the source image - */ - private final Rect mCropRect; - - /** - * The rectangle of the source image dimensions - */ - private final Rect mWholeImageRect; - - /** - * The final rotation of the cropped image relative to source - */ - private final int mRotation; - - /** - * sample size used creating the crop bitmap to lower its size - */ - private final int mSampleSize; - - CropResult( - Bitmap originalBitmap, - Uri originalUri, - Bitmap bitmap, - Uri uri, - Exception error, - float[] cropPoints, - Rect cropRect, - Rect wholeImageRect, - int rotation, - int sampleSize) { - mOriginalBitmap = originalBitmap; - mOriginalUri = originalUri; - mBitmap = bitmap; - mUri = uri; - mError = error; - mCropPoints = cropPoints; - mCropRect = cropRect; - mWholeImageRect = wholeImageRect; - mRotation = rotation; - mSampleSize = sampleSize; - } - - /** - * The image bitmap of the original image loaded for cropping.
- * Null if uri used to load image or activity result is used. - */ - public Bitmap getOriginalBitmap() { - return mOriginalBitmap; - } - - /** - * The Android uri of the original image loaded for cropping.
- * Null if bitmap was used to load image. - */ - public Uri getOriginalUri() { - return mOriginalUri; - } - - /** - * Is the result is success or error. - */ - public boolean isSuccessful() { - return mError == null; - } - - /** - * The cropped image bitmap result.
- * Null if save cropped image was executed, no output requested or failure. - */ - public Bitmap getBitmap() { - return mBitmap; - } - - /** - * The Android uri of the saved cropped image result Null if get cropped image was executed, no - * output requested or failure. - */ - public Uri getUri() { - return mUri; - } - - /** - * The error that failed the loading/cropping (null if successful) - */ - public Exception getError() { - return mError; - } - - /** - * The 4 points of the cropping window in the source image - */ - public float[] getCropPoints() { - return mCropPoints; - } - - /** - * The rectangle of the cropping window in the source image - */ - public Rect getCropRect() { - return mCropRect; - } - - /** - * The rectangle of the source image dimensions - */ - public Rect getWholeImageRect() { - return mWholeImageRect; - } - - /** - * The final rotation of the cropped image relative to source - */ - public int getRotation() { - return mRotation; - } - - /** - * sample size used creating the crop bitmap to lower its size - */ - public int getSampleSize() { - return mSampleSize; - } - } - // endregion -} diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropOverlayView.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropOverlayView.java deleted file mode 100644 index 2a774fe6..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropOverlayView.java +++ /dev/null @@ -1,1118 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth, -// inexhaustible as the great rivers. -// When they come to an end, -// they begin again, -// like the days and months; -// they die and are reborn, -// like the four seasons." -// -// - Sun Tsu, -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Region; -import android.os.Build; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.ScaleGestureDetector; -import android.view.View; - -import java.util.Arrays; - -/** - * A custom View representing the crop window and the shaded background outside the crop window. - */ -public class CropOverlayView extends View { - - // region: Fields and Consts - - /** - * Handler from crop window stuff, moving and knowing possition. - */ - private final CropWindowHandler mCropWindowHandler = new CropWindowHandler(); - /** - * Rectangle used for drawing - */ - private final RectF mDrawRect = new RectF(); - /** - * Used for oval crop window shape or non-straight rotation drawing. - */ - private final Path mPath = new Path(); - /** - * The bounding box around the Bitmap that we are cropping. - */ - private final float[] mBoundsPoints = new float[8]; - /** - * The bounding box around the Bitmap that we are cropping. - */ - private final RectF mCalcBounds = new RectF(); - /** - * the initial crop window rectangle to set - */ - private final Rect mInitialCropWindowRect = new Rect(); - /** - * Gesture detector used for multi touch box scaling - */ - private ScaleGestureDetector mScaleDetector; - /** - * Boolean to see if multi touch is enabled for the crop rectangle - */ - private boolean mMultiTouchEnabled; - /** - * Listener to publicj crop window changes - */ - private CropWindowChangeListener mCropWindowChangeListener; - /** - * The Paint used to draw the white rectangle around the crop area. - */ - private Paint mBorderPaint; - /** - * The Paint used to draw the corners of the Border - */ - private Paint mBorderCornerPaint; - /** - * The Paint used to draw the guidelines within the crop area when pressed. - */ - private Paint mGuidelinePaint; - /** - * The Paint used to darken the surrounding areas outside the crop area. - */ - private Paint mBackgroundPaint; - /** - * The bounding image view width used to know the crop overlay is at view edges. - */ - private int mViewWidth; - /** - * The bounding image view height used to know the crop overlay is at view edges. - */ - private int mViewHeight; - /** - * The offset to draw the border corener from the border - */ - private float mBorderCornerOffset; - /** - * the length of the border corner to draw - */ - private float mBorderCornerLength; - /** - * The initial crop window padding from image borders - */ - private float mInitialCropWindowPaddingRatio; - /** - * The radius of the touch zone (in pixels) around a given Handle. - */ - private float mTouchRadius; - /** - * An edge of the crop window will snap to the corresponding edge of a specified bounding box when - * the crop window edge is less than or equal to this distance (in pixels) away from the bounding - * box edge. - */ - private float mSnapRadius; - /** - * The Handle that is currently pressed; null if no Handle is pressed. - */ - private CropWindowMoveHandler mMoveHandler; - /** - * Flag indicating if the crop area should always be a certain aspect ratio (indicated by - * mTargetAspectRatio). - */ - private boolean mFixAspectRatio; - /** - * save the current aspect ratio of the image - */ - private int mAspectRatioX; - /** - * save the current aspect ratio of the image - */ - private int mAspectRatioY; - /** - * The aspect ratio that the crop area should maintain; this variable is only used when - * mMaintainAspectRatio is true. - */ - private float mTargetAspectRatio = ((float) mAspectRatioX) / mAspectRatioY; - /** - * Instance variables for customizable attributes - */ - private CropImageView.Guidelines mGuidelines; - /** - * The shape of the cropping area - rectangle/circular. - */ - private CropImageView.CropShape mCropShape; - /** - * Whether the Crop View has been initialized for the first time - */ - private boolean initializedCropWindow; - - /** - * Used to set back LayerType after changing to software. - */ - private Integer mOriginalLayerType; - // endregion - - public CropOverlayView(Context context) { - this(context, null); - } - - public CropOverlayView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Creates the Paint object for drawing. - */ - private static Paint getNewPaint(int color) { - Paint paint = new Paint(); - paint.setColor(color); - return paint; - } - - /** - * Creates the Paint object for given thickness and color, if thickness < 0 return null. - */ - private static Paint getNewPaintOrNull(float thickness, int color) { - if (thickness > 0) { - Paint borderPaint = new Paint(); - borderPaint.setColor(color); - borderPaint.setStrokeWidth(thickness); - borderPaint.setStyle(Paint.Style.STROKE); - borderPaint.setAntiAlias(true); - return borderPaint; - } else { - return null; - } - } - - /** - * Set the crop window change listener. - */ - public void setCropWindowChangeListener(CropWindowChangeListener listener) { - mCropWindowChangeListener = listener; - } - - /** - * Get the left/top/right/bottom coordinates of the crop window. - */ - public RectF getCropWindowRect() { - return mCropWindowHandler.getRect(); - } - - /** - * Set the left/top/right/bottom coordinates of the crop window. - */ - public void setCropWindowRect(RectF rect) { - mCropWindowHandler.setRect(rect); - } - - /** - * Fix the current crop window rectangle if it is outside of cropping image or view bounds. - */ - public void fixCurrentCropWindowRect() { - RectF rect = getCropWindowRect(); - fixCropWindowRectByRules(rect); - mCropWindowHandler.setRect(rect); - } - - /** - * Informs the CropOverlayView of the image's position relative to the ImageView. This is - * necessary to call in order to draw the crop window. - * - * @param boundsPoints the image's bounding points - * @param viewWidth The bounding image view width. - * @param viewHeight The bounding image view height. - */ - public void setBounds(float[] boundsPoints, int viewWidth, int viewHeight) { - if (boundsPoints == null || !Arrays.equals(mBoundsPoints, boundsPoints)) { - if (boundsPoints == null) { - Arrays.fill(mBoundsPoints, 0); - } else { - System.arraycopy(boundsPoints, 0, mBoundsPoints, 0, boundsPoints.length); - } - mViewWidth = viewWidth; - mViewHeight = viewHeight; - RectF cropRect = mCropWindowHandler.getRect(); - if (cropRect.width() == 0 || cropRect.height() == 0) { - initCropWindow(); - } - } - } - - /** - * Resets the crop overlay view. - */ - public void resetCropOverlayView() { - if (initializedCropWindow) { - setCropWindowRect(BitmapUtils.EMPTY_RECT_F); - initCropWindow(); - invalidate(); - } - } - - /** - * The shape of the cropping area - rectangle/circular. - */ - public CropImageView.CropShape getCropShape() { - return mCropShape; - } - - /** - * The shape of the cropping area - rectangle/circular. - */ - public void setCropShape(CropImageView.CropShape cropShape) { - if (mCropShape != cropShape) { - mCropShape = cropShape; - if (Build.VERSION.SDK_INT <= 17) { - if (mCropShape == CropImageView.CropShape.OVAL) { - mOriginalLayerType = getLayerType(); - if (mOriginalLayerType != View.LAYER_TYPE_SOFTWARE) { - // TURN off hardware acceleration - setLayerType(View.LAYER_TYPE_SOFTWARE, null); - } else { - mOriginalLayerType = null; - } - } else if (mOriginalLayerType != null) { - // return hardware acceleration back - setLayerType(mOriginalLayerType, null); - mOriginalLayerType = null; - } - } - invalidate(); - } - } - - /** - * Get the current guidelines option set. - */ - public CropImageView.Guidelines getGuidelines() { - return mGuidelines; - } - - /** - * Sets the guidelines for the CropOverlayView to be either on, off, or to show when resizing the - * application. - */ - public void setGuidelines(CropImageView.Guidelines guidelines) { - if (mGuidelines != guidelines) { - mGuidelines = guidelines; - if (initializedCropWindow) { - invalidate(); - } - } - } - - /** - * whether the aspect ratio is fixed or not; true fixes the aspect ratio, while false allows it to - * be changed. - */ - public boolean isFixAspectRatio() { - return mFixAspectRatio; - } - - /** - * Sets whether the aspect ratio is fixed or not; true fixes the aspect ratio, while false allows - * it to be changed. - */ - public void setFixedAspectRatio(boolean fixAspectRatio) { - if (mFixAspectRatio != fixAspectRatio) { - mFixAspectRatio = fixAspectRatio; - if (initializedCropWindow) { - initCropWindow(); - invalidate(); - } - } - } - - /** - * the X value of the aspect ratio; - */ - public int getAspectRatioX() { - return mAspectRatioX; - } - - /** - * Sets the X value of the aspect ratio; is defaulted to 1. - */ - public void setAspectRatioX(int aspectRatioX) { - if (aspectRatioX <= 0) { - throw new IllegalArgumentException( - "Cannot set aspect ratio value to a number less than or equal to 0."); - } else if (mAspectRatioX != aspectRatioX) { - mAspectRatioX = aspectRatioX; - mTargetAspectRatio = ((float) mAspectRatioX) / mAspectRatioY; - - if (initializedCropWindow) { - initCropWindow(); - invalidate(); - } - } - } - - /** - * the Y value of the aspect ratio; - */ - public int getAspectRatioY() { - return mAspectRatioY; - } - - /** - * Sets the Y value of the aspect ratio; is defaulted to 1. - * - * @param aspectRatioY int that specifies the new Y value of the aspect ratio - */ - public void setAspectRatioY(int aspectRatioY) { - if (aspectRatioY <= 0) { - throw new IllegalArgumentException( - "Cannot set aspect ratio value to a number less than or equal to 0."); - } else if (mAspectRatioY != aspectRatioY) { - mAspectRatioY = aspectRatioY; - mTargetAspectRatio = ((float) mAspectRatioX) / mAspectRatioY; - - if (initializedCropWindow) { - initCropWindow(); - invalidate(); - } - } - } - - /** - * An edge of the crop window will snap to the corresponding edge of a specified bounding box when - * the crop window edge is less than or equal to this distance (in pixels) away from the bounding - * box edge. (default: 3) - */ - public void setSnapRadius(float snapRadius) { - mSnapRadius = snapRadius; - } - - /** - * Set multi touch functionality to enabled/disabled. - */ - public boolean setMultiTouchEnabled(boolean multiTouchEnabled) { - if (mMultiTouchEnabled != multiTouchEnabled) { - mMultiTouchEnabled = multiTouchEnabled; - if (mMultiTouchEnabled && mScaleDetector == null) { - mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); - } - return true; - } - return false; - } - - /** - * the min size the resulting cropping image is allowed to be, affects the cropping window limits - * (in pixels).
- */ - public void setMinCropResultSize(int minCropResultWidth, int minCropResultHeight) { - mCropWindowHandler.setMinCropResultSize(minCropResultWidth, minCropResultHeight); - } - - /** - * the max size the resulting cropping image is allowed to be, affects the cropping window limits - * (in pixels).
- */ - public void setMaxCropResultSize(int maxCropResultWidth, int maxCropResultHeight) { - mCropWindowHandler.setMaxCropResultSize(maxCropResultWidth, maxCropResultHeight); - } - - /** - * set the max width/height and scale factor of the shown image to original image to scale the - * limits appropriately. - */ - public void setCropWindowLimits( - float maxWidth, float maxHeight, float scaleFactorWidth, float scaleFactorHeight) { - mCropWindowHandler.setCropWindowLimits( - maxWidth, maxHeight, scaleFactorWidth, scaleFactorHeight); - } - - /** - * Get crop window initial rectangle. - */ - public Rect getInitialCropWindowRect() { - return mInitialCropWindowRect; - } - - /** - * Set crop window initial rectangle to be used instead of default. - */ - public void setInitialCropWindowRect(Rect rect) { - mInitialCropWindowRect.set(rect != null ? rect : BitmapUtils.EMPTY_RECT); - if (initializedCropWindow) { - initCropWindow(); - invalidate(); - callOnCropWindowChanged(false); - } - } - - // region: Private methods - - /** - * Reset crop window to initial rectangle. - */ - public void resetCropWindowRect() { - if (initializedCropWindow) { - initCropWindow(); - invalidate(); - callOnCropWindowChanged(false); - } - } - - /** - * Sets all initial values, but does not call initCropWindow to reset the views.
- * Used once at the very start to initialize the attributes. - */ - public void setInitialAttributeValues(CropImageOptions options) { - - mCropWindowHandler.setInitialAttributeValues(options); - - setCropShape(options.cropShape); - - setSnapRadius(options.snapRadius); - - setGuidelines(options.guidelines); - - setFixedAspectRatio(options.fixAspectRatio); - - setAspectRatioX(options.aspectRatioX); - - setAspectRatioY(options.aspectRatioY); - - setMultiTouchEnabled(options.multiTouchEnabled); - - mTouchRadius = options.touchRadius; - - mInitialCropWindowPaddingRatio = options.initialCropWindowPaddingRatio; - - mBorderPaint = getNewPaintOrNull(options.borderLineThickness, options.borderLineColor); - - mBorderCornerOffset = options.borderCornerOffset; - mBorderCornerLength = options.borderCornerLength; - mBorderCornerPaint = - getNewPaintOrNull(options.borderCornerThickness, options.borderCornerColor); - - mGuidelinePaint = getNewPaintOrNull(options.guidelinesThickness, options.guidelinesColor); - - mBackgroundPaint = getNewPaint(options.backgroundColor); - } - - /** - * Set the initial crop window size and position. This is dependent on the size and position of - * the image being cropped. - */ - private void initCropWindow() { - - float leftLimit = Math.max(BitmapUtils.getRectLeft(mBoundsPoints), 0); - float topLimit = Math.max(BitmapUtils.getRectTop(mBoundsPoints), 0); - float rightLimit = Math.min(BitmapUtils.getRectRight(mBoundsPoints), getWidth()); - float bottomLimit = Math.min(BitmapUtils.getRectBottom(mBoundsPoints), getHeight()); - - if (rightLimit <= leftLimit || bottomLimit <= topLimit) { - return; - } - - RectF rect = new RectF(); - - // Tells the attribute functions the crop window has already been initialized - initializedCropWindow = true; - - float horizontalPadding = mInitialCropWindowPaddingRatio * (rightLimit - leftLimit); - float verticalPadding = mInitialCropWindowPaddingRatio * (bottomLimit - topLimit); - - if (mInitialCropWindowRect.width() > 0 && mInitialCropWindowRect.height() > 0) { - // Get crop window position relative to the displayed image. - rect.left = - leftLimit + mInitialCropWindowRect.left / mCropWindowHandler.getScaleFactorWidth(); - rect.top = topLimit + mInitialCropWindowRect.top / mCropWindowHandler.getScaleFactorHeight(); - rect.right = - rect.left + mInitialCropWindowRect.width() / mCropWindowHandler.getScaleFactorWidth(); - rect.bottom = - rect.top + mInitialCropWindowRect.height() / mCropWindowHandler.getScaleFactorHeight(); - - // Correct for floating point errors. Crop rect boundaries should not exceed the source Bitmap - // bounds. - rect.left = Math.max(leftLimit, rect.left); - rect.top = Math.max(topLimit, rect.top); - rect.right = Math.min(rightLimit, rect.right); - rect.bottom = Math.min(bottomLimit, rect.bottom); - - } else if (mFixAspectRatio && rightLimit > leftLimit && bottomLimit > topLimit) { - - // If the image aspect ratio is wider than the crop aspect ratio, - // then the image height is the determining initial length. Else, vice-versa. - float bitmapAspectRatio = (rightLimit - leftLimit) / (bottomLimit - topLimit); - if (bitmapAspectRatio > mTargetAspectRatio) { - - rect.top = topLimit + verticalPadding; - rect.bottom = bottomLimit - verticalPadding; - - float centerX = getWidth() / 2f; - - // dirty fix for wrong crop overlay aspect ratio when using fixed aspect ratio - mTargetAspectRatio = (float) mAspectRatioX / mAspectRatioY; - - // Limits the aspect ratio to no less than 40 wide or 40 tall - float cropWidth = - Math.max(mCropWindowHandler.getMinCropWidth(), rect.height() * mTargetAspectRatio); - - float halfCropWidth = cropWidth / 2f; - rect.left = centerX - halfCropWidth; - rect.right = centerX + halfCropWidth; - - } else { - - rect.left = leftLimit + horizontalPadding; - rect.right = rightLimit - horizontalPadding; - - float centerY = getHeight() / 2f; - - // Limits the aspect ratio to no less than 40 wide or 40 tall - float cropHeight = - Math.max(mCropWindowHandler.getMinCropHeight(), rect.width() / mTargetAspectRatio); - - float halfCropHeight = cropHeight / 2f; - rect.top = centerY - halfCropHeight; - rect.bottom = centerY + halfCropHeight; - } - } else { - // Initialize crop window to have 10% padding w/ respect to image. - rect.left = leftLimit + horizontalPadding; - rect.top = topLimit + verticalPadding; - rect.right = rightLimit - horizontalPadding; - rect.bottom = bottomLimit - verticalPadding; - } - - fixCropWindowRectByRules(rect); - - mCropWindowHandler.setRect(rect); - } - - /** - * Fix the given rect to fit into bitmap rect and follow min, max and aspect ratio rules. - */ - private void fixCropWindowRectByRules(RectF rect) { - if (rect.width() < mCropWindowHandler.getMinCropWidth()) { - float adj = (mCropWindowHandler.getMinCropWidth() - rect.width()) / 2; - rect.left -= adj; - rect.right += adj; - } - if (rect.height() < mCropWindowHandler.getMinCropHeight()) { - float adj = (mCropWindowHandler.getMinCropHeight() - rect.height()) / 2; - rect.top -= adj; - rect.bottom += adj; - } - if (rect.width() > mCropWindowHandler.getMaxCropWidth()) { - float adj = (rect.width() - mCropWindowHandler.getMaxCropWidth()) / 2; - rect.left += adj; - rect.right -= adj; - } - if (rect.height() > mCropWindowHandler.getMaxCropHeight()) { - float adj = (rect.height() - mCropWindowHandler.getMaxCropHeight()) / 2; - rect.top += adj; - rect.bottom -= adj; - } - - calculateBounds(rect); - if (mCalcBounds.width() > 0 && mCalcBounds.height() > 0) { - float leftLimit = Math.max(mCalcBounds.left, 0); - float topLimit = Math.max(mCalcBounds.top, 0); - float rightLimit = Math.min(mCalcBounds.right, getWidth()); - float bottomLimit = Math.min(mCalcBounds.bottom, getHeight()); - if (rect.left < leftLimit) { - rect.left = leftLimit; - } - if (rect.top < topLimit) { - rect.top = topLimit; - } - if (rect.right > rightLimit) { - rect.right = rightLimit; - } - if (rect.bottom > bottomLimit) { - rect.bottom = bottomLimit; - } - } - if (mFixAspectRatio && Math.abs(rect.width() - rect.height() * mTargetAspectRatio) > 0.1) { - if (rect.width() > rect.height() * mTargetAspectRatio) { - float adj = Math.abs(rect.height() * mTargetAspectRatio - rect.width()) / 2; - rect.left += adj; - rect.right -= adj; - } else { - float adj = Math.abs(rect.width() / mTargetAspectRatio - rect.height()) / 2; - rect.top += adj; - rect.bottom -= adj; - } - } - } - - /** - * Draw crop overview by drawing background over image not in the cripping area, then borders and - * guidelines. - */ - @Override - protected void onDraw(Canvas canvas) { - - super.onDraw(canvas); - - // Draw translucent background for the cropped area. - drawBackground(canvas); - - if (mCropWindowHandler.showGuidelines()) { - // Determines whether guidelines should be drawn or not - if (mGuidelines == CropImageView.Guidelines.ON) { - drawGuidelines(canvas); - } else if (mGuidelines == CropImageView.Guidelines.ON_TOUCH && mMoveHandler != null) { - // Draw only when resizing - drawGuidelines(canvas); - } - } - - drawBorders(canvas); - - drawCorners(canvas); - } - - /** - * Draw shadow background over the image not including the crop area. - */ - private void drawBackground(Canvas canvas) { - - RectF rect = mCropWindowHandler.getRect(); - - float left = Math.max(BitmapUtils.getRectLeft(mBoundsPoints), 0); - float top = Math.max(BitmapUtils.getRectTop(mBoundsPoints), 0); - float right = Math.min(BitmapUtils.getRectRight(mBoundsPoints), getWidth()); - float bottom = Math.min(BitmapUtils.getRectBottom(mBoundsPoints), getHeight()); - - if (mCropShape == CropImageView.CropShape.RECTANGLE) { - if (!isNonStraightAngleRotated() || Build.VERSION.SDK_INT <= 17) { - canvas.drawRect(left, top, right, rect.top, mBackgroundPaint); - canvas.drawRect(left, rect.bottom, right, bottom, mBackgroundPaint); - canvas.drawRect(left, rect.top, rect.left, rect.bottom, mBackgroundPaint); - canvas.drawRect(rect.right, rect.top, right, rect.bottom, mBackgroundPaint); - } else { - mPath.reset(); - mPath.moveTo(mBoundsPoints[0], mBoundsPoints[1]); - mPath.lineTo(mBoundsPoints[2], mBoundsPoints[3]); - mPath.lineTo(mBoundsPoints[4], mBoundsPoints[5]); - mPath.lineTo(mBoundsPoints[6], mBoundsPoints[7]); - mPath.close(); - - canvas.save(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - canvas.clipOutPath(mPath); - } else { - canvas.clipPath(mPath, Region.Op.INTERSECT); - } - canvas.clipRect(rect, Region.Op.XOR); - canvas.drawRect(left, top, right, bottom, mBackgroundPaint); - canvas.restore(); - } - } else { - mPath.reset(); - if (Build.VERSION.SDK_INT <= 17 && mCropShape == CropImageView.CropShape.OVAL) { - mDrawRect.set(rect.left + 2, rect.top + 2, rect.right - 2, rect.bottom - 2); - } else { - mDrawRect.set(rect.left, rect.top, rect.right, rect.bottom); - } - mPath.addOval(mDrawRect, Path.Direction.CW); - canvas.save(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - canvas.clipOutPath(mPath); - } else { - canvas.clipPath(mPath, Region.Op.XOR); - } - canvas.drawRect(left, top, right, bottom, mBackgroundPaint); - canvas.restore(); - } - } - - /** - * Draw 2 veritcal and 2 horizontal guidelines inside the cropping area to split it into 9 equal - * parts. - */ - private void drawGuidelines(Canvas canvas) { - if (mGuidelinePaint != null) { - float sw = mBorderPaint != null ? mBorderPaint.getStrokeWidth() : 0; - RectF rect = mCropWindowHandler.getRect(); - rect.inset(sw, sw); - - float oneThirdCropWidth = rect.width() / 3; - float oneThirdCropHeight = rect.height() / 3; - - if (mCropShape == CropImageView.CropShape.OVAL) { - - float w = rect.width() / 2 - sw; - float h = rect.height() / 2 - sw; - - // Draw vertical guidelines. - float x1 = rect.left + oneThirdCropWidth; - float x2 = rect.right - oneThirdCropWidth; - float yv = (float) (h * Math.sin(Math.acos((w - oneThirdCropWidth) / w))); - canvas.drawLine(x1, rect.top + h - yv, x1, rect.bottom - h + yv, mGuidelinePaint); - canvas.drawLine(x2, rect.top + h - yv, x2, rect.bottom - h + yv, mGuidelinePaint); - - // Draw horizontal guidelines. - float y1 = rect.top + oneThirdCropHeight; - float y2 = rect.bottom - oneThirdCropHeight; - float xv = (float) (w * Math.cos(Math.asin((h - oneThirdCropHeight) / h))); - canvas.drawLine(rect.left + w - xv, y1, rect.right - w + xv, y1, mGuidelinePaint); - canvas.drawLine(rect.left + w - xv, y2, rect.right - w + xv, y2, mGuidelinePaint); - } else { - - // Draw vertical guidelines. - float x1 = rect.left + oneThirdCropWidth; - float x2 = rect.right - oneThirdCropWidth; - canvas.drawLine(x1, rect.top, x1, rect.bottom, mGuidelinePaint); - canvas.drawLine(x2, rect.top, x2, rect.bottom, mGuidelinePaint); - - // Draw horizontal guidelines. - float y1 = rect.top + oneThirdCropHeight; - float y2 = rect.bottom - oneThirdCropHeight; - canvas.drawLine(rect.left, y1, rect.right, y1, mGuidelinePaint); - canvas.drawLine(rect.left, y2, rect.right, y2, mGuidelinePaint); - } - } - } - - /** - * Draw borders of the crop area. - */ - private void drawBorders(Canvas canvas) { - if (mBorderPaint != null) { - float w = mBorderPaint.getStrokeWidth(); - RectF rect = mCropWindowHandler.getRect(); - rect.inset(w / 2, w / 2); - - if (mCropShape == CropImageView.CropShape.RECTANGLE) { - // Draw rectangle crop window border. - canvas.drawRect(rect, mBorderPaint); - } else { - // Draw circular crop window border - canvas.drawOval(rect, mBorderPaint); - } - } - } - - /** - * Draw the corner of crop overlay. - */ - private void drawCorners(Canvas canvas) { - if (mBorderCornerPaint != null) { - - float lineWidth = mBorderPaint != null ? mBorderPaint.getStrokeWidth() : 0; - float cornerWidth = mBorderCornerPaint.getStrokeWidth(); - - // for rectangle crop shape we allow the corners to be offset from the borders - float w = - cornerWidth / 2 - + (mCropShape == CropImageView.CropShape.RECTANGLE ? mBorderCornerOffset : 0); - - RectF rect = mCropWindowHandler.getRect(); - rect.inset(w, w); - - float cornerOffset = (cornerWidth - lineWidth) / 2; - float cornerExtension = cornerWidth / 2 + cornerOffset; - - // Top left - canvas.drawLine( - rect.left - cornerOffset, - rect.top - cornerExtension, - rect.left - cornerOffset, - rect.top + mBorderCornerLength, - mBorderCornerPaint); - canvas.drawLine( - rect.left - cornerExtension, - rect.top - cornerOffset, - rect.left + mBorderCornerLength, - rect.top - cornerOffset, - mBorderCornerPaint); - - // Top right - canvas.drawLine( - rect.right + cornerOffset, - rect.top - cornerExtension, - rect.right + cornerOffset, - rect.top + mBorderCornerLength, - mBorderCornerPaint); - canvas.drawLine( - rect.right + cornerExtension, - rect.top - cornerOffset, - rect.right - mBorderCornerLength, - rect.top - cornerOffset, - mBorderCornerPaint); - - // Bottom left - canvas.drawLine( - rect.left - cornerOffset, - rect.bottom + cornerExtension, - rect.left - cornerOffset, - rect.bottom - mBorderCornerLength, - mBorderCornerPaint); - canvas.drawLine( - rect.left - cornerExtension, - rect.bottom + cornerOffset, - rect.left + mBorderCornerLength, - rect.bottom + cornerOffset, - mBorderCornerPaint); - - // Bottom left - canvas.drawLine( - rect.right + cornerOffset, - rect.bottom + cornerExtension, - rect.right + cornerOffset, - rect.bottom - mBorderCornerLength, - mBorderCornerPaint); - canvas.drawLine( - rect.right + cornerExtension, - rect.bottom + cornerOffset, - rect.right - mBorderCornerLength, - rect.bottom + cornerOffset, - mBorderCornerPaint); - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - // If this View is not enabled, don't allow for touch interactions. - if (isEnabled()) { - if (mMultiTouchEnabled) { - mScaleDetector.onTouchEvent(event); - } - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - onActionDown(event.getX(), event.getY()); - return true; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - getParent().requestDisallowInterceptTouchEvent(false); - onActionUp(); - return true; - case MotionEvent.ACTION_MOVE: - onActionMove(event.getX(), event.getY()); - getParent().requestDisallowInterceptTouchEvent(true); - return true; - default: - return false; - } - } else { - return false; - } - } - - /** - * On press down start crop window movment depending on the location of the press.
- * if press is far from crop window then no move handler is returned (null). - */ - private void onActionDown(float x, float y) { - mMoveHandler = mCropWindowHandler.getMoveHandler(x, y, mTouchRadius, mCropShape); - if (mMoveHandler != null) { - invalidate(); - } - } - - /** - * Clear move handler starting in {@link #onActionDown(float, float)} if exists. - */ - private void onActionUp() { - if (mMoveHandler != null) { - mMoveHandler = null; - callOnCropWindowChanged(false); - invalidate(); - } - } - - /** - * Handle move of crop window using the move handler created in {@link #onActionDown(float, - * float)}.
- * The move handler will do the proper move/resize of the crop window. - */ - private void onActionMove(float x, float y) { - if (mMoveHandler != null) { - float snapRadius = mSnapRadius; - RectF rect = mCropWindowHandler.getRect(); - - if (calculateBounds(rect)) { - snapRadius = 0; - } - - mMoveHandler.move( - rect, - x, - y, - mCalcBounds, - mViewWidth, - mViewHeight, - snapRadius, - mFixAspectRatio, - mTargetAspectRatio); - mCropWindowHandler.setRect(rect); - callOnCropWindowChanged(true); - invalidate(); - } - } - - /** - * Calculate the bounding rectangle for current crop window, handle non-straight rotation angles. - *
- * If the rotation angle is straight then the bounds rectangle is the bitmap rectangle, otherwsie - * we find the max rectangle that is within the image bounds starting from the crop window - * rectangle. - * - * @param rect the crop window rectangle to start finsing bounded rectangle from - * @return true - non straight rotation in place, false - otherwise. - */ - private boolean calculateBounds(RectF rect) { - - float left = BitmapUtils.getRectLeft(mBoundsPoints); - float top = BitmapUtils.getRectTop(mBoundsPoints); - float right = BitmapUtils.getRectRight(mBoundsPoints); - float bottom = BitmapUtils.getRectBottom(mBoundsPoints); - - if (!isNonStraightAngleRotated()) { - mCalcBounds.set(left, top, right, bottom); - return false; - } else { - float x0 = mBoundsPoints[0]; - float y0 = mBoundsPoints[1]; - float x2 = mBoundsPoints[4]; - float y2 = mBoundsPoints[5]; - float x3 = mBoundsPoints[6]; - float y3 = mBoundsPoints[7]; - - if (mBoundsPoints[7] < mBoundsPoints[1]) { - if (mBoundsPoints[1] < mBoundsPoints[3]) { - x0 = mBoundsPoints[6]; - y0 = mBoundsPoints[7]; - x2 = mBoundsPoints[2]; - y2 = mBoundsPoints[3]; - x3 = mBoundsPoints[4]; - y3 = mBoundsPoints[5]; - } else { - x0 = mBoundsPoints[4]; - y0 = mBoundsPoints[5]; - x2 = mBoundsPoints[0]; - y2 = mBoundsPoints[1]; - x3 = mBoundsPoints[2]; - y3 = mBoundsPoints[3]; - } - } else if (mBoundsPoints[1] > mBoundsPoints[3]) { - x0 = mBoundsPoints[2]; - y0 = mBoundsPoints[3]; - x2 = mBoundsPoints[6]; - y2 = mBoundsPoints[7]; - x3 = mBoundsPoints[0]; - y3 = mBoundsPoints[1]; - } - - float a0 = (y3 - y0) / (x3 - x0); - float a1 = -1f / a0; - float b0 = y0 - a0 * x0; - float b1 = y0 - a1 * x0; - float b2 = y2 - a0 * x2; - float b3 = y2 - a1 * x2; - - float c0 = (rect.centerY() - rect.top) / (rect.centerX() - rect.left); - float c1 = -c0; - float d0 = rect.top - c0 * rect.left; - float d1 = rect.top - c1 * rect.right; - - left = Math.max(left, (d0 - b0) / (a0 - c0) < rect.right ? (d0 - b0) / (a0 - c0) : left); - left = Math.max(left, (d0 - b1) / (a1 - c0) < rect.right ? (d0 - b1) / (a1 - c0) : left); - left = Math.max(left, (d1 - b3) / (a1 - c1) < rect.right ? (d1 - b3) / (a1 - c1) : left); - right = Math.min(right, (d1 - b1) / (a1 - c1) > rect.left ? (d1 - b1) / (a1 - c1) : right); - right = Math.min(right, (d1 - b2) / (a0 - c1) > rect.left ? (d1 - b2) / (a0 - c1) : right); - right = Math.min(right, (d0 - b2) / (a0 - c0) > rect.left ? (d0 - b2) / (a0 - c0) : right); - - top = Math.max(top, Math.max(a0 * left + b0, a1 * right + b1)); - bottom = Math.min(bottom, Math.min(a1 * left + b3, a0 * right + b2)); - - mCalcBounds.left = left; - mCalcBounds.top = top; - mCalcBounds.right = right; - mCalcBounds.bottom = bottom; - return true; - } - } - - /** - * Is the cropping image has been rotated by NOT 0,90,180 or 270 degrees. - */ - private boolean isNonStraightAngleRotated() { - return mBoundsPoints[0] != mBoundsPoints[6] && mBoundsPoints[1] != mBoundsPoints[7]; - } - - /** - * Invoke on crop change listener safe, don't let the app crash on exception. - */ - private void callOnCropWindowChanged(boolean inProgress) { - try { - if (mCropWindowChangeListener != null) { - mCropWindowChangeListener.onCropWindowChanged(inProgress); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - // endregion - - // region: Inner class: CropWindowChangeListener - - /** - * Interface definition for a callback to be invoked when crop window rectangle is changing. - */ - public interface CropWindowChangeListener { - - /** - * Called after a change in crop window rectangle. - * - * @param inProgress is the crop window change operation is still in progress by user touch - */ - void onCropWindowChanged(boolean inProgress); - } - // endregion - - // region: Inner class: ScaleListener - - /** - * Handle scaling the rectangle based on two finger input - */ - private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - - @Override - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public boolean onScale(ScaleGestureDetector detector) { - RectF rect = mCropWindowHandler.getRect(); - - float x = detector.getFocusX(); - float y = detector.getFocusY(); - float dY = detector.getCurrentSpanY() / 2; - float dX = detector.getCurrentSpanX() / 2; - - float newTop = y - dY; - float newLeft = x - dX; - float newRight = x + dX; - float newBottom = y + dY; - - if (newLeft < newRight - && newTop <= newBottom - && newLeft >= 0 - && newRight <= mCropWindowHandler.getMaxCropWidth() - && newTop >= 0 - && newBottom <= mCropWindowHandler.getMaxCropHeight()) { - - rect.set(newLeft, newTop, newRight, newBottom); - mCropWindowHandler.setRect(rect); - invalidate(); - } - - return true; - } - } - // endregion -} diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropWindowHandler.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropWindowHandler.java deleted file mode 100644 index d9785531..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropWindowHandler.java +++ /dev/null @@ -1,405 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth, -// inexhaustible as the great rivers. -// When they come to an end, -// they begin again, -// like the days and months; -// they die and are reborn, -// like the four seasons." -// -// - Sun Tsu, -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.graphics.RectF; - -/** - * Handler from crop window stuff, moving and knowing possition. - */ -final class CropWindowHandler { - - // region: Fields and Consts - - /** - * The 4 edges of the crop window defining its coordinates and size - */ - private final RectF mEdges = new RectF(); - - /** - * Rectangle used to return the edges rectangle without ability to change it and without creating - * new all the time. - */ - private final RectF mGetEdges = new RectF(); - - /** - * Minimum width in pixels that the crop window can get. - */ - private float mMinCropWindowWidth; - - /** - * Minimum height in pixels that the crop window can get. - */ - private float mMinCropWindowHeight; - - /** - * Maximum width in pixels that the crop window can CURRENTLY get. - */ - private float mMaxCropWindowWidth; - - /** - * Maximum height in pixels that the crop window can CURRENTLY get. - */ - private float mMaxCropWindowHeight; - - /** - * Minimum width in pixels that the result of cropping an image can get, affects crop window width - * adjusted by width scale factor. - */ - private float mMinCropResultWidth; - - /** - * Minimum height in pixels that the result of cropping an image can get, affects crop window - * height adjusted by height scale factor. - */ - private float mMinCropResultHeight; - - /** - * Maximum width in pixels that the result of cropping an image can get, affects crop window width - * adjusted by width scale factor. - */ - private float mMaxCropResultWidth; - - /** - * Maximum height in pixels that the result of cropping an image can get, affects crop window - * height adjusted by height scale factor. - */ - private float mMaxCropResultHeight; - - /** - * The width scale factor of shown image and actual image - */ - private float mScaleFactorWidth = 1; - - /** - * The height scale factor of shown image and actual image - */ - private float mScaleFactorHeight = 1; - // endregion - - /** - * Determines if the specified coordinate is in the target touch zone for a corner handle. - * - * @param x the x-coordinate of the touch point - * @param y the y-coordinate of the touch point - * @param handleX the x-coordinate of the corner handle - * @param handleY the y-coordinate of the corner handle - * @param targetRadius the target radius in pixels - * @return true if the touch point is in the target touch zone; false otherwise - */ - private static boolean isInCornerTargetZone( - float x, float y, float handleX, float handleY, float targetRadius) { - return Math.abs(x - handleX) <= targetRadius && Math.abs(y - handleY) <= targetRadius; - } - - /** - * Determines if the specified coordinate is in the target touch zone for a horizontal bar handle. - * - * @param x the x-coordinate of the touch point - * @param y the y-coordinate of the touch point - * @param handleXStart the left x-coordinate of the horizontal bar handle - * @param handleXEnd the right x-coordinate of the horizontal bar handle - * @param handleY the y-coordinate of the horizontal bar handle - * @param targetRadius the target radius in pixels - * @return true if the touch point is in the target touch zone; false otherwise - */ - private static boolean isInHorizontalTargetZone( - float x, float y, float handleXStart, float handleXEnd, float handleY, float targetRadius) { - return x > handleXStart && x < handleXEnd && Math.abs(y - handleY) <= targetRadius; - } - - /** - * Determines if the specified coordinate is in the target touch zone for a vertical bar handle. - * - * @param x the x-coordinate of the touch point - * @param y the y-coordinate of the touch point - * @param handleX the x-coordinate of the vertical bar handle - * @param handleYStart the top y-coordinate of the vertical bar handle - * @param handleYEnd the bottom y-coordinate of the vertical bar handle - * @param targetRadius the target radius in pixels - * @return true if the touch point is in the target touch zone; false otherwise - */ - private static boolean isInVerticalTargetZone( - float x, float y, float handleX, float handleYStart, float handleYEnd, float targetRadius) { - return Math.abs(x - handleX) <= targetRadius && y > handleYStart && y < handleYEnd; - } - - /** - * Determines if the specified coordinate falls anywhere inside the given bounds. - * - * @param x the x-coordinate of the touch point - * @param y the y-coordinate of the touch point - * @param left the x-coordinate of the left bound - * @param top the y-coordinate of the top bound - * @param right the x-coordinate of the right bound - * @param bottom the y-coordinate of the bottom bound - * @return true if the touch point is inside the bounding rectangle; false otherwise - */ - private static boolean isInCenterTargetZone( - float x, float y, float left, float top, float right, float bottom) { - return x > left && x < right && y > top && y < bottom; - } - - /** - * Get the left/top/right/bottom coordinates of the crop window. - */ - public RectF getRect() { - mGetEdges.set(mEdges); - return mGetEdges; - } - - /** - * Set the left/top/right/bottom coordinates of the crop window. - */ - public void setRect(RectF rect) { - mEdges.set(rect); - } - - /** - * Minimum width in pixels that the crop window can get. - */ - public float getMinCropWidth() { - return Math.max(mMinCropWindowWidth, mMinCropResultWidth / mScaleFactorWidth); - } - - /** - * Minimum height in pixels that the crop window can get. - */ - public float getMinCropHeight() { - return Math.max(mMinCropWindowHeight, mMinCropResultHeight / mScaleFactorHeight); - } - - /** - * Maximum width in pixels that the crop window can get. - */ - public float getMaxCropWidth() { - return Math.min(mMaxCropWindowWidth, mMaxCropResultWidth / mScaleFactorWidth); - } - - /** - * Maximum height in pixels that the crop window can get. - */ - public float getMaxCropHeight() { - return Math.min(mMaxCropWindowHeight, mMaxCropResultHeight / mScaleFactorHeight); - } - - /** - * get the scale factor (on width) of the showen image to original image. - */ - public float getScaleFactorWidth() { - return mScaleFactorWidth; - } - - /** - * get the scale factor (on height) of the showen image to original image. - */ - public float getScaleFactorHeight() { - return mScaleFactorHeight; - } - - /** - * the min size the resulting cropping image is allowed to be, affects the cropping window limits - * (in pixels).
- */ - public void setMinCropResultSize(int minCropResultWidth, int minCropResultHeight) { - mMinCropResultWidth = minCropResultWidth; - mMinCropResultHeight = minCropResultHeight; - } - - /** - * the max size the resulting cropping image is allowed to be, affects the cropping window limits - * (in pixels).
- */ - public void setMaxCropResultSize(int maxCropResultWidth, int maxCropResultHeight) { - mMaxCropResultWidth = maxCropResultWidth; - mMaxCropResultHeight = maxCropResultHeight; - } - - // region: Private methods - - /** - * set the max width/height and scale factor of the showen image to original image to scale the - * limits appropriately. - */ - public void setCropWindowLimits( - float maxWidth, float maxHeight, float scaleFactorWidth, float scaleFactorHeight) { - mMaxCropWindowWidth = maxWidth; - mMaxCropWindowHeight = maxHeight; - mScaleFactorWidth = scaleFactorWidth; - mScaleFactorHeight = scaleFactorHeight; - } - - /** - * Set the variables to be used during crop window handling. - */ - public void setInitialAttributeValues(CropImageOptions options) { - mMinCropWindowWidth = options.minCropWindowWidth; - mMinCropWindowHeight = options.minCropWindowHeight; - mMinCropResultWidth = options.minCropResultWidth; - mMinCropResultHeight = options.minCropResultHeight; - mMaxCropResultWidth = options.maxCropResultWidth; - mMaxCropResultHeight = options.maxCropResultHeight; - } - - /** - * Indicates whether the crop window is small enough that the guidelines should be shown. Public - * because this function is also used to determine if the center handle should be focused. - * - * @return boolean Whether the guidelines should be shown or not - */ - public boolean showGuidelines() { - return !(mEdges.width() < 100 || mEdges.height() < 100); - } - - /** - * Determines which, if any, of the handles are pressed given the touch coordinates, the bounding - * box, and the touch radius. - * - * @param x the x-coordinate of the touch point - * @param y the y-coordinate of the touch point - * @param targetRadius the target radius in pixels - * @return the Handle that was pressed; null if no Handle was pressed - */ - public CropWindowMoveHandler getMoveHandler( - float x, float y, float targetRadius, CropImageView.CropShape cropShape) { - CropWindowMoveHandler.Type type = - cropShape == CropImageView.CropShape.OVAL - ? getOvalPressedMoveType(x, y) - : getRectanglePressedMoveType(x, y, targetRadius); - return type != null ? new CropWindowMoveHandler(type, this, x, y) : null; - } - - /** - * Determines which, if any, of the handles are pressed given the touch coordinates, the bounding - * box, and the touch radius. - * - * @param x the x-coordinate of the touch point - * @param y the y-coordinate of the touch point - * @param targetRadius the target radius in pixels - * @return the Handle that was pressed; null if no Handle was pressed - */ - private CropWindowMoveHandler.Type getRectanglePressedMoveType( - float x, float y, float targetRadius) { - CropWindowMoveHandler.Type moveType = null; - - // Note: corner-handles take precedence, then side-handles, then center. - if (CropWindowHandler.isInCornerTargetZone(x, y, mEdges.left, mEdges.top, targetRadius)) { - moveType = CropWindowMoveHandler.Type.TOP_LEFT; - } else if (CropWindowHandler.isInCornerTargetZone( - x, y, mEdges.right, mEdges.top, targetRadius)) { - moveType = CropWindowMoveHandler.Type.TOP_RIGHT; - } else if (CropWindowHandler.isInCornerTargetZone( - x, y, mEdges.left, mEdges.bottom, targetRadius)) { - moveType = CropWindowMoveHandler.Type.BOTTOM_LEFT; - } else if (CropWindowHandler.isInCornerTargetZone( - x, y, mEdges.right, mEdges.bottom, targetRadius)) { - moveType = CropWindowMoveHandler.Type.BOTTOM_RIGHT; - } else if (CropWindowHandler.isInCenterTargetZone( - x, y, mEdges.left, mEdges.top, mEdges.right, mEdges.bottom) - && focusCenter()) { - moveType = CropWindowMoveHandler.Type.CENTER; - } else if (CropWindowHandler.isInHorizontalTargetZone( - x, y, mEdges.left, mEdges.right, mEdges.top, targetRadius)) { - moveType = CropWindowMoveHandler.Type.TOP; - } else if (CropWindowHandler.isInHorizontalTargetZone( - x, y, mEdges.left, mEdges.right, mEdges.bottom, targetRadius)) { - moveType = CropWindowMoveHandler.Type.BOTTOM; - } else if (CropWindowHandler.isInVerticalTargetZone( - x, y, mEdges.left, mEdges.top, mEdges.bottom, targetRadius)) { - moveType = CropWindowMoveHandler.Type.LEFT; - } else if (CropWindowHandler.isInVerticalTargetZone( - x, y, mEdges.right, mEdges.top, mEdges.bottom, targetRadius)) { - moveType = CropWindowMoveHandler.Type.RIGHT; - } else if (CropWindowHandler.isInCenterTargetZone( - x, y, mEdges.left, mEdges.top, mEdges.right, mEdges.bottom) - && !focusCenter()) { - moveType = CropWindowMoveHandler.Type.CENTER; - } - - return moveType; - } - - /** - * Determines which, if any, of the handles are pressed given the touch coordinates, the bounding - * box/oval, and the touch radius. - * - * @param x the x-coordinate of the touch point - * @param y the y-coordinate of the touch point - * @return the Handle that was pressed; null if no Handle was pressed - */ - private CropWindowMoveHandler.Type getOvalPressedMoveType(float x, float y) { - - /* - Use a 6x6 grid system divided into 9 "handles", with the center the biggest region. While - this is not perfect, it's a good quick-to-ship approach. - - TL T T T T TR - L C C C C R - L C C C C R - L C C C C R - L C C C C R - BL B B B B BR - */ - - float cellLength = mEdges.width() / 6; - float leftCenter = mEdges.left + cellLength; - float rightCenter = mEdges.left + (5 * cellLength); - - float cellHeight = mEdges.height() / 6; - float topCenter = mEdges.top + cellHeight; - float bottomCenter = mEdges.top + 5 * cellHeight; - - CropWindowMoveHandler.Type moveType; - if (x < leftCenter) { - if (y < topCenter) { - moveType = CropWindowMoveHandler.Type.TOP_LEFT; - } else if (y < bottomCenter) { - moveType = CropWindowMoveHandler.Type.LEFT; - } else { - moveType = CropWindowMoveHandler.Type.BOTTOM_LEFT; - } - } else if (x < rightCenter) { - if (y < topCenter) { - moveType = CropWindowMoveHandler.Type.TOP; - } else if (y < bottomCenter) { - moveType = CropWindowMoveHandler.Type.CENTER; - } else { - moveType = CropWindowMoveHandler.Type.BOTTOM; - } - } else { - if (y < topCenter) { - moveType = CropWindowMoveHandler.Type.TOP_RIGHT; - } else if (y < bottomCenter) { - moveType = CropWindowMoveHandler.Type.RIGHT; - } else { - moveType = CropWindowMoveHandler.Type.BOTTOM_RIGHT; - } - } - - return moveType; - } - - /** - * Determines if the cropper should focus on the center handle or the side handles. If it is a - * small image, focus on the center handle so the user can move it. If it is a large image, focus - * on the side handles so user can grab them. Corresponds to the appearance of the - * RuleOfThirdsGuidelines. - * - * @return true if it is small enough such that it should focus on the center; less than - * show_guidelines limit - */ - private boolean focusCenter() { - return !showGuidelines(); - } - // endregion -} diff --git a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropWindowMoveHandler.java b/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropWindowMoveHandler.java deleted file mode 100644 index 0f1eaab4..00000000 --- a/cropper/src/main/java/com/theartofdev/edmodo/cropper/CropWindowMoveHandler.java +++ /dev/null @@ -1,786 +0,0 @@ -// "Therefore those skilled at the unorthodox -// are infinite as heaven and earth, -// inexhaustible as the great rivers. -// When they come to an end, -// they begin again, -// like the days and months; -// they die and are reborn, -// like the four seasons." -// -// - Sun Tsu, -// "The Art of War" - -package com.theartofdev.edmodo.cropper; - -import android.graphics.Matrix; -import android.graphics.PointF; -import android.graphics.RectF; - -/** - * Handler to update crop window edges by the move type - Horizontal, Vertical, Corner or Center. - *
- */ -final class CropWindowMoveHandler { - - // region: Fields and Consts - - /** - * Matrix used for rectangle rotation handling - */ - private static final Matrix MATRIX = new Matrix(); - - /** - * Minimum width in pixels that the crop window can get. - */ - private final float mMinCropWidth; - - /** - * Minimum width in pixels that the crop window can get. - */ - private final float mMinCropHeight; - - /** - * Maximum height in pixels that the crop window can get. - */ - private final float mMaxCropWidth; - - /** - * Maximum height in pixels that the crop window can get. - */ - private final float mMaxCropHeight; - - /** - * The type of crop window move that is handled. - */ - private final Type mType; - - /** - * Holds the x and y offset between the exact touch location and the exact handle location that is - * activated. There may be an offset because we allow for some leeway (specified by mHandleRadius) - * in activating a handle. However, we want to maintain these offset values while the handle is - * being dragged so that the handle doesn't jump. - */ - private final PointF mTouchOffset = new PointF(); - // endregion - - /** - * @param edgeMoveType the type of move this handler is executing - * @param horizontalEdge the primary edge associated with this handle; may be null - * @param verticalEdge the secondary edge associated with this handle; may be null - * @param cropWindowHandler main crop window handle to get and update the crop window edges - * @param touchX the location of the initial toch possition to measure move distance - * @param touchY the location of the initial toch possition to measure move distance - */ - public CropWindowMoveHandler( - Type type, CropWindowHandler cropWindowHandler, float touchX, float touchY) { - mType = type; - mMinCropWidth = cropWindowHandler.getMinCropWidth(); - mMinCropHeight = cropWindowHandler.getMinCropHeight(); - mMaxCropWidth = cropWindowHandler.getMaxCropWidth(); - mMaxCropHeight = cropWindowHandler.getMaxCropHeight(); - calculateTouchOffset(cropWindowHandler.getRect(), touchX, touchY); - } - - /** - * Calculates the aspect ratio given a rectangle. - */ - private static float calculateAspectRatio(float left, float top, float right, float bottom) { - return (right - left) / (bottom - top); - } - - // region: Private methods - - /** - * Updates the crop window by change in the toch location.
- * Move type handled by this instance, as initialized in creation, affects how the change in toch - * location changes the crop window position and size.
- * After the crop window position/size is changed by toch move it may result in values that - * vialate contraints: outside the bounds of the shown bitmap, smaller/larger than min/max size or - * missmatch in aspect ratio. So a series of fixes is executed on "secondary" edges to adjust it - * by the "primary" edge movement.
- * Primary is the edge directly affected by move type, secondary is the other edge.
- * The crop window is changed by directly setting the Edge coordinates. - * - * @param x the new x-coordinate of this handle - * @param y the new y-coordinate of this handle - * @param bounds the bounding rectangle of the image - * @param viewWidth The bounding image view width used to know the crop overlay is at view edges. - * @param viewHeight The bounding image view height used to know the crop overlay is at view - * edges. - * @param parentView the parent View containing the image - * @param snapMargin the maximum distance (in pixels) at which the crop window should snap to the - * image - * @param fixedAspectRatio is the aspect ration fixed and 'targetAspectRatio' should be used - * @param aspectRatio the aspect ratio to maintain - */ - public void move( - RectF rect, - float x, - float y, - RectF bounds, - int viewWidth, - int viewHeight, - float snapMargin, - boolean fixedAspectRatio, - float aspectRatio) { - - // Adjust the coordinates for the finger position's offset (i.e. the - // distance from the initial touch to the precise handle location). - // We want to maintain the initial touch's distance to the pressed - // handle so that the crop window size does not "jump". - float adjX = x + mTouchOffset.x; - float adjY = y + mTouchOffset.y; - - if (mType == Type.CENTER) { - moveCenter(rect, adjX, adjY, bounds, viewWidth, viewHeight, snapMargin); - } else { - if (fixedAspectRatio) { - moveSizeWithFixedAspectRatio( - rect, adjX, adjY, bounds, viewWidth, viewHeight, snapMargin, aspectRatio); - } else { - moveSizeWithFreeAspectRatio(rect, adjX, adjY, bounds, viewWidth, viewHeight, snapMargin); - } - } - } - - /** - * Calculates the offset of the touch point from the precise location of the specified handle.
- * Save these values in a member variable since we want to maintain this offset as we drag the - * handle. - */ - private void calculateTouchOffset(RectF rect, float touchX, float touchY) { - - float touchOffsetX = 0; - float touchOffsetY = 0; - - // Calculate the offset from the appropriate handle. - switch (mType) { - case TOP_LEFT: - touchOffsetX = rect.left - touchX; - touchOffsetY = rect.top - touchY; - break; - case TOP_RIGHT: - touchOffsetX = rect.right - touchX; - touchOffsetY = rect.top - touchY; - break; - case BOTTOM_LEFT: - touchOffsetX = rect.left - touchX; - touchOffsetY = rect.bottom - touchY; - break; - case BOTTOM_RIGHT: - touchOffsetX = rect.right - touchX; - touchOffsetY = rect.bottom - touchY; - break; - case LEFT: - touchOffsetX = rect.left - touchX; - touchOffsetY = 0; - break; - case TOP: - touchOffsetX = 0; - touchOffsetY = rect.top - touchY; - break; - case RIGHT: - touchOffsetX = rect.right - touchX; - touchOffsetY = 0; - break; - case BOTTOM: - touchOffsetX = 0; - touchOffsetY = rect.bottom - touchY; - break; - case CENTER: - touchOffsetX = rect.centerX() - touchX; - touchOffsetY = rect.centerY() - touchY; - break; - default: - break; - } - - mTouchOffset.x = touchOffsetX; - mTouchOffset.y = touchOffsetY; - } - - /** - * Center move only changes the position of the crop window without changing the size. - */ - private void moveCenter( - RectF rect, float x, float y, RectF bounds, int viewWidth, int viewHeight, float snapRadius) { - float dx = x - rect.centerX(); - float dy = y - rect.centerY(); - if (rect.left + dx < 0 - || rect.right + dx > viewWidth - || rect.left + dx < bounds.left - || rect.right + dx > bounds.right) { - dx /= 1.05f; - mTouchOffset.x -= dx / 2; - } - if (rect.top + dy < 0 - || rect.bottom + dy > viewHeight - || rect.top + dy < bounds.top - || rect.bottom + dy > bounds.bottom) { - dy /= 1.05f; - mTouchOffset.y -= dy / 2; - } - rect.offset(dx, dy); - snapEdgesToBounds(rect, bounds, snapRadius); - } - - /** - * Change the size of the crop window on the required edge (or edges for corner size move) without - * affecting "secondary" edges.
- * Only the primary edge(s) are fixed to stay within limits. - */ - private void moveSizeWithFreeAspectRatio( - RectF rect, float x, float y, RectF bounds, int viewWidth, int viewHeight, float snapMargin) { - switch (mType) { - case TOP_LEFT: - adjustTop(rect, y, bounds, snapMargin, 0, false, false); - adjustLeft(rect, x, bounds, snapMargin, 0, false, false); - break; - case TOP_RIGHT: - adjustTop(rect, y, bounds, snapMargin, 0, false, false); - adjustRight(rect, x, bounds, viewWidth, snapMargin, 0, false, false); - break; - case BOTTOM_LEFT: - adjustBottom(rect, y, bounds, viewHeight, snapMargin, 0, false, false); - adjustLeft(rect, x, bounds, snapMargin, 0, false, false); - break; - case BOTTOM_RIGHT: - adjustBottom(rect, y, bounds, viewHeight, snapMargin, 0, false, false); - adjustRight(rect, x, bounds, viewWidth, snapMargin, 0, false, false); - break; - case LEFT: - adjustLeft(rect, x, bounds, snapMargin, 0, false, false); - break; - case TOP: - adjustTop(rect, y, bounds, snapMargin, 0, false, false); - break; - case RIGHT: - adjustRight(rect, x, bounds, viewWidth, snapMargin, 0, false, false); - break; - case BOTTOM: - adjustBottom(rect, y, bounds, viewHeight, snapMargin, 0, false, false); - break; - default: - break; - } - } - - /** - * Change the size of the crop window on the required "primary" edge WITH affect to relevant - * "secondary" edge via aspect ratio.
- * Example: change in the left edge (primary) will affect top and bottom edges (secondary) to - * preserve the given aspect ratio. - */ - private void moveSizeWithFixedAspectRatio( - RectF rect, - float x, - float y, - RectF bounds, - int viewWidth, - int viewHeight, - float snapMargin, - float aspectRatio) { - switch (mType) { - case TOP_LEFT: - if (calculateAspectRatio(x, y, rect.right, rect.bottom) < aspectRatio) { - adjustTop(rect, y, bounds, snapMargin, aspectRatio, true, false); - adjustLeftByAspectRatio(rect, aspectRatio); - } else { - adjustLeft(rect, x, bounds, snapMargin, aspectRatio, true, false); - adjustTopByAspectRatio(rect, aspectRatio); - } - break; - case TOP_RIGHT: - if (calculateAspectRatio(rect.left, y, x, rect.bottom) < aspectRatio) { - adjustTop(rect, y, bounds, snapMargin, aspectRatio, false, true); - adjustRightByAspectRatio(rect, aspectRatio); - } else { - adjustRight(rect, x, bounds, viewWidth, snapMargin, aspectRatio, true, false); - adjustTopByAspectRatio(rect, aspectRatio); - } - break; - case BOTTOM_LEFT: - if (calculateAspectRatio(x, rect.top, rect.right, y) < aspectRatio) { - adjustBottom(rect, y, bounds, viewHeight, snapMargin, aspectRatio, true, false); - adjustLeftByAspectRatio(rect, aspectRatio); - } else { - adjustLeft(rect, x, bounds, snapMargin, aspectRatio, false, true); - adjustBottomByAspectRatio(rect, aspectRatio); - } - break; - case BOTTOM_RIGHT: - if (calculateAspectRatio(rect.left, rect.top, x, y) < aspectRatio) { - adjustBottom(rect, y, bounds, viewHeight, snapMargin, aspectRatio, false, true); - adjustRightByAspectRatio(rect, aspectRatio); - } else { - adjustRight(rect, x, bounds, viewWidth, snapMargin, aspectRatio, false, true); - adjustBottomByAspectRatio(rect, aspectRatio); - } - break; - case LEFT: - adjustLeft(rect, x, bounds, snapMargin, aspectRatio, true, true); - adjustTopBottomByAspectRatio(rect, bounds, aspectRatio); - break; - case TOP: - adjustTop(rect, y, bounds, snapMargin, aspectRatio, true, true); - adjustLeftRightByAspectRatio(rect, bounds, aspectRatio); - break; - case RIGHT: - adjustRight(rect, x, bounds, viewWidth, snapMargin, aspectRatio, true, true); - adjustTopBottomByAspectRatio(rect, bounds, aspectRatio); - break; - case BOTTOM: - adjustBottom(rect, y, bounds, viewHeight, snapMargin, aspectRatio, true, true); - adjustLeftRightByAspectRatio(rect, bounds, aspectRatio); - break; - default: - break; - } - } - - /** - * Check if edges have gone out of bounds (including snap margin), and fix if needed. - */ - private void snapEdgesToBounds(RectF edges, RectF bounds, float margin) { - if (edges.left < bounds.left + margin) { - edges.offset(bounds.left - edges.left, 0); - } - if (edges.top < bounds.top + margin) { - edges.offset(0, bounds.top - edges.top); - } - if (edges.right > bounds.right - margin) { - edges.offset(bounds.right - edges.right, 0); - } - if (edges.bottom > bounds.bottom - margin) { - edges.offset(0, bounds.bottom - edges.bottom); - } - } - - /** - * Get the resulting x-position of the left edge of the crop window given the handle's position - * and the image's bounding box and snap radius. - * - * @param left the position that the left edge is dragged to - * @param bounds the bounding box of the image that is being cropped - * @param snapMargin the snap distance to the image edge (in pixels) - */ - private void adjustLeft( - RectF rect, - float left, - RectF bounds, - float snapMargin, - float aspectRatio, - boolean topMoves, - boolean bottomMoves) { - - float newLeft = left; - - if (newLeft < 0) { - newLeft /= 1.05f; - mTouchOffset.x -= newLeft / 1.1f; - } - - if (newLeft < bounds.left) { - mTouchOffset.x -= (newLeft - bounds.left) / 2f; - } - - if (newLeft - bounds.left < snapMargin) { - newLeft = bounds.left; - } - - // Checks if the window is too small horizontally - if (rect.right - newLeft < mMinCropWidth) { - newLeft = rect.right - mMinCropWidth; - } - - // Checks if the window is too large horizontally - if (rect.right - newLeft > mMaxCropWidth) { - newLeft = rect.right - mMaxCropWidth; - } - - if (newLeft - bounds.left < snapMargin) { - newLeft = bounds.left; - } - - // check vertical bounds if aspect ratio is in play - if (aspectRatio > 0) { - float newHeight = (rect.right - newLeft) / aspectRatio; - - // Checks if the window is too small vertically - if (newHeight < mMinCropHeight) { - newLeft = Math.max(bounds.left, rect.right - mMinCropHeight * aspectRatio); - newHeight = (rect.right - newLeft) / aspectRatio; - } - - // Checks if the window is too large vertically - if (newHeight > mMaxCropHeight) { - newLeft = Math.max(bounds.left, rect.right - mMaxCropHeight * aspectRatio); - newHeight = (rect.right - newLeft) / aspectRatio; - } - - // if top AND bottom edge moves by aspect ratio check that it is within full height bounds - if (topMoves && bottomMoves) { - newLeft = - Math.max(newLeft, Math.max(bounds.left, rect.right - bounds.height() * aspectRatio)); - } else { - // if top edge moves by aspect ratio check that it is within bounds - if (topMoves && rect.bottom - newHeight < bounds.top) { - newLeft = Math.max(bounds.left, rect.right - (rect.bottom - bounds.top) * aspectRatio); - newHeight = (rect.right - newLeft) / aspectRatio; - } - - // if bottom edge moves by aspect ratio check that it is within bounds - if (bottomMoves && rect.top + newHeight > bounds.bottom) { - newLeft = - Math.max( - newLeft, - Math.max(bounds.left, rect.right - (bounds.bottom - rect.top) * aspectRatio)); - } - } - } - - rect.left = newLeft; - } - - /** - * Get the resulting x-position of the right edge of the crop window given the handle's position - * and the image's bounding box and snap radius. - * - * @param right the position that the right edge is dragged to - * @param bounds the bounding box of the image that is being cropped - * @param viewWidth - * @param snapMargin the snap distance to the image edge (in pixels) - */ - private void adjustRight( - RectF rect, - float right, - RectF bounds, - int viewWidth, - float snapMargin, - float aspectRatio, - boolean topMoves, - boolean bottomMoves) { - - float newRight = right; - - if (newRight > viewWidth) { - newRight = viewWidth + (newRight - viewWidth) / 1.05f; - mTouchOffset.x -= (newRight - viewWidth) / 1.1f; - } - - if (newRight > bounds.right) { - mTouchOffset.x -= (newRight - bounds.right) / 2f; - } - - // If close to the edge - if (bounds.right - newRight < snapMargin) { - newRight = bounds.right; - } - - // Checks if the window is too small horizontally - if (newRight - rect.left < mMinCropWidth) { - newRight = rect.left + mMinCropWidth; - } - - // Checks if the window is too large horizontally - if (newRight - rect.left > mMaxCropWidth) { - newRight = rect.left + mMaxCropWidth; - } - - // If close to the edge - if (bounds.right - newRight < snapMargin) { - newRight = bounds.right; - } - - // check vertical bounds if aspect ratio is in play - if (aspectRatio > 0) { - float newHeight = (newRight - rect.left) / aspectRatio; - - // Checks if the window is too small vertically - if (newHeight < mMinCropHeight) { - newRight = Math.min(bounds.right, rect.left + mMinCropHeight * aspectRatio); - newHeight = (newRight - rect.left) / aspectRatio; - } - - // Checks if the window is too large vertically - if (newHeight > mMaxCropHeight) { - newRight = Math.min(bounds.right, rect.left + mMaxCropHeight * aspectRatio); - newHeight = (newRight - rect.left) / aspectRatio; - } - - // if top AND bottom edge moves by aspect ratio check that it is within full height bounds - if (topMoves && bottomMoves) { - newRight = - Math.min(newRight, Math.min(bounds.right, rect.left + bounds.height() * aspectRatio)); - } else { - // if top edge moves by aspect ratio check that it is within bounds - if (topMoves && rect.bottom - newHeight < bounds.top) { - newRight = Math.min(bounds.right, rect.left + (rect.bottom - bounds.top) * aspectRatio); - newHeight = (newRight - rect.left) / aspectRatio; - } - - // if bottom edge moves by aspect ratio check that it is within bounds - if (bottomMoves && rect.top + newHeight > bounds.bottom) { - newRight = - Math.min( - newRight, - Math.min(bounds.right, rect.left + (bounds.bottom - rect.top) * aspectRatio)); - } - } - } - - rect.right = newRight; - } - - /** - * Get the resulting y-position of the top edge of the crop window given the handle's position and - * the image's bounding box and snap radius. - * - * @param top the x-position that the top edge is dragged to - * @param bounds the bounding box of the image that is being cropped - * @param snapMargin the snap distance to the image edge (in pixels) - */ - private void adjustTop( - RectF rect, - float top, - RectF bounds, - float snapMargin, - float aspectRatio, - boolean leftMoves, - boolean rightMoves) { - - float newTop = top; - - if (newTop < 0) { - newTop /= 1.05f; - mTouchOffset.y -= newTop / 1.1f; - } - - if (newTop < bounds.top) { - mTouchOffset.y -= (newTop - bounds.top) / 2f; - } - - if (newTop - bounds.top < snapMargin) { - newTop = bounds.top; - } - - // Checks if the window is too small vertically - if (rect.bottom - newTop < mMinCropHeight) { - newTop = rect.bottom - mMinCropHeight; - } - - // Checks if the window is too large vertically - if (rect.bottom - newTop > mMaxCropHeight) { - newTop = rect.bottom - mMaxCropHeight; - } - - if (newTop - bounds.top < snapMargin) { - newTop = bounds.top; - } - - // check horizontal bounds if aspect ratio is in play - if (aspectRatio > 0) { - float newWidth = (rect.bottom - newTop) * aspectRatio; - - // Checks if the crop window is too small horizontally due to aspect ratio adjustment - if (newWidth < mMinCropWidth) { - newTop = Math.max(bounds.top, rect.bottom - (mMinCropWidth / aspectRatio)); - newWidth = (rect.bottom - newTop) * aspectRatio; - } - - // Checks if the crop window is too large horizontally due to aspect ratio adjustment - if (newWidth > mMaxCropWidth) { - newTop = Math.max(bounds.top, rect.bottom - (mMaxCropWidth / aspectRatio)); - newWidth = (rect.bottom - newTop) * aspectRatio; - } - - // if left AND right edge moves by aspect ratio check that it is within full width bounds - if (leftMoves && rightMoves) { - newTop = Math.max(newTop, Math.max(bounds.top, rect.bottom - bounds.width() / aspectRatio)); - } else { - // if left edge moves by aspect ratio check that it is within bounds - if (leftMoves && rect.right - newWidth < bounds.left) { - newTop = Math.max(bounds.top, rect.bottom - (rect.right - bounds.left) / aspectRatio); - newWidth = (rect.bottom - newTop) * aspectRatio; - } - - // if right edge moves by aspect ratio check that it is within bounds - if (rightMoves && rect.left + newWidth > bounds.right) { - newTop = - Math.max( - newTop, - Math.max(bounds.top, rect.bottom - (bounds.right - rect.left) / aspectRatio)); - } - } - } - - rect.top = newTop; - } - - /** - * Get the resulting y-position of the bottom edge of the crop window given the handle's position - * and the image's bounding box and snap radius. - * - * @param bottom the position that the bottom edge is dragged to - * @param bounds the bounding box of the image that is being cropped - * @param viewHeight - * @param snapMargin the snap distance to the image edge (in pixels) - */ - private void adjustBottom( - RectF rect, - float bottom, - RectF bounds, - int viewHeight, - float snapMargin, - float aspectRatio, - boolean leftMoves, - boolean rightMoves) { - - float newBottom = bottom; - - if (newBottom > viewHeight) { - newBottom = viewHeight + (newBottom - viewHeight) / 1.05f; - mTouchOffset.y -= (newBottom - viewHeight) / 1.1f; - } - - if (newBottom > bounds.bottom) { - mTouchOffset.y -= (newBottom - bounds.bottom) / 2f; - } - - if (bounds.bottom - newBottom < snapMargin) { - newBottom = bounds.bottom; - } - - // Checks if the window is too small vertically - if (newBottom - rect.top < mMinCropHeight) { - newBottom = rect.top + mMinCropHeight; - } - - // Checks if the window is too small vertically - if (newBottom - rect.top > mMaxCropHeight) { - newBottom = rect.top + mMaxCropHeight; - } - - if (bounds.bottom - newBottom < snapMargin) { - newBottom = bounds.bottom; - } - - // check horizontal bounds if aspect ratio is in play - if (aspectRatio > 0) { - float newWidth = (newBottom - rect.top) * aspectRatio; - - // Checks if the window is too small horizontally - if (newWidth < mMinCropWidth) { - newBottom = Math.min(bounds.bottom, rect.top + mMinCropWidth / aspectRatio); - newWidth = (newBottom - rect.top) * aspectRatio; - } - - // Checks if the window is too large horizontally - if (newWidth > mMaxCropWidth) { - newBottom = Math.min(bounds.bottom, rect.top + mMaxCropWidth / aspectRatio); - newWidth = (newBottom - rect.top) * aspectRatio; - } - - // if left AND right edge moves by aspect ratio check that it is within full width bounds - if (leftMoves && rightMoves) { - newBottom = - Math.min(newBottom, Math.min(bounds.bottom, rect.top + bounds.width() / aspectRatio)); - } else { - // if left edge moves by aspect ratio check that it is within bounds - if (leftMoves && rect.right - newWidth < bounds.left) { - newBottom = Math.min(bounds.bottom, rect.top + (rect.right - bounds.left) / aspectRatio); - newWidth = (newBottom - rect.top) * aspectRatio; - } - - // if right edge moves by aspect ratio check that it is within bounds - if (rightMoves && rect.left + newWidth > bounds.right) { - newBottom = - Math.min( - newBottom, - Math.min(bounds.bottom, rect.top + (bounds.right - rect.left) / aspectRatio)); - } - } - } - - rect.bottom = newBottom; - } - - /** - * Adjust left edge by current crop window height and the given aspect ratio, the right edge - * remains in possition while the left adjusts to keep aspect ratio to the height. - */ - private void adjustLeftByAspectRatio(RectF rect, float aspectRatio) { - rect.left = rect.right - rect.height() * aspectRatio; - } - - /** - * Adjust top edge by current crop window width and the given aspect ratio, the bottom edge - * remains in possition while the top adjusts to keep aspect ratio to the width. - */ - private void adjustTopByAspectRatio(RectF rect, float aspectRatio) { - rect.top = rect.bottom - rect.width() / aspectRatio; - } - - /** - * Adjust right edge by current crop window height and the given aspect ratio, the left edge - * remains in possition while the left adjusts to keep aspect ratio to the height. - */ - private void adjustRightByAspectRatio(RectF rect, float aspectRatio) { - rect.right = rect.left + rect.height() * aspectRatio; - } - - /** - * Adjust bottom edge by current crop window width and the given aspect ratio, the top edge - * remains in possition while the top adjusts to keep aspect ratio to the width. - */ - private void adjustBottomByAspectRatio(RectF rect, float aspectRatio) { - rect.bottom = rect.top + rect.width() / aspectRatio; - } - - /** - * Adjust left and right edges by current crop window height and the given aspect ratio, both - * right and left edges adjusts equally relative to center to keep aspect ratio to the height. - */ - private void adjustLeftRightByAspectRatio(RectF rect, RectF bounds, float aspectRatio) { - rect.inset((rect.width() - rect.height() * aspectRatio) / 2, 0); - if (rect.left < bounds.left) { - rect.offset(bounds.left - rect.left, 0); - } - if (rect.right > bounds.right) { - rect.offset(bounds.right - rect.right, 0); - } - } - - /** - * Adjust top and bottom edges by current crop window width and the given aspect ratio, both top - * and bottom edges adjusts equally relative to center to keep aspect ratio to the width. - */ - private void adjustTopBottomByAspectRatio(RectF rect, RectF bounds, float aspectRatio) { - rect.inset(0, (rect.height() - rect.width() / aspectRatio) / 2); - if (rect.top < bounds.top) { - rect.offset(0, bounds.top - rect.top); - } - if (rect.bottom > bounds.bottom) { - rect.offset(0, bounds.bottom - rect.bottom); - } - } - // endregion - - // region: Inner class: Type - - /** - * The type of crop window move that is handled. - */ - public enum Type { - TOP_LEFT, - TOP_RIGHT, - BOTTOM_LEFT, - BOTTOM_RIGHT, - LEFT, - TOP, - RIGHT, - BOTTOM, - CENTER - } - // endregion -} diff --git a/cropper/src/main/res/drawable-hdpi/crop_image_menu_flip.png b/cropper/src/main/res/drawable-hdpi/crop_image_menu_flip.png deleted file mode 100644 index 133395df..00000000 Binary files a/cropper/src/main/res/drawable-hdpi/crop_image_menu_flip.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-hdpi/crop_image_menu_rotate_left.png b/cropper/src/main/res/drawable-hdpi/crop_image_menu_rotate_left.png deleted file mode 100644 index e4e26f8c..00000000 Binary files a/cropper/src/main/res/drawable-hdpi/crop_image_menu_rotate_left.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-hdpi/crop_image_menu_rotate_right.png b/cropper/src/main/res/drawable-hdpi/crop_image_menu_rotate_right.png deleted file mode 100644 index 2311d1a0..00000000 Binary files a/cropper/src/main/res/drawable-hdpi/crop_image_menu_rotate_right.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-xhdpi/crop_image_menu_flip.png b/cropper/src/main/res/drawable-xhdpi/crop_image_menu_flip.png deleted file mode 100644 index 79910ffe..00000000 Binary files a/cropper/src/main/res/drawable-xhdpi/crop_image_menu_flip.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-xhdpi/crop_image_menu_rotate_left.png b/cropper/src/main/res/drawable-xhdpi/crop_image_menu_rotate_left.png deleted file mode 100644 index bdfcbca8..00000000 Binary files a/cropper/src/main/res/drawable-xhdpi/crop_image_menu_rotate_left.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-xhdpi/crop_image_menu_rotate_right.png b/cropper/src/main/res/drawable-xhdpi/crop_image_menu_rotate_right.png deleted file mode 100644 index 6d730125..00000000 Binary files a/cropper/src/main/res/drawable-xhdpi/crop_image_menu_rotate_right.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-xxhdpi/crop_image_menu_flip.png b/cropper/src/main/res/drawable-xxhdpi/crop_image_menu_flip.png deleted file mode 100644 index 3629e38d..00000000 Binary files a/cropper/src/main/res/drawable-xxhdpi/crop_image_menu_flip.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-xxhdpi/crop_image_menu_rotate_left.png b/cropper/src/main/res/drawable-xxhdpi/crop_image_menu_rotate_left.png deleted file mode 100644 index 5ae4f53e..00000000 Binary files a/cropper/src/main/res/drawable-xxhdpi/crop_image_menu_rotate_left.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-xxhdpi/crop_image_menu_rotate_right.png b/cropper/src/main/res/drawable-xxhdpi/crop_image_menu_rotate_right.png deleted file mode 100644 index 796114cc..00000000 Binary files a/cropper/src/main/res/drawable-xxhdpi/crop_image_menu_rotate_right.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-xxxhdpi/crop_image_menu_flip.png b/cropper/src/main/res/drawable-xxxhdpi/crop_image_menu_flip.png deleted file mode 100644 index 4200cb86..00000000 Binary files a/cropper/src/main/res/drawable-xxxhdpi/crop_image_menu_flip.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-xxxhdpi/crop_image_menu_rotate_left.png b/cropper/src/main/res/drawable-xxxhdpi/crop_image_menu_rotate_left.png deleted file mode 100644 index 1eb68612..00000000 Binary files a/cropper/src/main/res/drawable-xxxhdpi/crop_image_menu_rotate_left.png and /dev/null differ diff --git a/cropper/src/main/res/drawable-xxxhdpi/crop_image_menu_rotate_right.png b/cropper/src/main/res/drawable-xxxhdpi/crop_image_menu_rotate_right.png deleted file mode 100644 index 33ce6709..00000000 Binary files a/cropper/src/main/res/drawable-xxxhdpi/crop_image_menu_rotate_right.png and /dev/null differ diff --git a/cropper/src/main/res/layout/crop_image_activity.xml b/cropper/src/main/res/layout/crop_image_activity.xml deleted file mode 100644 index 82e84fcf..00000000 --- a/cropper/src/main/res/layout/crop_image_activity.xml +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/cropper/src/main/res/layout/crop_image_view.xml b/cropper/src/main/res/layout/crop_image_view.xml deleted file mode 100644 index 50f897b5..00000000 --- a/cropper/src/main/res/layout/crop_image_view.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/cropper/src/main/res/menu/crop_image_menu.xml b/cropper/src/main/res/menu/crop_image_menu.xml deleted file mode 100644 index ff42bc69..00000000 --- a/cropper/src/main/res/menu/crop_image_menu.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/cropper/src/main/res/values-ar/strings.xml b/cropper/src/main/res/values-ar/strings.xml deleted file mode 100644 index 4b570989..00000000 --- a/cropper/src/main/res/values-ar/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - أدر عكس اتجاه عقارب الساعة - أدر - قُصّ - اقلب - اقلب أفقيًا - اقلب رأسيًا - - اختر مصدرًا - - إلغاء؛ الأذونات المطلوبة غير ممنوحة - - diff --git a/cropper/src/main/res/values-cs/strings.xml b/cropper/src/main/res/values-cs/strings.xml deleted file mode 100644 index a8cef3c9..00000000 --- a/cropper/src/main/res/values-cs/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Otočit proti směru hodinových ručiček - Otočit - Oříznout - Překlopit - Překlopit vodorovně - Překlopit svisle - - Vybrat zdroj - - Probíhá storno, požadovaná povolení nejsou udělena - - diff --git a/cropper/src/main/res/values-de/strings.xml b/cropper/src/main/res/values-de/strings.xml deleted file mode 100644 index 1ef0f3d7..00000000 --- a/cropper/src/main/res/values-de/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - gegen den Uhrzeigersinn drehen - drehen - zuschneiden - spiegeln - horizontal spiegeln - vertikal spiegeln - - Quelle wählen - - Vorgang wird abgebrochen, benötigte Berechtigungen wurden nicht erteilt. - - diff --git a/cropper/src/main/res/values-es-rGT/strings.xml b/cropper/src/main/res/values-es-rGT/strings.xml deleted file mode 100644 index c9b0864f..00000000 --- a/cropper/src/main/res/values-es-rGT/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - Girar a la izquierda - Girar a la derecha - Cortar - Dar la vuelta - Voltear horizontalmente - Voltear verticalmente - Seleccionar fuente - Cancelando, los permisos requeridos no se otorgaron - \ No newline at end of file diff --git a/cropper/src/main/res/values-es/strings.xml b/cropper/src/main/res/values-es/strings.xml deleted file mode 100644 index a14c240a..00000000 --- a/cropper/src/main/res/values-es/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - Rotar a la izquierda - Rotar a la derecha - Cortar - Dar la vuelta - Voltear horizontalmente - Voltear verticalmente - Seleccionar fuente - Cancelando, los permisos requeridos no han sido otorgados - \ No newline at end of file diff --git a/cropper/src/main/res/values-fa/strings.xml b/cropper/src/main/res/values-fa/strings.xml deleted file mode 100644 index b6745743..00000000 --- a/cropper/src/main/res/values-fa/strings.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - چرخش در جهت عقربه های ساعت - چرخش - بریدن (کراپ) - آیینه کردن - آیینه کردن به صورت افقی - آیینه کردن به صورت عمودی - منبع را انتخاب کنید - لغو، مجوزهای مورد نیاز ارائه نشده - \ No newline at end of file diff --git a/cropper/src/main/res/values-fr/strings.xml b/cropper/src/main/res/values-fr/strings.xml deleted file mode 100644 index b0ec3bd0..00000000 --- a/cropper/src/main/res/values-fr/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - Pivoter à gauche - Pivoter à droite - Redimensionner - Retourner - Retourner horizontalement - Retourner verticalement - Sélectionner la source - Annulation, il manque des permissions requises - diff --git a/cropper/src/main/res/values-he/strings.xml b/cropper/src/main/res/values-he/strings.xml deleted file mode 100644 index 8a781d36..00000000 --- a/cropper/src/main/res/values-he/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - סובב נגד כיוון השעון - סובב - חתוך - הפוך - הפוך אופקית - הפוך אנכית - - בחר מקור - - ההרשאות הנדרשות חסרות, מבטל - - diff --git a/cropper/src/main/res/values-hi/strings.xml b/cropper/src/main/res/values-hi/strings.xml deleted file mode 100644 index 8549a125..00000000 --- a/cropper/src/main/res/values-hi/strings.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - घड़ी की सुई के विपरीत दिशा में घुमाइए - घुमाएँ - फ़सल - फ्लिप - क्षैतिज फ्लिप - लंबवत फ्लिप करें - सोर्स चुनें - रद्द करना, आवश्यक अनुमतियां नहीं दी गई हैं - \ No newline at end of file diff --git a/cropper/src/main/res/values-id/strings.xml b/cropper/src/main/res/values-id/strings.xml deleted file mode 100644 index 5d0570ea..00000000 --- a/cropper/src/main/res/values-id/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - Putar berlawanan arah jarum jam - Putar - Potong - Balik - Balik secara horizontal - Balik secara vertikal - Pilih sumber - Membatalkan, tidak mendapatkan izin yang diperlukan - - \ No newline at end of file diff --git a/cropper/src/main/res/values-in/strings.xml b/cropper/src/main/res/values-in/strings.xml deleted file mode 100644 index 5d0570ea..00000000 --- a/cropper/src/main/res/values-in/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - Putar berlawanan arah jarum jam - Putar - Potong - Balik - Balik secara horizontal - Balik secara vertikal - Pilih sumber - Membatalkan, tidak mendapatkan izin yang diperlukan - - \ No newline at end of file diff --git a/cropper/src/main/res/values-it/strings.xml b/cropper/src/main/res/values-it/strings.xml deleted file mode 100644 index fa266660..00000000 --- a/cropper/src/main/res/values-it/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Ruota in senso antiorario - Ruota - Ritaglia - Capovolgi - Capovolgi orizzontalmente - Capovolgi verticalmente - - Seleziona origine - - Annullamento in corso, autorizzazione richieste non concesse - - diff --git a/cropper/src/main/res/values-ja/strings.xml b/cropper/src/main/res/values-ja/strings.xml deleted file mode 100644 index 4ab0ca56..00000000 --- a/cropper/src/main/res/values-ja/strings.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - 左回転 - 右回転 - 切り取り - 反転 - 左右反転 - 上下反転 - 画像を選択 - 必要な権限がありません、キャンセルしています。 - diff --git a/cropper/src/main/res/values-ko/strings.xml b/cropper/src/main/res/values-ko/strings.xml deleted file mode 100644 index a33967bd..00000000 --- a/cropper/src/main/res/values-ko/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - 반시계 회전 - 회전 - 자르기 - 반전 - 좌우반전 - 상하반전 - - 이미지 선택 - - 필수 권한이 없어서 취소합니다. - - diff --git a/cropper/src/main/res/values-ms/strings.xml b/cropper/src/main/res/values-ms/strings.xml deleted file mode 100644 index 000ac2eb..00000000 --- a/cropper/src/main/res/values-ms/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - Putar arah berlawanan jam - Putar - Potong - Flip - Flip melintang - Flip menegak - Pilih sumber - Membatal, tidak mendapat kebenaran yang diperlukan - - \ No newline at end of file diff --git a/cropper/src/main/res/values-nb/strings.xml b/cropper/src/main/res/values-nb/strings.xml deleted file mode 100644 index c177d252..00000000 --- a/cropper/src/main/res/values-nb/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Roter teller med urviseren - Roter - Beskjær - Vend - Vend vannrett - Vend loddrett - - Velg kilde - - Avbryter, nødvendige tillatelser er ikke gitt - - diff --git a/cropper/src/main/res/values-nl/strings.xml b/cropper/src/main/res/values-nl/strings.xml deleted file mode 100644 index 6b25e03b..00000000 --- a/cropper/src/main/res/values-nl/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Tegen de klok in draaien - Draaien - Bijsnijden - Spiegelen - Horizontaal spiegelen - Verticaal spiegelen - - Bron selecteren - - Wordt geannuleerd, vereiste machtigingen zijn niet toegekend - - diff --git a/cropper/src/main/res/values-pl/strings.xml b/cropper/src/main/res/values-pl/strings.xml deleted file mode 100644 index 9db22a14..00000000 --- a/cropper/src/main/res/values-pl/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Obróć w lewo - Obróć - Przytnij - Odbij - Odbij poziomo - Odbij pionowo - - Wybierz źródło - - Przerywaniem, potrzebne uprawnienia nie zostały nadane - - diff --git a/cropper/src/main/res/values-pt-rBR/strings.xml b/cropper/src/main/res/values-pt-rBR/strings.xml deleted file mode 100644 index e60b8bfb..00000000 --- a/cropper/src/main/res/values-pt-rBR/strings.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - Girar para a esquerda - Girar para a direita - Cortar - Espelhar - Espelhar na horizontal - Espelhar na vertifcal - - Escolher foto a partir de - - diff --git a/cropper/src/main/res/values-ru-rRU/strings.xml b/cropper/src/main/res/values-ru-rRU/strings.xml deleted file mode 100644 index cd8e62d9..00000000 --- a/cropper/src/main/res/values-ru-rRU/strings.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - Повернуть налево - Повернуть направо - Обрезать - Отразить - Отразить по горизонтали - Отразить по вертикали - Выбрать источник - \ No newline at end of file diff --git a/cropper/src/main/res/values-sv/strings.xml b/cropper/src/main/res/values-sv/strings.xml deleted file mode 100644 index ce8beb96..00000000 --- a/cropper/src/main/res/values-sv/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Rotera vänster - Rotera höger - Beskär - Vänd - Vänd horisontellt - Vänd vertikalt - - Välj bild - - Avbryter, nödvändiga behörigheter beviljas inte - - diff --git a/cropper/src/main/res/values-tr/strings.xml b/cropper/src/main/res/values-tr/strings.xml deleted file mode 100644 index ba0f6f4e..00000000 --- a/cropper/src/main/res/values-tr/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - Saat yönünde döndür - döndürmek - ekin - fiske - Yatay olarak çevir - Dikey olarak çevir - Kaynağı seçin - İptal ediliyor, gerekli izinler verilmiyor - - \ No newline at end of file diff --git a/cropper/src/main/res/values-ur/strings.xml b/cropper/src/main/res/values-ur/strings.xml deleted file mode 100644 index b62a923f..00000000 --- a/cropper/src/main/res/values-ur/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - گھڑی وار گھڑی گھومیں - گھمائیں - فصل - پلٹائیں - افقی پلٹائیں - عمودی طور پر پلٹائیں - ذریعہ منتخب کریں - منسوخ کرنا، ضروری اجازت نہیں دی جاتی ہیں - - \ No newline at end of file diff --git a/cropper/src/main/res/values-vi/strings.xml b/cropper/src/main/res/values-vi/strings.xml deleted file mode 100644 index d6301f41..00000000 --- a/cropper/src/main/res/values-vi/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Xoay theo chiều kim đồng hồ - Xoay - Cắt - Lật - Lật theo chiều ngang - Lật theo chiều dọc - - Chọn nguồn - - Đang hủy, các quyền đã yêu cầu không được cấp - - diff --git a/cropper/src/main/res/values-zh-rCN/strings.xml b/cropper/src/main/res/values-zh-rCN/strings.xml deleted file mode 100644 index 7ceb799a..00000000 --- a/cropper/src/main/res/values-zh-rCN/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - 逆时针旋转 - 旋转 - 裁切 - 翻转 - 水平翻转 - 垂直翻转 - - 选择来源 - - 取消中,未授予所需权限 - - \ No newline at end of file diff --git a/cropper/src/main/res/values-zh-rTW/strings.xml b/cropper/src/main/res/values-zh-rTW/strings.xml deleted file mode 100644 index 269b9653..00000000 --- a/cropper/src/main/res/values-zh-rTW/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - 逆時針旋轉 - 旋轉 - 裁切 - 翻轉 - 水平翻轉 - 垂直翻轉 - - 選擇來源 - - 取消中,未授予所需權限 - - \ No newline at end of file diff --git a/cropper/src/main/res/values-zh/strings.xml b/cropper/src/main/res/values-zh/strings.xml deleted file mode 100644 index b197f48f..00000000 --- a/cropper/src/main/res/values-zh/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - 逆时针旋转 - 旋转 - 裁剪 - 翻转 - 水平翻转 - 垂直翻转 - - 选择来源 - - 正在取消,该操作未获得所需权限。 - - diff --git a/cropper/src/main/res/values/attrs.xml b/cropper/src/main/res/values/attrs.xml deleted file mode 100644 index 756a2c1b..00000000 --- a/cropper/src/main/res/values/attrs.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/cropper/src/main/res/values/strings.xml b/cropper/src/main/res/values/strings.xml deleted file mode 100644 index 6dc1fd22..00000000 --- a/cropper/src/main/res/values/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Rotate counter clockwise - Rotate - Crop - Flip - Flip horizontally - Flip vertically - - Select source - - Cancelling, required permissions are not granted - - diff --git a/settings.gradle b/settings.gradle index 48eb5e95..eea69bc0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,4 +3,3 @@ include ':app' include ':autoimageslider' include ':mytransl' include ':ratethisapp' -include ':cropper' diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/451.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/451.txt new file mode 100644 index 00000000..649057a9 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/451.txt @@ -0,0 +1,12 @@ +Added: +- Post random quotes +- Group reblogs in home timeline + +Changed: +- Display translate button only when language is different +- Respect blank spaces between words in messages +- Focus button more accessible when editing media + +Fixed: +- Behavior with cw toggle +- Truncated gimini links \ No newline at end of file diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/452.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/452.txt new file mode 100644 index 00000000..2c8f6b77 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/452.txt @@ -0,0 +1,16 @@ +Added: +- Rename Nitter timelines +- Android 13 support + +Changed: +- Visual feedback for block on account list +- Visual changes with compose / top bar + +Fixed: +- Nav buttons not visible with media (Light theme) +- Status bar with Android 5 +- Fix links not clickable +- Fix deep links +- Fix remote threads not fetched for some instances +- Adding description to shared media +- Fix crashes \ No newline at end of file diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/453.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/453.txt new file mode 100644 index 00000000..f5b61051 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/453.txt @@ -0,0 +1,8 @@ +Added: +- Pagination with search / trending + +Fixed: +- Long press on Nitter tabs +- Open with another accounts +- Chars size not respected for Android 5-6 +- Wrong instance fetched for instances.social \ No newline at end of file diff --git a/src/fdroid/fastlane/metadata/android/en/changelogs/454.txt b/src/fdroid/fastlane/metadata/android/en/changelogs/454.txt new file mode 100644 index 00000000..612aac3b --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/en/changelogs/454.txt @@ -0,0 +1,33 @@ +Added: +- Post random quotes +- Group reblogs in home timeline +- Rename Nitter timelines +- Android 13 support +- Pagination with search / trending +- Allow to remove left margin in messages (default: disabled) + +Changed: +- Display translate button only when language is different +- Respect blank spaces between words in messages +- Focus button more accessible when editing media +- Visual feedback for block on account list +- Visual changes with compose / top bar +- Use custom Nitter timeline name in manage timelines + +Fixed: +- Behavior with cw toggle +- Truncated gimini links +- Nav buttons not visible with media (Light theme) +- Status bar with Android 5 +- Fix links not clickable +- Fix deep links +- Fix remote threads not fetched for some instances +- Adding description to shared media +- Open with another accounts +- Chars size not respected for Android 5-6 +- Wrong instance fetched for instances.social +- Bouncing Timeline on refresh +- Links to mentions, tags, urls, not visible. +- Custom channel sounds not applied +- users with short username are not linked +- Fix crashes \ No newline at end of file diff --git a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/1.png b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/1.png index 1da10090..4be53baa 100644 Binary files a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/1.png and b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/1.png differ diff --git a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/2.png b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/2.png index 809b813d..afcefe32 100644 Binary files a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/2.png and b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/2.png differ diff --git a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/3.png b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/3.png index c04aae18..625654ab 100644 Binary files a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/3.png and b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/3.png differ diff --git a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/4.png b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/4.png index 8faad90b..0620833c 100644 Binary files a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/4.png and b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/4.png differ diff --git a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/5.png b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/5.png index 675cf275..1c8d6299 100644 Binary files a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/5.png and b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/5.png differ diff --git a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/6.png b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/6.png index 711aa73e..5700e2e3 100644 Binary files a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/6.png and b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/6.png differ diff --git a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/7.png b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/7.png index b9617623..c832c524 100644 Binary files a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/7.png and b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/7.png differ diff --git a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/8.png b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/8.png index 0938dd77..bd81c393 100644 Binary files a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/8.png and b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/8.png differ diff --git a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/9.png b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/9.png index 319e39a4..a4aa2739 100644 Binary files a/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/9.png and b/src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/9.png differ diff --git a/src/fdroid/fastlane/metadata/android/eo/title.txt b/src/fdroid/fastlane/metadata/android/eo/title.txt new file mode 100644 index 00000000..e6f369e8 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/eo/title.txt @@ -0,0 +1 @@ +Fedilab diff --git a/src/fdroid/fastlane/metadata/android/fr/changelogs/446.txt b/src/fdroid/fastlane/metadata/android/fr/changelogs/446.txt new file mode 100644 index 00000000..7738f6bf --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/fr/changelogs/446.txt @@ -0,0 +1,18 @@ +Ajouté : +- Afficher tout les messages des fils d'instances distantes (si possible) +- Possibilité de ne plus suivre/silencer/épingler un tag de la timeline des tags +- Affiche les comptes les plus utilisés dans l'en-tête du menu pour un changement rapide +- Ajoute automatiquement le tag lorsque l'on poste depuis la timeline des tags +- Ajoute un bouton traduire en bas des messages (désactivé par défaut) +- Ajoute des rôles de comptes dans les profils +- Traduction du morse + +Modifié : +- Désactive les animations après une actualisation + +Réparé : +- Le contact ne marche pas lors de la rédaction d'un post +- Barre de statut pour le thème noir +- Message copié dans les conversations lorsqu'il est édité +- Problèmes de couleurs avec Android 5 +- Plusieurs crashes diff --git a/src/fdroid/fastlane/metadata/android/fr/changelogs/447.txt b/src/fdroid/fastlane/metadata/android/fr/changelogs/447.txt new file mode 100644 index 00000000..41473dc8 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/fr/changelogs/447.txt @@ -0,0 +1,4 @@ +Ajouté : +- Silencer/désilencer les comptes dans la timeline accueil depuis leurs messages ou leurs profils +- Ajouter tout les utilisateurs d'une liste à "Silencer sur l'accueil" en un clic +- Afficher/gérer les utilisateurs silencés sur l'accueil diff --git a/src/fdroid/fastlane/metadata/android/fr/changelogs/448.txt b/src/fdroid/fastlane/metadata/android/fr/changelogs/448.txt new file mode 100644 index 00000000..fd5cf639 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/fr/changelogs/448.txt @@ -0,0 +1,7 @@ +Ajouté : +- Silencer/désilencer les comptes dans la timeline accueil depuis leurs messages ou leurs profils +- Ajouter tout les utilisateurs d'une liste à "Silencer sur l'accueil" en un clic +- Afficher/gérer les utilisateurs silencés sur l'accueil + +Réparé : +- Crashs de la timeline diff --git a/src/fdroid/fastlane/metadata/android/fr/changelogs/449.txt b/src/fdroid/fastlane/metadata/android/fr/changelogs/449.txt new file mode 100644 index 00000000..7f3a7882 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/fr/changelogs/449.txt @@ -0,0 +1,9 @@ +Ajouté : +- Ajoute plus de langues cibles dans picker pour les traductions +- Ajoute le nom du compte dans les notifications push + +Réparé : +- Répare le crash lors du changement de langue +- Répare les contre couleurs +- Répare la couleur de lien par défaut +- Répare le crash lorsque l'on clique sur les mentions diff --git a/src/fdroid/fastlane/metadata/android/fr/changelogs/450.txt b/src/fdroid/fastlane/metadata/android/fr/changelogs/450.txt new file mode 100644 index 00000000..c497861d --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/fr/changelogs/450.txt @@ -0,0 +1,12 @@ +Ajouté : +- Fonctionnalité d'importation/exportation des données complète +- Support des icônes du thème Android 13 + +Réparé : +- Répare une régression avec les filtres +- Répare le thème solarisé sombre +- Répare le lien de prévisualisation pour les CW +- Répare la couleur de la barre de statut pour tout les thèmes +- Réparer la langue dans la rédaction "..." +- Répare ajouter tout les comptes silencés dans l'accueil à partir de listes +- Répare les badges des top notofications diff --git a/src/fdroid/fastlane/metadata/android/fr/changelogs/451.txt b/src/fdroid/fastlane/metadata/android/fr/changelogs/451.txt new file mode 100644 index 00000000..e2edaeec --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/fr/changelogs/451.txt @@ -0,0 +1,12 @@ +Ajouté : +- Poster des citations aléatoires +- Re-blog de groupe dans la timeline d'accueil + +Modifié : +- Affiche le bouton traduire seulement lorsque la langue est différente +- Respecte les espaces blancs entre les mots dans les messages +- Le bouton focus est plus accessible lorsque l'on édite un média + +Réparé : +- Comportement avec le bouton cw +- Lien gemini tronqués diff --git a/src/fdroid/fastlane/metadata/android/fr/changelogs/452.txt b/src/fdroid/fastlane/metadata/android/fr/changelogs/452.txt new file mode 100644 index 00000000..62b4d307 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/fr/changelogs/452.txt @@ -0,0 +1,16 @@ +Ajouté : +- Renommer les timeline Nitter +- Support d'Android 13 + +Modifié : +- Feedback visuel pour bloquer sur la liste de comptes +- Changements visuels avec la barre écrire/favori + +Réparé : +- Bouton nav non visible avec les média (thème clair) +- Barre de statut avec Android 5 +- Répare les liens non cliquables +- Répare les liens profonds +- Répare les fils distants non importés depuis certaines instances +- Ajoute les descriptions aux médias partagés +- Répare des crashs diff --git a/src/fdroid/fastlane/metadata/android/fr/changelogs/453.txt b/src/fdroid/fastlane/metadata/android/fr/changelogs/453.txt new file mode 100644 index 00000000..d7728801 --- /dev/null +++ b/src/fdroid/fastlane/metadata/android/fr/changelogs/453.txt @@ -0,0 +1,8 @@ +Ajoute : +- La pagination avec recherche / tendance + +Réparé : +- Appuyer longtemps sur les onglets Nitter +- Ouvrir avec d'autres comptes +- Taille de caractères non respectée pour Android 5-6 +- Mauvaise instance importée depuis instances.social